From a24e6616c2f701896328c7cba5e6e8e76b42de1e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 19 Oct 2022 23:01:42 +0800 Subject: [PATCH 0001/1179] Cabana: fix time column was being cutoff (#26156) fix time column --- tools/cabana/historylog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index c0efbca280..a20845f15f 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -70,7 +70,7 @@ HistoryLog::HistoryLog(QWidget *parent) : QWidget(parent) { table = new QTableView(this); table->setModel(model); table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); + table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); table->setColumnWidth(0, 60); table->verticalHeader()->setVisible(false); table->setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); From a927d7b0ea25d1fde6a121888f8abd34e2fef867 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 19 Oct 2022 23:02:47 +0800 Subject: [PATCH 0002/1179] Cabana: warn when DBC message length is wrong (#26154) display warning if message size is incorrect --- tools/cabana/detailwidget.cc | 16 ++++++++++++++++ tools/cabana/detailwidget.h | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 60d0632d4c..a92969d4d3 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -29,6 +29,17 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { title_layout->addWidget(edit_btn); main_layout->addLayout(title_layout); + // warning + warning_widget = new QWidget(this); + QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); + QLabel *warning_icon = new QLabel(this); + warning_icon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap({16, 16})); + warning_hlayout->addWidget(warning_icon); + warning_label = new QLabel(this); + warning_hlayout->addWidget(warning_label,1, Qt::AlignLeft); + warning_widget->hide(); + main_layout->addWidget(warning_widget); + // binary view binary_view = new BinaryView(this); main_layout->addWidget(binary_view, 0, Qt::AlignTop); @@ -64,6 +75,7 @@ void DetailWidget::setMessage(const QString &message_id) { void DetailWidget::dbcMsgChanged() { if (msg_id.isEmpty()) return; + warning_widget->hide(); qDeleteAll(signals_container->findChildren()); QString msg_name = tr("untitled"); if (auto msg = dbc()->msg(msg_id)) { @@ -76,6 +88,10 @@ void DetailWidget::dbcMsgChanged() { QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); } msg_name = msg->name.c_str(); + if (msg->size != can->lastMessage(msg_id).dat.size()) { + warning_label->setText(tr("Message size (%1) is incorrect!").arg(msg->size)); + warning_widget->show(); + } } edit_btn->setVisible(true); name_label->setText(msg_name); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 9d3b81dcb0..07c78caa4a 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -46,7 +46,8 @@ private: void updateState(); QString msg_id; - QLabel *name_label, *time_label; + QLabel *name_label, *time_label, *warning_label; + QWidget *warning_widget; QPushButton *edit_btn; QWidget *signals_container; HistoryLog *history_log; From 3fae3b366087c20621624de8b4f3e00da4de987b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 19 Oct 2022 23:03:14 +0800 Subject: [PATCH 0003/1179] cabana: use monospaced font for hex in BinaryView (#26153) use fixedfont --- tools/cabana/binaryview.cc | 6 ++++-- tools/cabana/binaryview.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 71175e783e..4fc55077da 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -1,6 +1,7 @@ #include "tools/cabana/binaryview.h" #include +#include #include #include @@ -157,7 +158,8 @@ void BinarySelectionModel::select(const QItemSelection &selection, QItemSelectio BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { // cache fonts and color small_font.setPointSize(6); - bold_font.setBold(true); + hex_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + hex_font.setBold(true); highlight_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight); } @@ -172,7 +174,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // 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->setFont(hex_font); } painter->drawText(option.rect, Qt::AlignCenter, item->val); if (item->is_msb || item->is_lsb) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 631797ca48..38f0ddf216 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -14,7 +14,7 @@ public: QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: - QFont small_font, bold_font; + QFont small_font, hex_font; QColor highlight_color; }; From 1211ffbcf22800049682244727984a596395c217 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 19 Oct 2022 23:03:34 +0800 Subject: [PATCH 0004/1179] cabana: display a clear button in filter string edit box (#26152) display clear button --- tools/cabana/messageswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 28f79adad3..f39ce97684 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -42,6 +42,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // message filter QLineEdit *filter = new QLineEdit(this); + filter->setClearButtonEnabled(true); filter->setPlaceholderText(tr("filter messages")); main_layout->addWidget(filter); From d1495a90903ea3a29f2987af6de996dfbd9ab9ff Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 19 Oct 2022 23:07:01 +0800 Subject: [PATCH 0005/1179] Cabana: add dialog to find and locate signal values (#26131) * add dialog to find signals * dont close dlg after goto * limit number * cleanup * merge master --- tools/cabana/canmessages.cc | 29 ++++++++++++++ tools/cabana/canmessages.h | 4 ++ tools/cabana/signaledit.cc | 79 ++++++++++++++++++++++++++++++++++++- tools/cabana/signaledit.h | 7 ++++ 4 files changed, 118 insertions(+), 1 deletion(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 252a8c680c..897381b3f2 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -3,6 +3,8 @@ #include #include +#include "tools/cabana/dbcmanager.h" + Q_DECLARE_METATYPE(std::vector); Settings settings; @@ -38,6 +40,33 @@ bool CANMessages::loadRoute(const QString &route, const QString &data_dir, bool return false; } +QList CANMessages::findSignalValues(const QString &id, const Signal *signal, double value, FindFlags flag, int max_count) { + auto evts = events(); + if (!evts) return {}; + + auto l = id.split(':'); + int bus = l[0].toInt(); + uint32_t address = l[1].toUInt(nullptr, 16); + + QList ret; + ret.reserve(max_count); + for (auto &evt : *evts) { + if (evt->which != cereal::Event::Which::CAN) continue; + + for (auto c : evt->event.getCan()) { + if (bus == c.getSrc() && address == c.getAddress()) { + double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), *signal); + if ((flag == EQ && val == value) || (flag == LT && val < value) || (flag == GT && val > value)) { + ret.push_back({(evt->mono_time / (double)1e9) - can->routeStartTime(), val}); + } + if (ret.size() >= max_count) + return ret; + } + } + } + return ret; +} + void CANMessages::process(QHash> *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { ++counters[it.key()]; diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 58f5ad70b7..44131ad5c9 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -5,7 +5,9 @@ #include #include +#include +#include "opendbc/can/common_dbc.h" #include "tools/replay/replay.h" class Settings : public QObject { @@ -35,12 +37,14 @@ class CANMessages : public QObject { Q_OBJECT public: + enum FindFlags{ EQ, LT, GT }; CANMessages(QObject *parent); ~CANMessages(); bool loadRoute(const QString &route, const QString &data_dir, bool use_qcam); void seekTo(double ts); void resetRange(); void setRange(double min, double max); + QList findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); bool eventFilter(const Event *event); inline std::pair range() const { return {begin_sec, end_sec}; } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 7cace48402..050802d452 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -3,8 +3,12 @@ #include #include #include +#include +#include #include +#include "selfdrive/ui/qt/util.h" + // SignalForm SignalForm::SignalForm(const Signal &sig, QWidget *parent) : start_bit(sig.start_bit), QWidget(parent) { @@ -93,6 +97,12 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWid title->setStyleSheet(QString("font-weight:bold; color:%1").arg(getColor(index))); title_layout->addWidget(title, 1); + QPushButton *seek_btn = new QPushButton("⌕"); + seek_btn->setStyleSheet("font-weight:bold;font-size:20px"); + seek_btn->setToolTip(tr("Find signal values")); + seek_btn->setFixedSize(20, 20); + title_layout->addWidget(seek_btn); + QPushButton *plot_btn = new QPushButton("📈"); plot_btn->setToolTip(tr("Show Plot")); plot_btn->setFixedSize(20, 20); @@ -124,13 +134,17 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWid main_layout->addWidget(hline); QObject::connect(remove_btn, &QPushButton::clicked, this, &SignalEdit::remove); + QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); 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); + QObject::connect(seek_btn, &QPushButton::clicked, [this, msg_id, s = &sig]() { + SignalFindDlg dlg(msg_id, s, this); + dlg.exec(); + }); } void SignalEdit::setFormVisible(bool visible) { @@ -159,3 +173,66 @@ AddSignalDialog::AddSignalDialog(const QString &id, int start_bit, int size, QWi connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); } + +SignalFindDlg::SignalFindDlg(const QString &id, const Signal *signal, QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Find signal values")); + QVBoxLayout *main_layout = new QVBoxLayout(this); + + QHBoxLayout *h = new QHBoxLayout(); + h->addWidget(new QLabel(signal->name.c_str())); + QComboBox *comp_box = new QComboBox(); + comp_box->addItems({">", "=", "<"}); + h->addWidget(comp_box); + QLineEdit *value_edit = new QLineEdit("0", this); + value_edit->setValidator( new QDoubleValidator(-500000, 500000, 6, this) ); + h->addWidget(value_edit, 1); + QPushButton *search_btn = new QPushButton(tr("Find"), this); + h->addWidget(search_btn); + main_layout->addLayout(h); + + QWidget *container = new QWidget(this); + QVBoxLayout *signals_layout = new QVBoxLayout(container); + QScrollArea *scroll = new QScrollArea(this); + scroll->setWidget(container); + scroll->setWidgetResizable(true); + scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + main_layout->addWidget(scroll); + + QObject::connect(search_btn, &QPushButton::clicked, [=]() { + clearLayout(signals_layout); + + CANMessages::FindFlags comp = CANMessages::EQ; + if (comp_box->currentIndex() == 0) { + comp = CANMessages::GT; + } else if (comp_box->currentIndex() == 2) { + comp = CANMessages::LT; + } + double value = value_edit->text().toDouble(); + + const int limit_results = 50; + auto values = can->findSignalValues(id, signal, value, comp, limit_results); + for (auto &v : values) { + QHBoxLayout *item_layout = new QHBoxLayout(); + item_layout->addWidget(new QLabel(QString::number(v.x(), 'f', 2))); + item_layout->addWidget(new QLabel(QString::number(v.y()))); + item_layout->addStretch(1); + + QPushButton *goto_btn = new QPushButton(tr("Goto"), this); + QObject::connect(goto_btn, &QPushButton::clicked, [sec = v.x()]() { can->seekTo(sec); }); + item_layout->addWidget(goto_btn); + signals_layout->addLayout(item_layout); + } + if (values.size() == limit_results) { + QFrame *hline = new QFrame(); + hline->setFrameShape(QFrame::HLine); + hline->setFrameShadow(QFrame::Sunken); + signals_layout->addWidget(hline); + QLabel *info = new QLabel(tr("Only display the first %1 results").arg(limit_results)); + info->setAlignment(Qt::AlignCenter); + signals_layout->addWidget(info); + } + if (values.size() * 30 > container->height()) { + scroll->setFixedHeight(std::min(values.size() * 30, 300)); + } + }); +} diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index f31408657f..f7611747ec 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -51,3 +51,10 @@ public: AddSignalDialog(const QString &id, int start_bit, int size, QWidget *parent); SignalForm *form; }; + +class SignalFindDlg : public QDialog { + Q_OBJECT + +public: + SignalFindDlg(const QString &id, const Signal *signal, QWidget *parent); +}; From bc2b247d7116e8c5962e6767732be61846dd6f47 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 20 Oct 2022 02:04:08 +0800 Subject: [PATCH 0006/1179] Cabana: highlight signal on mouse over (#26157) --- tools/cabana/binaryview.cc | 41 +++++++++++++++++++++++++++++++++--- tools/cabana/binaryview.h | 10 ++++++++- tools/cabana/canmessages.h | 7 ++++++ tools/cabana/detailwidget.cc | 2 ++ tools/cabana/signaledit.cc | 17 ++++++++++++++- tools/cabana/signaledit.h | 7 ++++++ 6 files changed, 79 insertions(+), 5 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 4fc55077da..168edc75f4 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include #include "tools/cabana/canmessages.h" @@ -19,6 +21,7 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { horizontalHeader()->hide(); verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setMouseTracking(true); // replace selection model auto old_model = selectionModel(); @@ -30,6 +33,24 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { }); } +void BinaryView::highlight(const Signal *sig) { + if (sig != hovered_sig) { + hovered_sig = sig; + model->dataChanged(model->index(0, 0), model->index(model->rowCount() - 1, model->columnCount() - 1)); + emit signalHovered(hovered_sig); + } +} + +void BinaryView::mouseMoveEvent(QMouseEvent *event) { + if (auto index = indexAt(event->pos()); index.isValid()) { + auto item = (BinaryViewModel::Item *)index.internalPointer(); + highlight(item->sig); + if (item->sig) + QToolTip::showText(event->globalPos(), item->sig->name.c_str(), this, rect()); + } + QTableView::mouseMoveEvent(event); +} + void BinaryView::mouseReleaseEvent(QMouseEvent *event) { QTableView::mouseReleaseEvent(event); @@ -40,6 +61,11 @@ void BinaryView::mouseReleaseEvent(QMouseEvent *event) { } } +void BinaryView::leaveEvent(QEvent *event) { + highlight(nullptr); + QTableView::leaveEvent(event); +} + void BinaryView::setMessage(const QString &message_id) { msg_id = message_id; model->setMessage(message_id); @@ -80,7 +106,8 @@ void BinaryViewModel::setMessage(const QString &message_id) { } 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)); + items[idx].bg_color = getColor(i); + items[idx].sig = &dbc_msg->sigs[i]; } } } @@ -170,9 +197,17 @@ QSize BinaryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (const BinaryViewModel::Item *)index.internalPointer(); + BinaryView *bin_view = (BinaryView *)parent(); painter->save(); - // TODO: highlight signal cells on mouse over - painter->fillRect(option.rect, option.state & QStyle::State_Selected ? highlight_color : item->bg_color); + + // background + QColor bg_color = item->sig && bin_view->hoveredSignal() == item->sig ? hoverColor(item->bg_color) : item->bg_color; + if (option.state & QStyle::State_Selected) { + bg_color = highlight_color; + } + painter->fillRect(option.rect, bg_color); + + // text if (index.column() == 8) { painter->setFont(hex_font); } diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 38f0ddf216..48eb5eff8a 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -37,6 +37,7 @@ public: bool is_msb = false; bool is_lsb = false; QString val = "0"; + const Signal *sig = nullptr; }; private: @@ -59,14 +60,21 @@ class BinaryView : public QTableView { public: BinaryView(QWidget *parent = nullptr); - void mouseReleaseEvent(QMouseEvent *event) override; void setMessage(const QString &message_id); void updateState(); + void highlight(const Signal *sig); + const Signal *hoveredSignal() const { return hovered_sig; } signals: void cellsSelected(int start_bit, int size); + void signalHovered(const Signal *sig); private: + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void leaveEvent(QEvent *event) override; + QString msg_id; BinaryViewModel *model; + const Signal *hovered_sig = nullptr; }; diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 44131ad5c9..a468fb2956 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -103,6 +104,12 @@ 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; extern Settings settings; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index a92969d4d3..1f1b73638b 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -86,6 +86,8 @@ void DetailWidget::dbcMsgChanged() { QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); + QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); + QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); } msg_name = msg->name.c_str(); if (msg->size != can->lastMessage(msg_id).dat.size()) { diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 050802d452..d5dccf0e6d 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -82,7 +82,7 @@ Signal SignalForm::getSignal() { // SignalEdit SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWidget *parent) - : sig_name(sig.name.c_str()), QWidget(parent) { + : sig(&sig), form_idx(index), sig_name(sig.name.c_str()), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -152,6 +152,21 @@ void SignalEdit::setFormVisible(bool visible) { icon->setText(visible ? "▼" : ">"); } +void SignalEdit::signalHovered(const Signal *s) { + auto color = sig == s ? hoverColor(getColor(form_idx)) : QColor(getColor(form_idx)); + title->setStyleSheet(QString("font-weight:bold; color:%1").arg(color.name())); +} + +void SignalEdit::enterEvent(QEvent *event) { + emit highlight(sig); + QWidget::enterEvent(event); +} + +void SignalEdit::leaveEvent(QEvent *event) { + emit highlight(nullptr); + QWidget::leaveEvent(event); +} + // AddSignalDialog AddSignalDialog::AddSignalDialog(const QString &id, int start_bit, int size, QWidget *parent) : QDialog(parent) { diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index f7611747ec..1213b3ec51 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -30,17 +30,24 @@ class SignalEdit : public QWidget { public: SignalEdit(int index, const QString &msg_id, const Signal &sig, QWidget *parent = nullptr); void setFormVisible(bool show); + void signalHovered(const Signal *sig); inline bool isFormVisible() const { return form_container->isVisible(); } QString sig_name; SignalForm *form; + int form_idx = 0; + const Signal *sig = nullptr; signals: + void highlight(const Signal *sig); void showChart(); void showFormClicked(); void remove(); void save(); protected: + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + ElidedLabel *title; QWidget *form_container; QLabel *icon; From d2c1bb4238436dd5e39447f367b7ff1dc0b531b8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 19 Oct 2022 14:13:06 -0700 Subject: [PATCH 0007/1179] Update CI routes: speed up (#26162) * cache get_azure_keys * tqdm --- selfdrive/test/update_ci_routes.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/test/update_ci_routes.py b/selfdrive/test/update_ci_routes.py index 201ffb745a..933027840d 100755 --- a/selfdrive/test/update_ci_routes.py +++ b/selfdrive/test/update_ci_routes.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +from functools import lru_cache import sys import subprocess +from tqdm import tqdm from azure.storage.blob import BlockBlobService # pylint: disable=import-error from selfdrive.car.tests.routes import routes as test_car_models_routes @@ -15,6 +17,7 @@ SOURCES = [ ] +@lru_cache def get_azure_keys(): dest_key = azureutil.get_user_token(_DATA_ACCOUNT_CI, "openpilotci") source_keys = [azureutil.get_user_token(account, bucket) for account, bucket in SOURCES] @@ -82,7 +85,7 @@ if __name__ == "__main__": to_sync.extend([rt.route for rt in test_car_models_routes]) to_sync.extend([s[1].rsplit('--', 1)[0] for s in replay_segments]) - for r in to_sync: + for r in tqdm(to_sync): if not sync_to_ci_public(r): failed_routes.append(r) From 2ed51e31517e1e1948833cfcf8d2c83471b1e1be Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 20 Oct 2022 05:18:28 +0800 Subject: [PATCH 0008/1179] Cabana: load DBC from car fingerprint (#26158) * auto load DBC from fingerprint * generate json in scons --- tools/cabana/.gitignore | 2 ++ tools/cabana/SConscript | 1 + tools/cabana/generate_dbc_json.py | 24 +++++++++++++++++++++++ tools/cabana/messageswidget.cc | 32 ++++++++++++++++++++++--------- tools/cabana/messageswidget.h | 7 +++++-- 5 files changed, 55 insertions(+), 11 deletions(-) create mode 100755 tools/cabana/generate_dbc_json.py diff --git a/tools/cabana/.gitignore b/tools/cabana/.gitignore index 88ffab2717..d7a552eabb 100644 --- a/tools/cabana/.gitignore +++ b/tools/cabana/.gitignore @@ -3,3 +3,5 @@ moc_* _cabana settings +car_fingerprint_to_dbc.json + diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index fd44ecd138..d791466ce7 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -12,5 +12,6 @@ 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.Execute('./generate_dbc_json.py --out car_fingerprint_to_dbc.json') 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/generate_dbc_json.py b/tools/cabana/generate_dbc_json.py new file mode 100755 index 0000000000..cb122e2eb2 --- /dev/null +++ b/tools/cabana/generate_dbc_json.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +import argparse +import json + +from selfdrive.car.car_helpers import get_interface_attr + + +def generate_dbc_json() -> str: + all_cars_by_brand = get_interface_attr("CAR_INFO") + all_dbcs_by_brand = get_interface_attr("DBC") + dbc_map = {car: all_dbcs_by_brand[brand][car]['pt'] for brand, cars in all_cars_by_brand.items() for car in cars if car != 'mock'} + return json.dumps(dict(sorted(dbc_map.items())), indent=2) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate mapping for all car fingerprints to DBC names and outputs json file", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + parser.add_argument("--out", required=True, help="Generated json filepath") + args = parser.parse_args() + + with open(args.out, 'w') as f: + f.write(generate_dbc_json()) + print(f"Generated and written to {args.out}") diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index f39ce97684..dfe665d750 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -68,9 +68,10 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // signals/slots QObject::connect(filter, &QLineEdit::textChanged, proxy_model, &QSortFilterProxyModel::setFilterFixedString); + QObject::connect(can, &CANMessages::eventsMerged, this, &MessagesWidget::loadDBCFromFingerprint); QObject::connect(can, &CANMessages::updated, model, &MessageListModel::updateState); - QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(dbcSelectionChanged(const QString &))); - QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadFromPaste); + QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); + QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadDBCFromPaste); QObject::connect(save_btn, &QPushButton::clicked, [=]() { // TODO: save DBC to file }); @@ -80,17 +81,20 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { } }); - // For test purpose - dbc_combo->setCurrentText("toyota_nodsu_pt_generated"); + QFile json_file("./car_fingerprint_to_dbc.json"); + if(json_file.open(QIODevice::ReadOnly)) { + fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); + } } -void MessagesWidget::dbcSelectionChanged(const QString &dbc_file) { - dbc()->open(dbc_file); - // TODO: reset model? - table_widget->sortByColumn(0, Qt::AscendingOrder); +void MessagesWidget::loadDBCFromName(const QString &name) { + dbc()->open(name); + dbc_combo->setCurrentText(name); + // refresh model + model->updateState(); } -void MessagesWidget::loadFromPaste() { +void MessagesWidget::loadDBCFromPaste() { LoadDBCDialog dlg(this); if (dlg.exec()) { dbc()->open("from paste", dlg.dbc_edit->toPlainText()); @@ -98,6 +102,16 @@ void MessagesWidget::loadFromPaste() { } } +void MessagesWidget::loadDBCFromFingerprint() { + auto fingerprint = can->carFingerprint(); + if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { + auto dbc_name = fingerprint_to_dbc[fingerprint]; + if (dbc_name != QJsonValue::Undefined) { + loadDBCFromName(dbc_name.toString()); + } + } +} + // MessageListModel QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 1184772f3b..bef15c2cf7 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,9 @@ public: MessagesWidget(QWidget *parent); public slots: - void dbcSelectionChanged(const QString &dbc_file); - void loadFromPaste(); + void loadDBCFromName(const QString &name); + void loadDBCFromFingerprint(); + void loadDBCFromPaste(); signals: void msgSelectionChanged(const QString &message_id); @@ -48,4 +50,5 @@ protected: QTableView *table_widget; QComboBox *dbc_combo; MessageListModel *model; + QJsonDocument fingerprint_to_dbc; }; From f6416e776995df68c5ae43354c9af7c335ed2e26 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 19 Oct 2022 14:21:03 -0700 Subject: [PATCH 0009/1179] Hyundai HDA2 detection: use ADAS ECU (#26130) * use adas ecu * new route * update refs * new route * update refs * new test routes * bump --- selfdrive/car/hyundai/interface.py | 5 +++-- selfdrive/car/tests/routes.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/test_processes.py | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 13e93c7d06..cf7063aacc 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -8,6 +8,7 @@ from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.disable_ecu import disable_ecu +Ecu = car.CarParams.Ecu ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL) @@ -33,8 +34,8 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30} if candidate in CANFD_CAR: - # detect HDA2 with LKAS message - if 0x50 in fingerprint[6]: + # detect HDA2 with ADAS Driving ECU + if Ecu.adas in [fw.ecu for fw in car_fw]: ret.flags |= HyundaiFlags.CANFD_HDA2.value else: # non-HDA2 diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 85787ae88d..1dea53a05e 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -97,7 +97,7 @@ routes = [ CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), - CarTestRoute("22de8111a8c5463c|2022-07-29--13-34-49", HYUNDAI.IONIQ_5), + CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.IONIQ_5), # HDA2 CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019), CarTestRoute("fa8db5869167f821|2021-06-10--22-50-10", HYUNDAI.IONIQ_PHEV), CarTestRoute("2c5cf2dd6102e5da|2020-12-17--16-06-44", HYUNDAI.IONIQ_EV_2020), @@ -110,7 +110,7 @@ routes = [ CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.KONA_HEV), CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER), CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.VELOSTER), - CarTestRoute("d824e27e8c60172c|2022-05-19--16-15-28", HYUNDAI.KIA_EV6), # HDA2 + CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2 CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1 CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021), CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0b4081595b..b0613393ad 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -1c1287691cbdd866d9e435d5d27f59f6a027d270 +a87455caf93e91fae0f3704aa476e0732d066b77 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 683387dce8..cecabd8a3a 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -18,7 +18,7 @@ from tools.lib.logreader import LogReader source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY ("HYUNDAI", "02c45f73a2e5c6e9|2021-01-01--19-08-22--1"), # HYUNDAI.SONATA - ("HYUNDAI2", "d824e27e8c60172c|2022-09-13--11-26-50--2"), # HYUNDAI.KIA_EV6 + ("HYUNDAI2", "d545129f3ca90f28|2022-10-19--09-22-54--9"), # HYUNDAI.KIA_EV6 ("TOYOTA", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA.PRIUS (INDI) ("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR) ("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2 @@ -40,7 +40,7 @@ source_segments = [ segments = [ ("BODY", "regenFA002A80700|2022-09-27--15-37-02--0"), ("HYUNDAI", "regenBE53A59065B|2022-09-27--16-52-03--0"), - ("HYUNDAI2", "regenFA8B5CA9840|2022-10-12--21-47-06--0"), + ("HYUNDAI2", "d545129f3ca90f28|2022-10-19--09-22-54--9"), ("TOYOTA", "regen929C5790007|2022-09-27--16-27-47--0"), ("TOYOTA2", "regenEA3950D7F22|2022-09-27--15-43-24--0"), ("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"), From 1766cf9fc232e56e54429ff464fa237e913a348c Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 19 Oct 2022 17:31:02 -0400 Subject: [PATCH 0010/1179] HKG: Car Port for Kia Sportage Hybrid 2023 (#26106) * HKG: Car Port for Kia Sportage Hybrid 2023 * Add torque values * Add test route * Fix CARS.md * cleanup Co-authored-by: Adeeb Shihadeh --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/hyundai/interface.py | 5 +++++ selfdrive/car/hyundai/values.py | 15 +++++++++++++-- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 35ed1b9520..51387091b8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,6 +12,7 @@ Version 0.8.17 (2022-XX-XX) * Border turns grey while overriding steering * Added button to bookmark events while driving; view them later in comma connect * AGNOS 6 +* Kia Sportage Hybrid 2023 support thanks to sunnyhaibin! Version 0.8.16 (2022-08-26) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index 4c65f0007b..a03da5ca6a 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 208 Supported Cars +# 209 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -100,6 +100,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Telluride 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index cf7063aacc..b1fa8d9e1d 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -248,6 +248,11 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16. tire_stiffness_factor = 0.65 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: + ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only + ret.wheelbase = 2.756 + ret.steerRatio = 13.6 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) # Genesis elif candidate == CAR.GENESIS_G70: diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index f69273ba55..0c4cf3c743 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -90,6 +90,7 @@ class CAR: KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_SELTOS = "KIA SELTOS 2021" KIA_SORENTO = "KIA SORENTO GT LINE 2018" + KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN" KIA_STINGER = "KIA STINGER GT2 2018" KIA_CEED = "KIA CEED INTRO ED 2019" KIA_EV6 = "KIA EV6 2022" @@ -172,6 +173,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), ], + CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e), CAR.KIA_EV6: [ @@ -1367,6 +1369,14 @@ FW_VERSIONS = { b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', ], }, + CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00NQ5__ 1.01 1.03 99110-CH000 ', + ], + }, } CHECKSUM = { @@ -1384,12 +1394,12 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN} # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } -HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN} # these cars use a different gas signal +HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN} # these cars use a different gas signal EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5} # these cars require a special panda safety mode due to missing counters and checksums in the messages @@ -1442,4 +1452,5 @@ DBC = { CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.IONIQ_5: dbc_dict('hyundai_canfd', None), + CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 1dea53a05e..8c4efe3061 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -91,6 +91,7 @@ routes = [ CarTestRoute("7653b2bce7bcfdaa|2020-03-04--15-34-32", HYUNDAI.KIA_OPTIMA_G4), CarTestRoute("018654717bc93d7d|2022-09-19--23-11-10", HYUNDAI.KIA_OPTIMA_G4_FL, segment=0), CarTestRoute("c75a59efa0ecd502|2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS), + CarTestRoute("b3537035ffe6a7d6|2022-10-17--15-23-49", HYUNDAI.KIA_SPORTAGE_HYBRID_5TH_GEN), CarTestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA), CarTestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF), CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 889eeffb25..13a0dae7a7 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -32,6 +32,7 @@ CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05] VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1] VOLKSWAGEN SHARAN 2ND GEN: [2.5, 2.5, 0.1] HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0] +KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.0] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From bd3b2e624617eb8f46990f8f1bb3e061a6387195 Mon Sep 17 00:00:00 2001 From: Kyumin Han Date: Wed, 19 Oct 2022 17:35:57 -0400 Subject: [PATCH 0011/1179] HKG: Remove Kia Stinger from 255 torque blacklist (#25866) --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 0c4cf3c743..0fee3ccc51 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -36,7 +36,7 @@ class CarControllerParams: # If the max stock LKAS request is <384, add your car to this list. elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.ELANTRA_GT_I30, CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV, - CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO, CAR.KIA_STINGER): + CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO): self.STEER_MAX = 255 # Default for most HKG From 334ee602f53b7645baba41610051c807ffe5bebb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 19 Oct 2022 14:43:12 -0700 Subject: [PATCH 0012/1179] cabana: add usage to readme --- tools/cabana/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/cabana/README.md b/tools/cabana/README.md index f64e6b2d2d..99d0d4c9ce 100644 --- a/tools/cabana/README.md +++ b/tools/cabana/README.md @@ -6,4 +6,19 @@ Cabana is a tool developed to view raw CAN data. One use for this is creating an ## Usage Instructions +```bash +$ ./cabana -h +Usage: ./_cabana [options] route + +Options: + -h, --help Displays this help. + --demo use a demo route instead of providing your own + --qcam load qcamera + --data_dir local directory with routes + +Arguments: + route the drive to replay. find your drives at + connect.comma.ai +``` + See [openpilot wiki](https://github.com/commaai/openpilot/wiki/Cabana) From 3ee8572d585cf1e56bb00666cb8747dc8f2e77e7 Mon Sep 17 00:00:00 2001 From: hoomoose <94947902+hoomoose@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:19:38 -0600 Subject: [PATCH 0013/1179] HKG: resume from standstill for HDA1 CAN-FD (#26069) * Cruise Button Press on bus 6 for HDA1 Canfd * use bus helper * Update hyundaicanfd.py * Update hyundaicanfd.py * Update hyundaicanfd.py * Update hyundaicanfd.py * Update selfdrive/car/hyundai/hyundaicanfd.py Co-authored-by: Shane Smiskol * Update selfdrive/car/hyundai/hyundaicanfd.py Co-authored-by: Shane Smiskol * bump panda Co-authored-by: Shane Smiskol Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/car/hyundai/carcontroller.py | 9 ++++++--- selfdrive/car/hyundai/hyundaicanfd.py | 8 +++++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/panda b/panda index b95a65df58..dd751862c3 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit b95a65df58fea89b42b7c6b4fc85289b93a0bdb2 +Subproject commit dd751862c34f6a9c9c95748acaf31b8534b42497 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 6b38297eb9..913f683e2c 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -135,14 +135,17 @@ class CarController: self.last_button_frame = self.frame else: for _ in range(20): - can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.CANCEL)) + can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, CS.buttons_counter+1, Buttons.CANCEL)) self.last_button_frame = self.frame # cruise standstill resume elif CC.cruiseControl.resume: - if not (self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS): + if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS: + # TODO: resume for alt button cars + pass + else: for _ in range(20): - can_sends.append(hyundaicanfd.create_buttons(self.packer, CS.buttons_counter+1, Buttons.RES_ACCEL)) + can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, CS.buttons_counter+1, Buttons.RES_ACCEL)) self.last_button_frame = self.frame else: can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, lat_active, diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index f2cbafdcf0..e1478e6f18 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -3,7 +3,7 @@ from selfdrive.car.hyundai.values import HyundaiFlags def get_e_can_bus(CP): # On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars - # have a a different harness than the HDA1 and non-HDA variants in order to split + # have a different harness than the HDA1 and non-HDA variants in order to split # a different bus, since the steering is done by different ECUs. return 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4 @@ -39,13 +39,15 @@ def create_cam_0x2a4(packer, camera_values): }) return packer.make_can_msg("CAM_0x2a4", 4, camera_values) -def create_buttons(packer, cnt, btn): +def create_buttons(packer, CP, cnt, btn): values = { "COUNTER": cnt, "SET_ME_1": 1, "CRUISE_BUTTONS": btn, } - return packer.make_can_msg("CRUISE_BUTTONS", 5, values) + + bus = 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 6 + return packer.make_can_msg("CRUISE_BUTTONS", bus, values) def create_acc_cancel(packer, CP, cruise_info_copy): values = cruise_info_copy From 017b5b27718afc844bc5c08cff09dfac95d5ba46 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 19 Oct 2022 15:20:55 -0700 Subject: [PATCH 0014/1179] HKG CAN-FD: query camera on both buses (#26167) fwdCamera is only on bus 4 on HDA1, only bus 5 on HDA2 --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 0fee3ccc51..d5b8427f66 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -306,7 +306,7 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdRadar], + whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar], bus=4, ), Request( From ffc151ed8facbb6b29c6cf1aa6676f2c59271483 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 19 Oct 2022 15:34:06 -0700 Subject: [PATCH 0015/1179] no more preserve bucket --- selfdrive/test/update_ci_routes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/test/update_ci_routes.py b/selfdrive/test/update_ci_routes.py index 933027840d..a2b971999c 100755 --- a/selfdrive/test/update_ci_routes.py +++ b/selfdrive/test/update_ci_routes.py @@ -12,7 +12,6 @@ from xx.chffr.lib.storage import _DATA_ACCOUNT_PRODUCTION, _DATA_ACCOUNT_CI, _DA SOURCES = [ (_DATA_ACCOUNT_PRODUCTION, _DATA_BUCKET_PRODUCTION), - (_DATA_ACCOUNT_PRODUCTION, "preserve"), (_DATA_ACCOUNT_CI, "commadataci"), ] From 93e972e6f9907382d62807c5d4c2eb80327ebc43 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 19 Oct 2022 16:55:14 -0700 Subject: [PATCH 0016/1179] Update RELEASES.md --- RELEASES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 51387091b8..b424259581 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,9 +2,10 @@ Version 0.8.17 (2022-XX-XX) ======================== * New driving model * Internal feature space accuracy increased tenfold during training, this makes the model dramatically more accurate. +* New driver monitoring model + * New end-to-end distracted trigger * Self-tuning torque lateral controller parameters * Parameters learned live for each car - * Enabled only on Toyota Corolla for now * UI updates * Multi-language in navigation * Matched speeds shown on car's dash @@ -12,6 +13,7 @@ Version 0.8.17 (2022-XX-XX) * Border turns grey while overriding steering * Added button to bookmark events while driving; view them later in comma connect * AGNOS 6 +* tools: new and improved cabana thanks to deanlee! * Kia Sportage Hybrid 2023 support thanks to sunnyhaibin! Version 0.8.16 (2022-08-26) From 1800592f5a4403a38891f8513e6438300a3b5e01 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 19 Oct 2022 17:09:25 -0700 Subject: [PATCH 0017/1179] DM: finetune e2e policy but keep alert rate (#26168) --- selfdrive/monitoring/driver_monitor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index 30781f4d1b..a2dda5da9d 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -32,7 +32,8 @@ class DRIVER_MONITOR_SETTINGS(): self._BLINK_THRESHOLD = 0.895 self._EE_THRESH11 = 0.275 - self._EE_THRESH12 = 3.0 + self._EE_THRESH12 = 5.5 + self._EE_MAX_OFFSET1 = 0.06 self._EE_THRESH21 = 0.01 self._EE_THRESH22 = 0.35 @@ -204,7 +205,7 @@ class DriverStatus(): distracted_types.append(DistractedType.DISTRACTED_BLINK) if self.ee1_calibrated: - ee1_dist = self.eev1 > self.ee1_offseter.filtered_stat.M * self.settings._EE_THRESH12 + ee1_dist = self.eev1 > min(self.ee1_offseter.filtered_stat.M, self.settings._EE_MAX_OFFSET1) * self.settings._EE_THRESH12 else: ee1_dist = self.eev1 > self.settings._EE_THRESH11 # if self.ee2_calibrated: From 301a7ce1899a3212900dc6cfb08de6840d276a05 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 19 Oct 2022 20:40:52 -0700 Subject: [PATCH 0018/1179] GM: make loopback updated check more explicit This previously checked if parser_pyx filled the defaultdict, now it checks the values in the list (same either way) --- selfdrive/car/gm/carstate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index f531914877..b651606b79 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -28,7 +28,7 @@ class CarState(CarStateBase): self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] # Variables used for avoiding LKAS faults - self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]) > 0 + self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 if self.CP.networkLocation == NetworkLocation.fwdCamera: self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] From eaedfb9a66012b82091c4b602184a0078d7f0c25 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 19 Oct 2022 23:31:24 -0700 Subject: [PATCH 0019/1179] Hyundai CAN-FD: use cruise signals from SCC ECU (#26171) * Hyundai CAN-FD: use cruise signals from SCC ECU * bump panda * bumppanda * update refs --- panda | 2 +- selfdrive/car/hyundai/carstate.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/panda b/panda index dd751862c3..723e60cb43 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit dd751862c34f6a9c9c95748acaf31b8534b42497 +Subproject commit 723e60cb435ad5d3b6a8e99080be46a6590259cd diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 5da1dd72c8..60d434a603 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -189,13 +189,13 @@ class CarState(CarStateBase): cp.vl["BLINKERS"]["RIGHT_LAMP"]) ret.cruiseState.available = True - ret.cruiseState.enabled = cp.vl["SCC1"]["CRUISE_ACTIVE"] == 1 self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1 if not self.CP.openpilotLongitudinalControl: speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS cp_cruise_info = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam ret.cruiseState.speed = cp_cruise_info.vl["CRUISE_INFO"]["SET_SPEED"] * speed_factor ret.cruiseState.standstill = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STANDSTILL"] == 1 + ret.cruiseState.enabled = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STATUS"] != 0 self.cruise_info = copy.copy(cp_cruise_info.vl["CRUISE_INFO"]) cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" @@ -452,6 +452,7 @@ class CarState(CarStateBase): if CP.flags & HyundaiFlags.CANFD_HDA2 and not CP.openpilotLongitudinalControl: signals += [ + ("CRUISE_STATUS", "CRUISE_INFO"), ("SET_SPEED", "CRUISE_INFO"), ("CRUISE_STANDSTILL", "CRUISE_INFO"), ] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index b0613393ad..84658effee 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a87455caf93e91fae0f3704aa476e0732d066b77 \ No newline at end of file +1f41cd8bbf2431ae89c489a81698120d14a44145 \ No newline at end of file From 63d552cafc6e4728cfe097e7a3f8e3f5cd98a566 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 19 Oct 2022 23:41:54 -0700 Subject: [PATCH 0020/1179] GM camera ACC: hide take steering alert (#26010) * add all signals * try to forward this PSCMStatus * fixes * see if this works * modify checksum when bit flipped * bump opendbc * so i can test without restarting * bump * bump panda * clean up * comment * also fix this * bump * bump * every 5 seconds * only send our values * fix * try sending everything again (+1 counter) * revert * revert, forward msg * forward * fix that * bump panda * bump panda * fine to not copy * after cancel, pass bus * fix * Revert "fine to not copy" This reverts commit 654ac1a7dad4f7b9b0a3de52768522fb60cc55bd. --- panda | 2 +- selfdrive/car/gm/carcontroller.py | 4 ++++ selfdrive/car/gm/carstate.py | 7 +++++++ selfdrive/car/gm/gmcan.py | 6 ++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/panda b/panda index 723e60cb43..54f9390ff5 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 723e60cb435ad5d3b6a8e99080be46a6590259cd +Subproject commit 54f9390ff51b4fb0c2b3a81b9cde8727acdd1977 diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 7c883dacc0..dbad355c46 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -117,6 +117,10 @@ class CarController: self.last_button_frame = self.frame can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) + # Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1 + if self.frame % 10 == 0: + can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status)) + # Show green icon when LKA torque is applied, and # alarming orange icon when approaching torque limit. # If not sent again, LKA icon disappears in about 5 seconds. diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index b651606b79..de63f56eab 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -1,3 +1,4 @@ +import copy from cereal import car from common.conversions import Conversions as CV from common.numpy_fast import mean @@ -26,6 +27,7 @@ class CarState(CarStateBase): self.prev_cruise_buttons = self.cruise_buttons self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] + self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"]) # Variables used for avoiding LKAS faults self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 @@ -147,6 +149,11 @@ class CarState(CarStateBase): ("LKADriverAppldTrq", "PSCMStatus"), ("LKATorqueDelivered", "PSCMStatus"), ("LKATorqueDeliveredStatus", "PSCMStatus"), + ("HandsOffSWlDetectionStatus", "PSCMStatus"), + ("HandsOffSWDetectionMode", "PSCMStatus"), + ("LKATotalTorqueDelivered", "PSCMStatus"), + ("PSCMStatusChecksum", "PSCMStatus"), + ("RollingCounter", "PSCMStatus"), ("TractionControlOn", "ESPStatus"), ("ParkBrake", "VehicleIgnitionAlt"), ("CruiseMainOn", "ECMEngineStatus"), diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 20e4c4ab6e..ec046dc3c2 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -7,6 +7,12 @@ def create_buttons(packer, bus, idx, button): } return packer.make_can_msg("ASCMSteeringButton", bus, values) +def create_pscm_status(packer, bus, pscm_status): + checksum_mod = int(1 - pscm_status["HandsOffSWlDetectionStatus"]) << 5 + pscm_status["HandsOffSWlDetectionStatus"] = 1 + pscm_status["PSCMStatusChecksum"] += checksum_mod + return packer.make_can_msg("PSCMStatus", bus, pscm_status) + def create_steering_control(packer, bus, apply_steer, idx, lkas_active): values = { From 5d8840b6ee2302def37b2e6cd8b4c826127fc0f4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 20 Oct 2022 22:56:12 +0800 Subject: [PATCH 0021/1179] cabana: remove unused metatype (#26175) remove unused metatype --- tools/cabana/canmessages.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 897381b3f2..2ef9dba600 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -13,7 +13,6 @@ CANMessages *can = nullptr; CANMessages::CANMessages(QObject *parent) : QObject(parent) { can = this; - qRegisterMetaType>(); QObject::connect(this, &CANMessages::received, this, &CANMessages::process, Qt::QueuedConnection); QObject::connect(&settings, &Settings::changed, this, &CANMessages::settingChanged); } From b2b27ff7ee00da4b1bffa7bbe95462303b835024 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 20 Oct 2022 22:56:28 +0800 Subject: [PATCH 0022/1179] cabana: improve signal highlight on hover (#26161) * just change font color * merge master --- tools/cabana/binaryview.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 168edc75f4..c0ebfa9f0a 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -200,16 +200,19 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op BinaryView *bin_view = (BinaryView *)parent(); painter->save(); + bool hover = item->sig && bin_view->hoveredSignal() == item->sig; // background - QColor bg_color = item->sig && bin_view->hoveredSignal() == item->sig ? hoverColor(item->bg_color) : item->bg_color; + QColor bg_color = hover ? hoverColor(item->bg_color) : item->bg_color; if (option.state & QStyle::State_Selected) { bg_color = highlight_color; } painter->fillRect(option.rect, bg_color); // text - if (index.column() == 8) { + if (index.column() == 8) { // hex column painter->setFont(hex_font); + } else if (hover) { + painter->setPen(Qt::white); } painter->drawText(option.rect, Qt::AlignCenter, item->val); if (item->is_msb || item->is_lsb) { From 998d18783dee2c0d17acd7c5f0ebf82d5ac42d19 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 02:21:22 +0800 Subject: [PATCH 0023/1179] Cabana: multiple tabs detail view (#26174) --- tools/cabana/detailwidget.cc | 46 +++++++++++++++++++++++++++++------- tools/cabana/detailwidget.h | 3 +++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 1f1b73638b..fdedb066fb 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -12,13 +12,26 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setSpacing(0); - // title + // tabbar + tabbar = new QTabBar(this); + tabbar->setTabsClosable(true); + tabbar->setDrawBase(false); + tabbar->setUsesScrollButtons(true); + tabbar->setAutoHide(true); + main_layout->addWidget(tabbar); + + // message title + QFrame *title_frame = new QFrame(); + main_layout->addWidget(title_frame); + QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); + title_frame->setFrameShape(QFrame::StyledPanel); QHBoxLayout *title_layout = new QHBoxLayout(); title_layout->addWidget(new QLabel("time:")); time_label = new QLabel(this); - title_layout->addWidget(time_label); time_label->setStyleSheet("font-weight:bold"); + title_layout->addWidget(time_label); title_layout->addStretch(); name_label = new QLabel(this); name_label->setStyleSheet("font-weight:bold;"); @@ -27,18 +40,18 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { edit_btn = new QPushButton(tr("Edit"), this); edit_btn->setVisible(false); title_layout->addWidget(edit_btn); - main_layout->addLayout(title_layout); + frame_layout->addLayout(title_layout); // warning warning_widget = new QWidget(this); QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); - QLabel *warning_icon = new QLabel(this); + QLabel *warning_icon = new QLabel(this); warning_icon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap({16, 16})); warning_hlayout->addWidget(warning_icon); warning_label = new QLabel(this); - warning_hlayout->addWidget(warning_label,1, Qt::AlignLeft); + warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); warning_widget->hide(); - main_layout->addWidget(warning_widget); + frame_layout->addWidget(warning_widget); // binary view binary_view = new BinaryView(this); @@ -63,13 +76,28 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { 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); + QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { setMessage(messages[index]); }); + QObject::connect(tabbar, &QTabBar::tabCloseRequested, [=](int index) { + messages.removeAt(index); + tabbar->removeTab(index); + setMessage(messages.isEmpty() ? "" : messages[0]); + }); } void DetailWidget::setMessage(const QString &message_id) { - if (msg_id != message_id) { - msg_id = message_id; - dbcMsgChanged(); + if (message_id.isEmpty()) return; + + int index = messages.indexOf(message_id); + if (index == -1) { + messages.push_back(message_id); + tabbar->addTab(message_id); + index = tabbar->count() - 1; + auto msg = dbc()->msg(message_id); + tabbar->setTabToolTip(index, msg ? msg->name.c_str() : "untitled"); } + tabbar->setCurrentIndex(index); + msg_id = message_id; + dbcMsgChanged(); } void DetailWidget::dbcMsgChanged() { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 07c78caa4a..d935839dc4 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "tools/cabana/binaryview.h" #include "tools/cabana/historylog.h" @@ -50,6 +51,8 @@ private: QWidget *warning_widget; QPushButton *edit_btn; QWidget *signals_container; + QTabBar *tabbar; + QStringList messages; HistoryLog *history_log; BinaryView *binary_view; ScrollArea *scroll; From 4bf86742e64bbfb826540fbd263c0e250349f49a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 02:22:09 +0800 Subject: [PATCH 0024/1179] Cabana: move settings to seperate files (#26173) --- tools/cabana/SConscript | 11 ++++-- tools/cabana/canmessages.cc | 24 ----------- tools/cabana/canmessages.h | 20 +--------- tools/cabana/mainwin.cc | 52 ------------------------ tools/cabana/mainwin.h | 12 ------ tools/cabana/settings.cc | 79 +++++++++++++++++++++++++++++++++++++ tools/cabana/settings.h | 35 ++++++++++++++++ 7 files changed, 124 insertions(+), 109 deletions(-) create mode 100644 tools/cabana/settings.cc create mode 100644 tools/cabana/settings.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index d791466ce7..4e4e11dbd8 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -1,3 +1,4 @@ +import os Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', 'cereal', 'transformations', 'widgets', 'opendbc') @@ -12,6 +13,10 @@ 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.Execute('./generate_dbc_json.py --out car_fingerprint_to_dbc.json') -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) +cabana_env = qt_env.Clone() + +prev_moc_path = cabana_env['QT_MOCHPREFIX'] +cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' +cabana_env.Execute('./generate_dbc_json.py --out car_fingerprint_to_dbc.json') +cabana_env.Program('_cabana', ['cabana.cc', 'mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', + 'canmessages.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 2ef9dba600..3900ad93f7 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -7,7 +7,6 @@ Q_DECLARE_METATYPE(std::vector); -Settings settings; CANMessages *can = nullptr; CANMessages::CANMessages(QObject *parent) : QObject(parent) { @@ -158,26 +157,3 @@ void CANMessages::resetRange() { void CANMessages::settingChanged() { replay->setSegmentCacheLimit(settings.cached_segment_limit); } - -// Settings - -Settings::Settings() { - load(); -} - -void Settings::save() { - QSettings s("settings", QSettings::IniFormat); - 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(); - chart_height = s.value("chart_height", 200).toInt(); -} diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index a468fb2956..84f4e06dfb 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -9,25 +9,9 @@ #include #include "opendbc/can/common_dbc.h" +#include "tools/cabana/settings.h" #include "tools/replay/replay.h" -class Settings : public QObject { - Q_OBJECT - -public: - Settings(); - void save(); - void load(); - - int fps = 10; - int can_msg_log_size = 100; - int cached_segment_limit = 3; - int chart_height = 200; - -signals: - void changed(); -}; - struct CanData { double ts; uint16_t bus_time; @@ -112,4 +96,4 @@ inline QColor hoverColor(const QColor &color) { // A global pointer referring to the unique CANMessages object extern CANMessages *can; -extern Settings settings; + diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 50fcbc455c..9ba69f8a90 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -1,9 +1,7 @@ #include "tools/cabana/mainwin.h" #include -#include #include -#include #include #include #include @@ -82,53 +80,3 @@ void MainWindow::setOption() { SettingsDlg dlg(this); dlg.exec(); } - -// SettingsDlg - -SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { - setWindowTitle(tr("Settings")); - QVBoxLayout *main_layout = new QVBoxLayout(this); - QFormLayout *form_layout = new QFormLayout(); - - fps = new QSpinBox(this); - fps->setRange(10, 100); - fps->setSingleStep(10); - fps->setValue(settings.fps); - form_layout->addRow("FPS", fps); - - log_size = new QSpinBox(this); - log_size->setRange(50, 500); - log_size->setSingleStep(10); - log_size->setValue(settings.can_msg_log_size); - form_layout->addRow(tr("Log size"), log_size); - - cached_segment = new QSpinBox(this); - cached_segment->setRange(3, 60); - cached_segment->setSingleStep(1); - 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); - main_layout->addWidget(buttonBox); - - setFixedWidth(360); - connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDlg::save); - connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -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 594e608b59..792390d5c1 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -23,15 +23,3 @@ protected: QWidget *floating_window = nullptr; QVBoxLayout *r_layout; }; - -class SettingsDlg : public QDialog { - Q_OBJECT - -public: - SettingsDlg(QWidget *parent); - void save(); - QSpinBox *fps; - QSpinBox *log_size ; - QSpinBox *cached_segment; - QSpinBox *chart_height; -}; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc new file mode 100644 index 0000000000..0b36f25fbc --- /dev/null +++ b/tools/cabana/settings.cc @@ -0,0 +1,79 @@ +#include "tools/cabana/settings.h" + +#include +#include +#include + +// Settings +Settings settings; + +Settings::Settings() { + load(); +} + +void Settings::save() { + QSettings s("settings", QSettings::IniFormat); + 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(); + chart_height = s.value("chart_height", 200).toInt(); +} + +// SettingsDlg + +SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Settings")); + QVBoxLayout *main_layout = new QVBoxLayout(this); + QFormLayout *form_layout = new QFormLayout(); + + fps = new QSpinBox(this); + fps->setRange(10, 100); + fps->setSingleStep(10); + fps->setValue(settings.fps); + form_layout->addRow("FPS", fps); + + log_size = new QSpinBox(this); + log_size->setRange(50, 500); + log_size->setSingleStep(10); + log_size->setValue(settings.can_msg_log_size); + form_layout->addRow(tr("Log size"), log_size); + + cached_segment = new QSpinBox(this); + cached_segment->setRange(3, 60); + cached_segment->setSingleStep(1); + 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); + main_layout->addWidget(buttonBox); + + setFixedWidth(360); + connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDlg::save); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +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/settings.h b/tools/cabana/settings.h new file mode 100644 index 0000000000..22542fc04c --- /dev/null +++ b/tools/cabana/settings.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +class Settings : public QObject { + Q_OBJECT + +public: + Settings(); + void save(); + void load(); + + int fps = 10; + int can_msg_log_size = 100; + int cached_segment_limit = 3; + int chart_height = 200; + +signals: + void changed(); +}; + +class SettingsDlg : public QDialog { + Q_OBJECT + +public: + SettingsDlg(QWidget *parent); + void save(); + QSpinBox *fps; + QSpinBox *log_size ; + QSpinBox *cached_segment; + QSpinBox *chart_height; +}; + +extern Settings settings; From 85d39ec34ef80ab292eae0ac18600037f7903e44 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 02:23:27 +0800 Subject: [PATCH 0025/1179] Cabana: dynamic sorting message list (#26150) --- tools/cabana/messageswidget.cc | 106 +++++++++++++++++++++++---------- tools/cabana/messageswidget.h | 16 ++++- 2 files changed, 89 insertions(+), 33 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index dfe665d750..c34d883b3f 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -49,27 +48,23 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // message table table_widget = new QTableView(this); model = new MessageListModel(this); - QSortFilterProxyModel *proxy_model = new QSortFilterProxyModel(this); - proxy_model->setSourceModel(model); - proxy_model->setFilterCaseSensitivity(Qt::CaseInsensitive); - proxy_model->setDynamicSortFilter(false); - table_widget->setModel(proxy_model); + table_widget->setModel(model); table_widget->setSelectionBehavior(QAbstractItemView::SelectRows); table_widget->setSelectionMode(QAbstractItemView::SingleSelection); table_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); table_widget->setSortingEnabled(true); + table_widget->sortByColumn(0, Qt::AscendingOrder); table_widget->setColumnWidth(0, 250); table_widget->setColumnWidth(1, 80); table_widget->setColumnWidth(2, 80); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); - table_widget->sortByColumn(0, Qt::AscendingOrder); main_layout->addWidget(table_widget); // signals/slots - QObject::connect(filter, &QLineEdit::textChanged, proxy_model, &QSortFilterProxyModel::setFilterFixedString); + QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); QObject::connect(can, &CANMessages::eventsMerged, this, &MessagesWidget::loadDBCFromFingerprint); - QObject::connect(can, &CANMessages::updated, model, &MessageListModel::updateState); + QObject::connect(can, &CANMessages::updated, [this]() { model->updateState(); }); QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadDBCFromPaste); QObject::connect(save_btn, &QPushButton::clicked, [=]() { @@ -122,21 +117,15 @@ QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, 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 QString &msg_id = it.key(); - switch (index.column()) { - case 0: { - auto msg = dbc()->msg(msg_id); - return msg ? msg->name.c_str() : "untitled"; - } - case 1: return msg_id; - case 2: return can->counters[msg_id]; - case 3: return toHex(it.value().front().dat); - } + const auto &m = msgs[index.row()]; + switch (index.column()) { + case 0: return m->name; + case 1: return m->id; + case 2: return can->counters[m->id]; + case 3: return toHex(can->lastMessage(m->id).dat); } } else if (role == Qt::UserRole) { - return std::next(can->can_msgs.begin(), index.row()).key(); + return msgs[index.row()]->id; } else if (role == Qt::FontRole) { if (index.column() == 3) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); @@ -145,20 +134,77 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { return {}; } -void MessageListModel::updateState() { - int prev_row_count = row_count; - row_count = can->can_msgs.size(); - int delta = row_count - prev_row_count; +bool MessageListModel::updateMessages(bool sort) { + if (msgs.size() == can->can_msgs.size() && filter_str.isEmpty() && !sort) + return false; + + // update message list + int i = 0; + bool search_id = filter_str.contains(':'); + for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + const Msg *msg = dbc()->msg(it.key()); + QString msg_name = msg ? msg->name.c_str() : "untitled"; + if (!filter_str.isEmpty() && !(search_id ? it.key() : msg_name).contains(filter_str, Qt::CaseInsensitive)) + continue; + auto &m = i < msgs.size() ? msgs[i] : msgs.emplace_back(new Message); + m->id = it.key(); + m->name = msg_name; + ++i; + } + msgs.resize(i); + + if (sort_column == 0) { + std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { + bool ret = l->name < r->name || (l->name == r->name && l->id < r->id); + return sort_order == Qt::AscendingOrder ? ret : !ret; + }); + } else if (sort_column == 1) { + std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { + return sort_order == Qt::AscendingOrder ? l->id < r->id : l->id > r->id; + }); + } else if (sort_column == 2) { + std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { + uint32_t lcount = can->counters[l->id], rcount = can->counters[r->id]; + bool ret = lcount < rcount || (lcount == rcount && l->id < r->id); + return sort_order == Qt::AscendingOrder ? ret : !ret; + }); + } + return true; +} + +void MessageListModel::updateState(bool sort) { + int prev_row_count = msgs.size(); + auto prev_idx = persistentIndexList(); + QString selected_msg_id = prev_idx.empty() ? "" : prev_idx[0].data(Qt::UserRole).toString(); + + bool msg_updated = updateMessages(sort); + int delta = msgs.size() - prev_row_count; if (delta > 0) { - beginInsertRows({}, prev_row_count, row_count - 1); + beginInsertRows({}, prev_row_count, msgs.size() - 1); endInsertRows(); } else if (delta < 0) { - beginRemoveRows({}, row_count, prev_row_count - 1); + beginRemoveRows({}, msgs.size(), prev_row_count - 1); endRemoveRows(); } - if (row_count > 0) { - emit dataChanged(index(0, 0), index(row_count - 1, 3), {Qt::DisplayRole}); + if (!msgs.empty()) { + if (msg_updated && !prev_idx.isEmpty()) { + // keep selection + auto it = std::find_if(msgs.begin(), msgs.end(), [&](auto &m) { return m->id == selected_msg_id; }); + if (it != msgs.end()) { + for (auto &idx : prev_idx) + changePersistentIndex(idx, index(std::distance(msgs.begin(), it), idx.column())); + } + } + emit dataChanged(index(0, 0), index(msgs.size() - 1, 3), {Qt::DisplayRole}); + } +} + +void MessageListModel::sort(int column, Qt::SortOrder order) { + if (column != columnCount() - 1) { + sort_column = column; + sort_order = order; + updateState(true); } } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index bef15c2cf7..7b6c8e53cf 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -25,11 +25,21 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 4; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const override { return row_count; } - void updateState(); + int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; + void updateState(bool sort = false); + void setFilterString(const QString &string) { filter_str = string; } private: - int row_count = 0; + bool updateMessages(bool sort); + + struct Message { + QString id, name; + }; + std::vector> msgs; + QString filter_str; + int sort_column = 0; + Qt::SortOrder sort_order = Qt::AscendingOrder; }; class MessagesWidget : public QWidget { From f957f3391d291c355a789782f00d85aeaa67fabb Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 20 Oct 2022 20:25:20 +0200 Subject: [PATCH 0026/1179] ui brightness: fix exposure scale factor (#26104) --- selfdrive/ui/ui.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 152c7fbfcd..1a6027bf7f 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -163,7 +163,8 @@ static void update_state(UIState *s) { scene.longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); } if (sm.updated("wideRoadCameraState")) { - scene.light_sensor = 100.0f - sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(); + float scale = (sm["wideRoadCameraState"].getWideRoadCameraState().getSensor() == cereal::FrameData::ImageSensor::AR0321) ? 6.0f : 1.0f; + scene.light_sensor = std::max(100.0f - scale * sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(), 0.0f); } scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; } From d6a0f1c25a44ad5629f491bb0066999eb0a9d357 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 04:09:49 +0800 Subject: [PATCH 0027/1179] Cabana: drag to adjust signal size (#26172) * drag to adjust signal size * rename * override setSelection * use signal color as selection color while resing * helper funtion * hide tooltip if not in signal * cleanup * cabana: remove unused metatype (#26175) remove unused metatype * cabana: improve signal highlight on hover (#26161) * just change font color * merge master * cleanup --- tools/cabana/binaryview.cc | 100 ++++++++++++++++++++++++----------- tools/cabana/binaryview.h | 18 +++---- tools/cabana/detailwidget.cc | 23 ++++++-- tools/cabana/detailwidget.h | 3 +- 4 files changed, 101 insertions(+), 43 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index c0ebfa9f0a..eee3f90986 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -13,21 +13,23 @@ const int CELL_HEIGHT = 30; +static std::pair getSignalRange(const Signal *s) { + int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit); + int to = from + s->size - 1; + return {from, to}; +} + BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { model = new BinaryViewModel(this); setModel(model); - setItemDelegate(new BinaryItemDelegate(this)); + delegate = new BinaryItemDelegate(this); + setItemDelegate(delegate); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->hide(); verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setMouseTracking(true); - // 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); }); @@ -41,12 +43,42 @@ void BinaryView::highlight(const Signal *sig) { } } +void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) { + QModelIndex tl = indexAt({qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())}); + QModelIndex br = indexAt({qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())}); + if (!tl.isValid() || !br.isValid()) + return; + + if (tl < anchor_index) { + br = anchor_index; + } else if (anchor_index < br) { + tl = anchor_index; + } + QItemSelection 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); + } + selectionModel()->select(selection, flags); +} + +void BinaryView::mousePressEvent(QMouseEvent *event) { + delegate->setSelectionColor(style()->standardPalette().color(QPalette::Active, QPalette::Highlight)); + anchor_index = indexAt(event->pos()); + if (getResizingSignal() != nullptr) { + auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); + delegate->setSelectionColor(item->bg_color); + } + QTableView::mousePressEvent(event); +} + void BinaryView::mouseMoveEvent(QMouseEvent *event) { if (auto index = indexAt(event->pos()); index.isValid()) { auto item = (BinaryViewModel::Item *)index.internalPointer(); highlight(item->sig); - if (item->sig) - QToolTip::showText(event->globalPos(), item->sig->name.c_str(), this, rect()); + item->sig ? QToolTip::showText(event->globalPos(), item->sig->name.c_str(), this, rect()) + : QToolTip::hideText(); } QTableView::mouseMoveEvent(event); } @@ -55,10 +87,21 @@ 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); + int from = indexes.first().row() * 8 + indexes.first().column(); + int to = indexes.back().row() * 8 + indexes.back().column(); + if (auto sig = getResizingSignal()) { + auto [sig_from, sig_to] = getSignalRange(sig); + if (from >= sig_from && to <= sig_to) { // reduce size + emit(from == sig_from ? resizeSignal(sig, to, sig_to) : resizeSignal(sig, sig_from, from)); + } else { // increase size + emit resizeSignal(sig, std::min(from, sig_from), std::max(to, sig_to)); + } + } else { + emit addSignal(from, to); + } + clearSelection(); } + anchor_index = QModelIndex(); } void BinaryView::leaveEvent(QEvent *event) { @@ -78,6 +121,19 @@ void BinaryView::updateState() { model->updateState(); } +const Signal *BinaryView::getResizingSignal() const { + if (anchor_index.isValid()) { + auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); + if (item && item->sig) { + int archor_pos = anchor_index.row() * 8 + anchor_index.column(); + auto [sig_from, sig_to] = getSignalRange(item->sig); + if (archor_pos == sig_from || archor_pos == sig_to) + return item->sig; + } + } + return nullptr; +} + // BinaryViewModel void BinaryViewModel::setMessage(const QString &message_id) { @@ -93,8 +149,7 @@ void BinaryViewModel::setMessage(const QString &message_id) { 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; + auto [start, end] = getSignalRange(&sig); for (int j = start; j <= end; ++j) { int idx = column_count * (j / 8) + j % 8; if (idx >= items.size()) { @@ -165,21 +220,6 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i 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) { @@ -187,7 +227,7 @@ BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(pa small_font.setPointSize(6); hex_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); hex_font.setBold(true); - highlight_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight); + selection_color = QApplication::style()->standardPalette().color(QPalette::Active, QPalette::Highlight); } QSize BinaryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -204,7 +244,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // background QColor bg_color = hover ? hoverColor(item->bg_color) : item->bg_color; if (option.state & QStyle::State_Selected) { - bg_color = highlight_color; + bg_color = selection_color; } painter->fillRect(option.rect, bg_color); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 48eb5eff8a..8c1a582014 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -12,10 +12,11 @@ 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; + void setSelectionColor(const QColor &color) { selection_color = color; } private: QFont small_font, hex_font; - QColor highlight_color; + QColor selection_color; }; class BinaryViewModel : public QAbstractTableModel { @@ -48,13 +49,6 @@ private: 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 @@ -66,15 +60,21 @@ public: const Signal *hoveredSignal() const { return hovered_sig; } signals: - void cellsSelected(int start_bit, int size); void signalHovered(const Signal *sig); + void addSignal(int from, int size); + void resizeSignal(const Signal *sig, int from, int size); private: + void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override; + void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void leaveEvent(QEvent *event) override; + const Signal *getResizingSignal() const; QString msg_id; + QModelIndex anchor_index; BinaryViewModel *model; + BinaryItemDelegate *delegate; const Signal *hovered_sig = nullptr; }; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index fdedb066fb..579bb1af75 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -73,7 +73,8 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(history_log); QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg); - QObject::connect(binary_view, &BinaryView::cellsSelected, this, &DetailWidget::addSignal); + QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); + QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::dbcMsgChanged); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { setMessage(messages[index]); }); @@ -159,9 +160,9 @@ void DetailWidget::editMsg() { } } -void DetailWidget::addSignal(int start_bit, int size) { +void DetailWidget::addSignal(int start_bit, int to) { if (dbc()->msg(msg_id)) { - AddSignalDialog dlg(msg_id, start_bit, size, this); + AddSignalDialog dlg(msg_id, start_bit, to - start_bit + 1, this); if (dlg.exec()) { dbc()->addSignal(msg_id, dlg.form->getSignal()); dbcMsgChanged(); @@ -169,6 +170,22 @@ void DetailWidget::addSignal(int start_bit, int size) { } } +void DetailWidget::resizeSignal(const Signal *sig, int from, int to) { + assert(sig != nullptr); + Signal s = *sig; + s.start_bit = s.is_little_endian ? from : bigEndianBitIndex(from);; + s.size = to - from + 1; + if (s.is_little_endian) { + s.lsb = s.start_bit; + s.msb = s.start_bit + s.size - 1; + } else { + s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); + s.msb = s.start_bit; + } + dbc()->updateSignal(msg_id, s.name.c_str(), s); + dbcMsgChanged(); +} + void DetailWidget::saveSignal() { SignalEdit *sig_form = qobject_cast(QObject::sender()); auto s = sig_form->form->getSignal(); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index d935839dc4..02bbb2a9e8 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -39,7 +39,8 @@ signals: void removeChart(const Signal *sig); private: - void addSignal(int start_bit, int size); + void addSignal(int start_bit, int to); + void resizeSignal(const Signal *sig, int from, int to); void saveSignal(); void removeSignal(); void editMsg(); From 68530f18b4cb2a1f20dfb19319d91216c23e00bb Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 20 Oct 2022 13:23:59 -0700 Subject: [PATCH 0028/1179] ci: don't trigger on pull request sync event (#25900) --- .github/workflows/selfdrive_tests.yaml | 1 + .github/workflows/tools_tests.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index d84779103b..20bf8c3d8e 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -5,6 +5,7 @@ on: branches-ignore: - 'testing-closet*' pull_request: + types: [opened, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 549a2f4195..71bad021d0 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -5,6 +5,7 @@ on: branches-ignore: - 'testing-closet*' pull_request: + types: [opened, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} From 02a0a1c201e2c203e79669fd927b38768ef645b7 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 04:37:27 +0800 Subject: [PATCH 0029/1179] Cabana: add status bar to main window (#26159) --- tools/cabana/detailwidget.cc | 1 + tools/cabana/mainwin.cc | 43 ++++++++++++++++++++++++++++++++-- tools/cabana/mainwin.h | 10 ++++++++ tools/cabana/messageswidget.cc | 1 + 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 579bb1af75..c7bfdee164 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -12,6 +12,7 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); // tabbar diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 9ba69f8a90..2478155fcf 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -6,14 +6,18 @@ #include #include +#include "tools/replay/util.h" + MainWindow::MainWindow() : QWidget() { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(11, 11, 11, 5); + main_layout->setSpacing(0); QHBoxLayout *h_layout = new QHBoxLayout(); + h_layout->setContentsMargins(0, 0, 0, 0); main_layout->addLayout(h_layout); QSplitter *splitter = new QSplitter(Qt::Horizontal, this); - messages_widget = new MessagesWidget(this); splitter->addWidget(messages_widget); @@ -27,7 +31,7 @@ MainWindow::MainWindow() : QWidget() { QWidget *right_container = new QWidget(this); right_container->setFixedWidth(640); r_layout = new QVBoxLayout(right_container); - + r_layout->setContentsMargins(11, 0, 0, 0); QHBoxLayout *right_hlayout = new QHBoxLayout(); QLabel *fingerprint_label = new QLabel(this); right_hlayout->addWidget(fingerprint_label); @@ -47,6 +51,30 @@ MainWindow::MainWindow() : QWidget() { h_layout->addWidget(right_container); + // status bar + status_bar = new QStatusBar(this); + status_bar->setContentsMargins(0, 0, 0, 0); + status_bar->setSizeGripEnabled(true); + progress_bar = new QProgressBar(); + progress_bar->setRange(0, 100); + progress_bar->setTextVisible(true); + progress_bar->setFixedSize({230, 16}); + progress_bar->setVisible(false); + status_bar->addPermanentWidget(progress_bar); + main_layout->addWidget(status_bar); + + qRegisterMetaType("uint64_t"); + qRegisterMetaType("ReplyMsgType"); + installMessageHandler([this](ReplyMsgType type, const std::string msg) { + // use queued connection to recv the log messages from replay. + emit logMessageFromReplay(QString::fromStdString(msg), 3000); + }); + installDownloadProgressHandler([this](uint64_t cur, uint64_t total, bool success) { + emit updateProgressBar(cur, total, success); + }); + + QObject::connect(this, &MainWindow::logMessageFromReplay, status_bar, &QStatusBar::showMessage); + QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); QObject::connect(detail_widget, &DetailWidget::showChart, charts_widget, &ChartsWidget::addChart); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); @@ -54,6 +82,17 @@ MainWindow::MainWindow() : QWidget() { QObject::connect(can, &CANMessages::eventsMerged, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); } +void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool success) { + if (success && cur < total) { + progress_bar->setValue((cur / (double)total) * 100); + progress_bar->setFormat(tr("Downloading %p% (%1)").arg(formattedDataSize(total).c_str())); + progress_bar->show(); + } else { + progress_bar->hide(); + } +} + + void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 792390d5c1..56d2da145b 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include "tools/cabana/chartswidget.h" #include "tools/cabana/detailwidget.h" #include "tools/cabana/messageswidget.h" @@ -12,8 +15,13 @@ public: MainWindow(); void dockCharts(bool dock); +signals: + void logMessageFromReplay(const QString &msg, int timeout); + void updateProgressBar(uint64_t cur, uint64_t total, bool success); + protected: void closeEvent(QCloseEvent *event) override; + void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); VideoWidget *video_widget; @@ -22,4 +30,6 @@ protected: ChartsWidget *charts_widget; QWidget *floating_window = nullptr; QVBoxLayout *r_layout; + QProgressBar *progress_bar; + QStatusBar *status_bar; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index c34d883b3f..46776a4f5d 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -13,6 +13,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); // DBC file selector QHBoxLayout *dbc_file_layout = new QHBoxLayout(); From 4f84b2998579a630e1577e60dd1d30d23261cd28 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Thu, 20 Oct 2022 14:34:36 -0700 Subject: [PATCH 0030/1179] Use same minimum speed for lateral planning and controls (#26177) * Use same speed for lag adjustmenet * One is a nicer number * Update ref --- selfdrive/controls/lib/drive_helpers.py | 3 ++- selfdrive/controls/lib/lateral_planner.py | 3 +-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index f81cd0c40c..e74be7199e 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -13,6 +13,7 @@ V_CRUISE_MIN = 8 # kph V_CRUISE_ENABLE_MIN = 40 # kph V_CRUISE_INITIAL = 255 # kph +MIN_SPEED = 1.0 LAT_MPC_N = 16 LON_MPC_N = 32 CONTROL_N = 17 @@ -102,7 +103,7 @@ def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates): psis = [0.0]*CONTROL_N curvatures = [0.0]*CONTROL_N curvature_rates = [0.0]*CONTROL_N - v_ego = max(v_ego, 0.1) + v_ego = max(MIN_SPEED, v_ego) # TODO this needs more thought, use .2s extra for now to estimate other delays delay = CP.steerActuatorDelay + .2 diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index 29137defd3..932ad49535 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -4,7 +4,7 @@ from common.numpy_fast import interp from system.swaglog import cloudlog from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import N as LAT_MPC_N -from selfdrive.controls.lib.drive_helpers import CONTROL_N +from selfdrive.controls.lib.drive_helpers import CONTROL_N, MIN_SPEED from selfdrive.controls.lib.desire_helper import DesireHelper import cereal.messaging as messaging from cereal import log @@ -22,7 +22,6 @@ LATERAL_JERK_COST = 0.05 # TODO this cost should be lowered when low # speed lateral control is stable on all cars STEERING_RATE_COST = 800.0 -MIN_SPEED = 1.5 class LateralPlanner: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 84658effee..230e81d949 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -1f41cd8bbf2431ae89c489a81698120d14a44145 \ No newline at end of file +f5a352666728344ca5065bb44c47c1f5650b4243 From 6b36f73870bebf467971b5e6020e35ddf1a456c9 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 20 Oct 2022 15:13:58 -0700 Subject: [PATCH 0031/1179] desire: give the pulse at t=0 (#26180) input desire at t0 --- selfdrive/modeld/models/driving.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 3316e6d114..8b70589036 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -62,9 +62,9 @@ ModelOutput* model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* wbuf, // Model decides when action is completed // so desire input is just a pulse triggered on rising edge if (desire_in[i] - s->prev_desire[i] > .99) { - s->pulse_desire[DESIRE_LEN*(HISTORY_BUFFER_LEN-1)+i] = desire_in[i]; + s->pulse_desire[DESIRE_LEN*HISTORY_BUFFER_LEN+i] = desire_in[i]; } else { - s->pulse_desire[DESIRE_LEN*(HISTORY_BUFFER_LEN-1)+i] = 0.0; + s->pulse_desire[DESIRE_LEN*HISTORY_BUFFER_LEN+i] = 0.0; } s->prev_desire[i] = desire_in[i]; } From 63035e535bd1c4d269e240a789a2d06a75c45703 Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Thu, 20 Oct 2022 21:50:42 -0500 Subject: [PATCH 0032/1179] Mazda: add missing CX5 2021 FW (#25477) dongle-id: 82c6d952da5e2122 Signed-off-by: Jafar Al-Gharaibeh Signed-off-by: Jafar Al-Gharaibeh Co-authored-by: Shane Smiskol --- selfdrive/car/mazda/values.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 9befad4d0b..921dc7a634 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -98,13 +98,15 @@ FW_VERSIONS = { }, CAR.CX5: { (Ecu.eps, 0x730, None): [ + b'K319-3210X-A-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'KCB8-3210X-B-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KJ01-3210X-G-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KJ01-3210X-J-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'KJ01-3210X-M-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', - b'K319-3210X-A-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'PA53-188K2-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'PAR4-188K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYFA-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYFC-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PYFD-188K2-J\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', @@ -146,6 +148,7 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'PA66-21PS1-A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'PA66-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PX39-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PX39-21PS1-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PX68-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From c35e2b8e305b2648ce392ffdefd5d90b39ce353e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 20 Oct 2022 19:55:04 -0700 Subject: [PATCH 0033/1179] Hyundai: common CAN-FD brake pressed signal (#26170) * Hyundai: common CAN-FD brake pressed signal * new name * bump panda * bump opendbc to master * bump opendbc * bump panda * bump panda Co-authored-by: Shane Smiskol --- opendbc | 2 +- panda | 2 +- selfdrive/car/hyundai/carstate.py | 8 ++++---- selfdrive/debug/can_print_changes.py | 8 ++++++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/opendbc b/opendbc index 8f245e6ef5..7bd94e3ff4 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 8f245e6ef5e25814d8e6e1f096221f6dfeefe86b +Subproject commit 7bd94e3ff4a2890eb69118f0dfadb64f9d32d618 diff --git a/panda b/panda index 54f9390ff5..fcb1a5a8e2 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 54f9390ff51b4fb0c2b3a81b9cde8727acdd1977 +Subproject commit fcb1a5a8e233a8b520c42c58cf8bfaa82753ac5a diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 60d434a603..e27432e23b 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -159,7 +159,7 @@ class CarState(CarStateBase): elif self.CP.carFingerprint in HYBRID_CAR: ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023. ret.gasPressed = ret.gas > 1e-5 - ret.brakePressed = cp.vl["BRAKE"]["BRAKE_PRESSED"] == 1 + ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1 ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1 ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0 @@ -415,7 +415,6 @@ class CarState(CarStateBase): ("WHEEL_SPEED_4", "WHEEL_SPEEDS"), ("GEAR", "GEAR_SHIFTER"), - ("BRAKE_PRESSED", "BRAKE"), ("STEERING_RATE", "STEERING_SENSORS"), ("STEERING_ANGLE", "STEERING_SENSORS"), @@ -423,7 +422,8 @@ class CarState(CarStateBase): ("STEERING_OUT_TORQUE", "MDPS"), ("LKA_FAULT", "MDPS"), - ("CRUISE_ACTIVE", "SCC1"), + ("DriverBraking", "TCS"), + ("COUNTER", cruise_btn_msg), ("CRUISE_BUTTONS", cruise_btn_msg), ("ADAPTIVE_CRUISE_MAIN_BTN", cruise_btn_msg), @@ -443,7 +443,7 @@ class CarState(CarStateBase): ("BRAKE", 100), ("STEERING_SENSORS", 100), ("MDPS", 100), - ("SCC1", 50), + ("TCS", 50), (cruise_btn_msg, 50), ("CLUSTER_INFO", 4), ("BLINKERS", 4), diff --git a/selfdrive/debug/can_print_changes.py b/selfdrive/debug/can_print_changes.py index b883fbc23f..ff98c20e60 100755 --- a/selfdrive/debug/can_print_changes.py +++ b/selfdrive/debug/can_print_changes.py @@ -54,6 +54,7 @@ def can_printer(bus=0, init_msgs=None, new_msgs=None, table=False): update(new_msgs, bus, dat, low_to_high, high_to_low) else: # Live mode + print(f"Waiting for messages on bus {bus}") try: while 1: can_recv = messaging.drain_sock(logcan) @@ -89,14 +90,17 @@ if __name__ == "__main__": formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--bus", type=int, help="CAN bus to print out", default=0) parser.add_argument("--table", action="store_true", help="Print a cabana-like table") - parser.add_argument("init", type=str, nargs='?', help="Route or segment to initialize with") + parser.add_argument("init", type=str, nargs='?', help="Route or segment to initialize with. Use empty quotes to compare against all zeros.") parser.add_argument("comp", type=str, nargs='?', help="Route or segment to compare against init") args = parser.parse_args() init_lr, new_lr = None, None if args.init: - init_lr = logreader_from_route_or_segment(args.init) + if args.init == '': + init_lr = [] + else: + init_lr = logreader_from_route_or_segment(args.init) if args.comp: new_lr = logreader_from_route_or_segment(args.comp) From d828b69e140f5dda2450d40bafe4c018b01a2577 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 20 Oct 2022 20:10:09 -0700 Subject: [PATCH 0034/1179] Hyundai: add corner radar FW query (#26143) * Hyundai: add corner radar FW query * Add to both, and fix when we look at data * add TODO * comments Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index d5b8427f66..c11bf67d15 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -292,6 +292,8 @@ HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x4 FW_QUERY_CONFIG = FwQueryConfig( requests=[ + # TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD + # CAN queries (OBD-II port) Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], @@ -302,22 +304,23 @@ FW_QUERY_CONFIG = FwQueryConfig( [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar], ), - # CAN-FD queries + # CAN-FD queries (camera) Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar], + whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar], bus=4, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera, Ecu.adas], + whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar], bus=5, ), ], extra_ecus=[ - (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms + (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms + (Ecu.cornerRadar, 0x7b7, None), ], ) From 188c2c1c5e1c06d68ae957ab16bcb77e29052f4b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 20 Oct 2022 20:58:58 -0700 Subject: [PATCH 0035/1179] model replay speedup (#26181) * model replay speedup * less frames too Co-authored-by: Comma Device --- selfdrive/test/process_replay/model_replay.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index ecfacbf5d2..a63ec6489b 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -22,7 +22,7 @@ from tools.lib.logreader import LogReader TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36" SEGMENT = 0 -MAX_FRAMES = 100 if PC else 1300 +MAX_FRAMES = 100 if PC else 600 SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0")) @@ -149,9 +149,9 @@ if __name__ == "__main__": # load logs lr = list(LogReader(get_url(TEST_ROUTE, SEGMENT))) frs = { - 'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="fcamera")), - 'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="dcamera")), - 'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera")) + 'roadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="fcamera"), readahead=True), + 'driverCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="dcamera"), readahead=True), + 'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True) } # run replay From 0ac12b82c770504199f0f9ecad8ab9c6a9b3a470 Mon Sep 17 00:00:00 2001 From: Bruce Wayne Date: Fri, 21 Oct 2022 00:24:11 -0700 Subject: [PATCH 0036/1179] d8501d20-bb59-4193-aa82-82b2737dedd6/449 f78009d1-2184-4136-9fbc-1c5de55d460d/700 --- selfdrive/modeld/models/supercombo.onnx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 59b8883d2a..21602ea70a 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:022a830c39267f378f45204682060c93e3aa304bbd8cfa6b2dfe4fa8f419102d -size 56972617 +oid sha256:9c119aa811a929b3a442dbe8e462a9d88e8bfb9f5809a4e737687fb7380d7e05 +size 45922882 From 3a50d5fd852b6d8938fd7974c6966a649cba7ca5 Mon Sep 17 00:00:00 2001 From: Bruce Wayne Date: Fri, 21 Oct 2022 00:32:34 -0700 Subject: [PATCH 0037/1179] Revert "d8501d20-bb59-4193-aa82-82b2737dedd6/449 f78009d1-2184-4136-9fbc-1c5de55d460d/700" This reverts commit 0ac12b82c770504199f0f9ecad8ab9c6a9b3a470. --- selfdrive/modeld/models/supercombo.onnx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 21602ea70a..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:9c119aa811a929b3a442dbe8e462a9d88e8bfb9f5809a4e737687fb7380d7e05 -size 45922882 +oid sha256:022a830c39267f378f45204682060c93e3aa304bbd8cfa6b2dfe4fa8f419102d +size 56972617 From 3a70253567cc908204b73cf5df53369b19506b7b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 21 Oct 2022 01:14:15 -0700 Subject: [PATCH 0038/1179] GM: inactive gas/regen safety (#26184) * Add INACTIVE_REGEN * bump * Update selfdrive/car/gm/carcontroller.py --- panda | 2 +- selfdrive/car/gm/carcontroller.py | 4 ++-- selfdrive/car/gm/values.py | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/panda b/panda index fcb1a5a8e2..d51dd496cb 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit fcb1a5a8e233a8b520c42c58cf8bfaa82753ac5a +Subproject commit d51dd496cbdc8665928af40247582bc62dba1f2a diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index dbad355c46..f28a0f7b59 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -67,8 +67,8 @@ class CarController: # Gas/regen, brakes, and UI commands - all at 25Hz if self.frame % 4 == 0: if not CC.longActive: - # Stock ECU sends max regen when not enabled - self.apply_gas = self.params.MAX_ACC_REGEN + # ASCM sends max regen when not enabled + self.apply_gas = self.params.INACTIVE_REGEN self.apply_brake = 0 else: if self.CP.carFingerprint in EV_CAR: diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 999dabfee3..f8f9e7f043 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -30,6 +30,7 @@ class CarControllerParams: ZERO_GAS = 2048 # Coasting MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen + INACTIVE_REGEN = 1404 # Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we # perform the closed loop control, and might need some From d25ab3e3663f1e8a7b08348692d6555fac84e73b Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Fri, 21 Oct 2022 01:29:58 -0700 Subject: [PATCH 0039/1179] Wide transform model (#26165) * d8501d20-bb59-4193-aa82-82b2737dedd6/449 f78009d1-2184-4136-9fbc-1c5de55d460d/700 * Change model outs * Add cereal * Publish transform * d8501d20-bb59-4193-aa82-82b2737dedd6/449 f78009d1-2184-4136-9fbc-1c5de55d460d/700 * Bump cereal to master * Bump cereal to master * Update model ref --- cereal | 2 +- selfdrive/modeld/models/driving.cc | 5 +++ selfdrive/modeld/models/driving.h | 41 ++++--------------- selfdrive/modeld/models/supercombo.onnx | 4 +- .../process_replay/model_replay_ref_commit | 2 +- 5 files changed, 17 insertions(+), 37 deletions(-) diff --git a/cereal b/cereal index 1e3dd70a39..38133307b2 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 1e3dd70a391bc1bbe437d3eea8be30947f929a75 +Subproject commit 38133307b2e6036e76684b39878e79212e545e06 diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 8b70589036..cc4a83de62 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -363,14 +363,19 @@ void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_droppe MessageBuilder msg; const auto &v_mean = net_outputs.pose.velocity_mean; const auto &r_mean = net_outputs.pose.rotation_mean; + const auto &t_mean = net_outputs.wide_from_device_euler.mean; const auto &v_std = net_outputs.pose.velocity_std; const auto &r_std = net_outputs.pose.rotation_std; + const auto &t_std = net_outputs.wide_from_device_euler.std; auto posenetd = msg.initEvent(valid && (vipc_dropped_frames < 1)).initCameraOdometry(); posenetd.setTrans({v_mean.x, v_mean.y, v_mean.z}); posenetd.setRot({r_mean.x, r_mean.y, r_mean.z}); + posenetd.setWideFromDeviceEuler({t_mean.x, t_mean.y, t_mean.z}); posenetd.setTransStd({exp(v_std.x), exp(v_std.y), exp(v_std.z)}); posenetd.setRotStd({exp(r_std.x), exp(r_std.y), exp(r_std.z)}); + posenetd.setWideFromDeviceEulerStd({exp(t_std.x), exp(t_std.y), exp(t_std.z)}); + posenetd.setTimestampEof(timestamp_eof); posenetd.setFrameId(vipc_frame_id); diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index 8bb84d0245..64218467df 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -28,7 +28,6 @@ constexpr int BLINKER_LEN = 6; constexpr int META_STRIDE = 7; constexpr int PLAN_MHP_N = 5; -constexpr int STOP_LINE_MHP_N = 3; constexpr int LEAD_MHP_N = 2; constexpr int LEAD_TRAJ_LEN = 6; @@ -151,36 +150,6 @@ struct ModelOutputLeads { }; static_assert(sizeof(ModelOutputLeads) == (sizeof(ModelOutputLeadPrediction)*LEAD_MHP_N) + (sizeof(float)*LEAD_MHP_SELECTION)); -struct ModelOutputStopLineElement { - ModelOutputXYZ position; - ModelOutputXYZ rotation; - float speed; - float time; -}; -static_assert(sizeof(ModelOutputStopLineElement) == (sizeof(ModelOutputXYZ)*2 + sizeof(float)*2)); - -struct ModelOutputStopLinePrediction { - ModelOutputStopLineElement mean; - ModelOutputStopLineElement std; - float prob; -}; -static_assert(sizeof(ModelOutputStopLinePrediction) == (sizeof(ModelOutputStopLineElement)*2 + sizeof(float))); - -struct ModelOutputStopLines { - std::array prediction; - float prob; - - constexpr const ModelOutputStopLinePrediction &get_best_prediction(int t_idx) const { - int max_idx = 0; - for (int i = 1; i < prediction.size(); i++) { - if (prediction[i].prob > prediction[max_idx].prob) { - max_idx = i; - } - } - return prediction[max_idx]; - } -}; -static_assert(sizeof(ModelOutputStopLines) == (sizeof(ModelOutputStopLinePrediction)*STOP_LINE_MHP_N) + sizeof(float)); struct ModelOutputPose { ModelOutputXYZ velocity_mean; @@ -190,6 +159,12 @@ struct ModelOutputPose { }; static_assert(sizeof(ModelOutputPose) == sizeof(ModelOutputXYZ)*4); +struct ModelOutputWideFromDeviceEuler { + ModelOutputXYZ mean; + ModelOutputXYZ std; +}; +static_assert(sizeof(ModelOutputWideFromDeviceEuler) == sizeof(ModelOutputXYZ)*2); + struct ModelOutputDisengageProb { float gas_disengage; float brake_disengage; @@ -245,9 +220,9 @@ struct ModelOutput { const ModelOutputLaneLines lane_lines; const ModelOutputRoadEdges road_edges; const ModelOutputLeads leads; - const ModelOutputStopLines stop_lines; const ModelOutputMeta meta; const ModelOutputPose pose; + const ModelOutputWideFromDeviceEuler wide_from_device_euler; }; constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float); @@ -257,7 +232,7 @@ constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float); #else constexpr int TEMPORAL_SIZE = 0; #endif -constexpr int NET_OUTPUT_SIZE = OUTPUT_SIZE + FEATURE_LEN; +constexpr int NET_OUTPUT_SIZE = OUTPUT_SIZE + FEATURE_LEN + 2; // TODO: convert remaining arrays to std::array and update model runners struct ModelState { diff --git a/selfdrive/modeld/models/supercombo.onnx b/selfdrive/modeld/models/supercombo.onnx index 59b8883d2a..21602ea70a 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:022a830c39267f378f45204682060c93e3aa304bbd8cfa6b2dfe4fa8f419102d -size 56972617 +oid sha256:9c119aa811a929b3a442dbe8e462a9d88e8bfb9f5809a4e737687fb7380d7e05 +size 45922882 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 5bb045ec29..b5fd11fee8 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -865885fc49b2766326568e5cc7ec06be8a3f6fad +46cb9c522e942d8b25deac90ffdee89efff60ce9 From 931cecf41a5546c0cfd96138f954fa20b8e75d1d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 23:00:49 +0800 Subject: [PATCH 0040/1179] Canaba: remove unused metatype in canmessage (#26190) remove metatype --- tools/cabana/canmessages.cc | 2 -- tools/cabana/canmessages.h | 1 - 2 files changed, 3 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 3900ad93f7..212a0d9020 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -5,8 +5,6 @@ #include "tools/cabana/dbcmanager.h" -Q_DECLARE_METATYPE(std::vector); - CANMessages *can = nullptr; CANMessages::CANMessages(QObject *parent) : QObject(parent) { diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 84f4e06dfb..7a641a0e32 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -96,4 +96,3 @@ inline QColor hoverColor(const QColor &color) { // A global pointer referring to the unique CANMessages object extern CANMessages *can; - From d0c0972ba44e72f4875ed4f3c6fc3b25fd862b99 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 23:01:26 +0800 Subject: [PATCH 0041/1179] Cabana: show frequency column in message table (#26189) * show frequency column in message table * add comments --- tools/cabana/canmessages.cc | 12 ++++++++++++ tools/cabana/canmessages.h | 11 ++++++++--- tools/cabana/messageswidget.cc | 22 +++++++++++++++++----- tools/cabana/messageswidget.h | 2 +- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 212a0d9020..4cc91031ad 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -97,6 +97,12 @@ bool CANMessages::eventFilter(const Event *event) { } current_sec = (event->mono_time - replay->routeStartTime()) / (double)1e9; + if (counters_begin_sec > current_sec) { + // clear counters + counters.clear(); + counters_begin_sec = current_sec; + } + auto can_events = event->event.getCan(); for (const auto &c : can_events) { QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); @@ -108,6 +114,12 @@ bool CANMessages::eventFilter(const Event *event) { data.ts = current_sec; data.bus_time = c.getBusTime(); data.dat.append((char *)c.getDat().begin(), c.getDat().size()); + + auto &count = counters[id]; + data.count = ++count; + if (double delta = (current_sec - counters_begin_sec); delta > 0) { + data.freq = count / delta; + } } if (current_sec < prev_update_sec || (current_sec - prev_update_sec) > 1.0 / settings.fps) { diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 7a641a0e32..d1bb1b73b6 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -13,8 +13,10 @@ #include "tools/replay/replay.h" struct CanData { - double ts; - uint16_t bus_time; + double ts = 0.; + uint32_t count = 0; + uint32_t freq = 0; + uint16_t bus_time = 0; QByteArray dat; }; @@ -57,7 +59,6 @@ signals: public: QMap> can_msgs; std::unique_ptr>> received_msgs = nullptr; - QHash counters; protected: void process(QHash> *); @@ -66,6 +67,7 @@ protected: std::atomic current_sec = 0.; std::atomic seeking = false; + double begin_sec = 0; double end_sec = 0; double event_begin_sec = 0; @@ -73,6 +75,9 @@ protected: bool is_zoomed = false; QString routeName; Replay *replay = nullptr; + + double counters_begin_sec = std::numeric_limits::max(); + QHash counters; }; inline QString toHex(const QByteArray &dat) { diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 46776a4f5d..c289f54fc4 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -112,23 +112,25 @@ void MessagesWidget::loadDBCFromFingerprint() { 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]; + return (QString[]){"Name", "ID", "Freq", "Count", "Bytes"}[section]; return {}; } QVariant MessageListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { const auto &m = msgs[index.row()]; + auto &can_data = can->lastMessage(m->id); switch (index.column()) { case 0: return m->name; case 1: return m->id; - case 2: return can->counters[m->id]; - case 3: return toHex(can->lastMessage(m->id).dat); + case 2: return can_data.freq; + case 3: return can_data.count; + case 4: return toHex(can_data.dat); } } else if (role == Qt::UserRole) { return msgs[index.row()]->id; } else if (role == Qt::FontRole) { - if (index.column() == 3) { + if (index.column() == columnCount() - 1) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); } } @@ -164,8 +166,18 @@ bool MessageListModel::updateMessages(bool sort) { return sort_order == Qt::AscendingOrder ? l->id < r->id : l->id > r->id; }); } else if (sort_column == 2) { + // sort by frequency std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - uint32_t lcount = can->counters[l->id], rcount = can->counters[r->id]; + uint32_t lfreq = can->lastMessage(l->id).freq; + uint32_t rfreq = can->lastMessage(r->id).freq; + bool ret = lfreq < rfreq || (lfreq == rfreq && l->id < r->id); + return sort_order == Qt::AscendingOrder ? ret : !ret; + }); + } else if (sort_column == 3) { + // sort by count + std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { + uint32_t lcount = can->lastMessage(l->id).count; + uint32_t rcount = can->lastMessage(r->id).count; bool ret = lcount < rcount || (lcount == rcount && l->id < r->id); return sort_order == Qt::AscendingOrder ? ret : !ret; }); diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 7b6c8e53cf..fcd4939dac 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -23,7 +23,7 @@ Q_OBJECT public: MessageListModel(QObject *parent) : QAbstractTableModel(parent) {} QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 4; } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 5; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; From ae1d15094169b5cad2921e5320bc53ce3bcb6b96 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 23:01:55 +0800 Subject: [PATCH 0042/1179] Cabana: redirect qt logs to status bar (#26187) Redirect qt logs to status bar --- tools/cabana/mainwin.cc | 8 ++++++++ tools/cabana/mainwin.h | 1 + 2 files changed, 9 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 2478155fcf..60a1f7a3a3 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -8,7 +8,15 @@ #include "tools/replay/util.h" +static MainWindow *main_win = nullptr; +void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { + main_win->showStatusMessage(msg); +} + MainWindow::MainWindow() : QWidget() { + main_win = this; + qInstallMessageHandler(qLogMessageHandler); + QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(11, 11, 11, 5); main_layout->setSpacing(0); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 56d2da145b..63f704dcc8 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -14,6 +14,7 @@ class MainWindow : public QWidget { public: MainWindow(); void dockCharts(bool dock); + void showStatusMessage(const QString &msg, int timeout = 0) { status_bar->showMessage(msg, timeout); } signals: void logMessageFromReplay(const QString &msg, int timeout); From 8697e928fc23dc256c746c1561095e36d86cb964 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 21 Oct 2022 23:31:28 +0800 Subject: [PATCH 0043/1179] Cabana: Fix unable to display charts for same signals from different buses. (#26191) keep charts in list instead of hash --- tools/cabana/chartswidget.cc | 48 ++++++++++++++++++++++-------------- tools/cabana/chartswidget.h | 8 +++--- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 811eae68cb..f0bef36f4a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -55,11 +55,13 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(charts_scroll); - QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); - QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartsWidget::removeChart); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { removeAll(nullptr); }); + QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartsWidget::removeAll); QObject::connect(dbc(), &DBCManager::signalUpdated, [this](const Signal *sig) { - if (auto it = charts.find(sig); it != charts.end()) { - it.value()->chart_view->updateSeries(); + for (auto chart : charts) { + if (chart->signal == sig) { + chart->chart_view->updateSeries(); + } } }); QObject::connect(dbc(), &DBCManager::msgUpdated, [this](const QString &id) { @@ -71,7 +73,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { 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); + QObject::connect(remove_all_btn, &QPushButton::clicked, [this]() { removeAll(); }); QObject::connect(dock_btn, &QPushButton::clicked, [this]() { emit dock(!docking); docking = !docking; @@ -102,28 +104,38 @@ void ChartsWidget::updateTitleBar() { } void ChartsWidget::addChart(const QString &id, const Signal *sig) { - if (!charts.contains(sig)) { + auto it = std::find_if(charts.begin(), charts.end(), [=](auto c) { return c->id == id && c->signal == sig; }); + if (it == charts.end()) { auto chart = new ChartWidget(id, sig, this); - QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(sig); }); + QObject::connect(chart, &ChartWidget::remove, this, &ChartsWidget::removeChart); charts_layout->insertWidget(0, chart); - charts.insert(sig, chart); + charts.push_back(chart); } updateTitleBar(); } -void ChartsWidget::removeChart(const Signal *sig) { - auto it = charts.find(sig); - if (it != charts.end()) { - it.value()->deleteLater(); - charts.remove(sig); +void ChartsWidget::removeChart(const QString &msg_id, const Signal *sig) { + QMutableListIterator it(charts); + while (it.hasNext()) { + auto c = it.next(); + if (c->id == msg_id && c->signal == sig) { + c->deleteLater(); + it.remove(); + break; + } } updateTitleBar(); } -void ChartsWidget::removeAll() { - for (auto chart : charts) - chart->deleteLater(); - charts.clear(); +void ChartsWidget::removeAll(const Signal *sig) { + QMutableListIterator it(charts); + while (it.hasNext()) { + auto c = it.next(); + if (sig == nullptr || c->signal == sig) { + c->deleteLater(); + it.remove(); + } + } updateTitleBar(); } @@ -153,7 +165,7 @@ ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) QPushButton *remove_btn = new QPushButton("✖", this); remove_btn->setFixedSize(30, 30); remove_btn->setToolTip(tr("Remove chart")); - QObject::connect(remove_btn, &QPushButton::clicked, this, &ChartWidget::remove); + QObject::connect(remove_btn, &QPushButton::clicked, [=]() { emit remove(id, sig); }); header_layout->addWidget(remove_btn); main_layout->addWidget(header); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index fe2e14db9f..5adbdfcd04 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -50,7 +50,7 @@ public: void setHeight(int height); signals: - void remove(); + void remove(const QString &msg_id, const Signal *sig); public: QString id; @@ -65,7 +65,7 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); void addChart(const QString &id, const Signal *sig); - void removeChart(const Signal *sig); + void removeChart(const QString &id, const Signal *sig); signals: void dock(bool floating); @@ -73,7 +73,7 @@ signals: private: void updateState(); void updateTitleBar(); - void removeAll(); + void removeAll(const Signal *sig = nullptr); bool eventFilter(QObject *obj, QEvent *event); QWidget *title_bar; @@ -84,5 +84,5 @@ private: QPushButton *reset_zoom_btn; QPushButton *remove_all_btn; QVBoxLayout *charts_layout; - QHash charts; + QList charts; }; From 22c5be5ec12f1e94eb56092d123257ca46132124 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 22 Oct 2022 01:33:00 +0800 Subject: [PATCH 0044/1179] Cabana: fix segment fault in QApplication::notify(QObject*, QEvent*) () (#26194) fix segment fault in QApplication::notify(QObject*, QEvent*) () --- tools/cabana/detailwidget.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index c7bfdee164..039a7c4e55 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -5,6 +5,7 @@ #include #include +#include "selfdrive/ui/qt/util.h" #include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" @@ -106,7 +107,7 @@ void DetailWidget::dbcMsgChanged() { if (msg_id.isEmpty()) return; warning_widget->hide(); - qDeleteAll(signals_container->findChildren()); + clearLayout(signals_container->layout()); QString msg_name = tr("untitled"); if (auto msg = dbc()->msg(msg_id)) { for (int i = 0; i < msg->sigs.size(); ++i) { From d75cbf2338f098a9c2143c94a9db8ddce68699b4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 22 Oct 2022 01:33:13 +0800 Subject: [PATCH 0045/1179] Cabana: fix segfault on exit (#26193) fix segfault on exit --- tools/cabana/mainwin.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 60a1f7a3a3..d0e171c86e 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -10,7 +10,7 @@ static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - main_win->showStatusMessage(msg); + if (main_win) main_win->showStatusMessage(msg); } MainWindow::MainWindow() : QWidget() { @@ -118,6 +118,7 @@ void MainWindow::dockCharts(bool dock) { } void MainWindow::closeEvent(QCloseEvent *event) { + main_win = nullptr; if (floating_window) floating_window->deleteLater(); QWidget::closeEvent(event); From 0edbbdeaf9e5c8ad23b73089d2871f88ff29509e Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Fri, 21 Oct 2022 11:20:52 -0700 Subject: [PATCH 0046/1179] Modeld: Add comment (#26188) Rename and add comment --- selfdrive/modeld/models/driving.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index 64218467df..dd1609b1d1 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -33,6 +33,8 @@ constexpr int LEAD_MHP_N = 2; constexpr int LEAD_TRAJ_LEN = 6; constexpr int LEAD_PRED_DIM = 4; constexpr int LEAD_MHP_SELECTION = 3; +// Padding to get output shape as multiple of 4 +constexpr int PAD_SIZE = 2; struct ModelOutputXYZ { float x; @@ -232,7 +234,7 @@ constexpr int OUTPUT_SIZE = sizeof(ModelOutput) / sizeof(float); #else constexpr int TEMPORAL_SIZE = 0; #endif -constexpr int NET_OUTPUT_SIZE = OUTPUT_SIZE + FEATURE_LEN + 2; +constexpr int NET_OUTPUT_SIZE = OUTPUT_SIZE + FEATURE_LEN + PAD_SIZE; // TODO: convert remaining arrays to std::array and update model runners struct ModelState { From 6e257300eac6d5c26a59ef7aaa8976791a7682f5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 21 Oct 2022 12:51:41 -0700 Subject: [PATCH 0047/1179] Kia: add missing Stinger transmission FW (#26198) Add missing transmission --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index c11bf67d15..1eed03923c 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -786,6 +786,7 @@ FW_VERSIONS = { 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', + b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', ], }, CAR.PALISADE: { From 68e7f42d68232efb89a5dc882fafa71daab72a28 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Fri, 21 Oct 2022 13:11:50 -0700 Subject: [PATCH 0048/1179] use upstream tinygrad (#26178) * use upstream tinygrad * add networkx to pipfile * Revert "add networkx to pipfile" This reverts commit 6cfa164378fa072b325a27040f0388730771437c. * dont need networkx and update tinygrad * submodule sync * add new thneed file * fix release files Co-authored-by: Adeeb Shihadeh --- .gitmodules | 2 +- release/files_common | 1 + selfdrive/modeld/SConscript | 1 + selfdrive/test/setup_device_ci.sh | 1 + tinygrad_repo | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 544c95c943..26f93ef164 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,4 +18,4 @@ url = ../../commaai/body.git [submodule "tinygrad"] path = tinygrad_repo - url = ../../commaai/tinygrad.git + url = https://github.com/geohot/tinygrad.git diff --git a/release/files_common b/release/files_common index 07ffaf8501..e3c417040c 100644 --- a/release/files_common +++ b/release/files_common @@ -565,6 +565,7 @@ opendbc/tesla_powertrain.dbc tinygrad_repo/openpilot/compile.py tinygrad_repo/accel/opencl/* tinygrad_repo/extra/onnx.py +tinygrad_repo/extra/thneed.py tinygrad_repo/extra/utils.py tinygrad_repo/tinygrad/llops/ops_gpu.py tinygrad_repo/tinygrad/llops/ops_opencl.py diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 5c02e2b15f..f1a8d71881 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -83,6 +83,7 @@ if use_thneed and arch == "larch64" or GetOption('pc_thneed'): "#tinygrad_repo/accel/opencl/ops_opencl.py", "#tinygrad_repo/accel/opencl/preprocessing.py", "#tinygrad_repo/extra/onnx.py", + "#tinygrad_repo/extra/thneed.py", "#tinygrad_repo/extra/utils.py", "#tinygrad_repo/tinygrad/llops/ops_gpu.py", "#tinygrad_repo/tinygrad/llops/ops_opencl.py", diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh index a9c6527970..02c7d76637 100755 --- a/selfdrive/test/setup_device_ci.sh +++ b/selfdrive/test/setup_device_ci.sh @@ -60,6 +60,7 @@ find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm - git reset --hard $GIT_COMMIT git checkout $GIT_COMMIT git clean -xdff +git submodule sync git submodule update --init --recursive git submodule foreach --recursive "git reset --hard && git clean -xdff" diff --git a/tinygrad_repo b/tinygrad_repo index 870ea766ee..8e22d5ee67 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit 870ea766eec7a38d7d590c81436f15271ba2667e +Subproject commit 8e22d5ee675277181e1eff644dde9e844fc40fce From a98d105cb95a445f5ec69e783585c56604b09449 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Fri, 21 Oct 2022 16:23:56 -0700 Subject: [PATCH 0049/1179] Pipenv -> poetry (#24858) * Try poetry * Remove casadi for now * Update docker * Copy pipfiles * add casadi back * Too many slashes * New poetry api * Install system * Try again * No more pipenv * new dependencies * updates * poetry 1.2.1, install dev dependencies * keep install pipenv for xx for now? * add pre-commit checks for poetry * poetry lock is too slow * update pip * migrate to poetry groups * update lockfile * don't need to specify dev group unless it is made optional * always install poetry * set POETRY_VIRTUALENVS_CREATE instead, and use pipenv for xx * use env for docs docker image * alphabetical * poetry 1.2.2 * add dev dependencies for typing added in 4e310b80 * remove constraint * fix PIPENV_SYSTEM * remove constraint * don't need this here * bump * bump pipenv adds support for installing local pyprojects (can add openpilot as dependency of xx) * README improvements * probably not necessary * bump pip * maybe not necessary? * revert * don't install openpilot itself into the virtual env * remove PySide2 and shiboken2 reverts c6b749fb96b3b6332fd850e733140357f84d53a4 * remove Pipenv, add xx dependencies, sync system python * add pipenv as xx dep * semver package constraints, use old lockfile versions * fix casadi * remove whitespace Co-authored-by: Adeeb Shihadeh * disable poetry cache * cleanup * prefer config file Co-authored-by: Cameron Clough Co-authored-by: Adeeb Shihadeh --- .github/workflows/selfdrive_tests.yaml | 6 +- .gitignore | 2 + .pre-commit-config.yaml | 4 + Dockerfile.openpilot_base | 6 +- Pipfile | 100 - Pipfile.lock | 3072 --------- docs/docker/Dockerfile | 7 +- poetry.lock | 7963 ++++++++++++++++++++++++ pyproject.toml | 176 + tools/README.md | 9 +- tools/mac_setup.sh | 2 +- update_requirements.sh | 30 +- 12 files changed, 8173 insertions(+), 3204 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 20bf8c3d8e..0693a66164 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -106,7 +106,7 @@ jobs: # /usr/local/Cellar # ~/github_brew_cache_entries.txt # /tmp/scons_cache - # key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'Pipfile*') }} + # key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'poetry.lock') }} # restore-keys: macos- # - name: Brew link restored dependencies # run: | @@ -122,11 +122,11 @@ jobs: # - name: Build openpilot # run: | # source tools/openpilot_env.sh - # pipenv run selfdrive/manager/build.py + # poetry run selfdrive/manager/build.py # # # cleanup scons cache # rm -rf /tmp/scons_cache/ - # pipenv run scons -j$(nproc) --cache-populate + # poetry run scons -j$(nproc) --cache-populate # - name: Remove pre-existing Homebrew packages for caching # if: steps.dependency-cache.outputs.cache-hit != 'true' # run: | diff --git a/.gitignore b/.gitignore index 062358ef24..31cef94222 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,5 @@ selfdrive/modeld/models/*.thneed build/ !**/.gitkeep + +poetry.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85c24b911b..91b9c61628 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -78,3 +78,7 @@ repos: entry: selfdrive/ui/tests/test_translations.py language: script pass_filenames: false +- repo: https://github.com/python-poetry/poetry + rev: '1.2.2' + hooks: + - id: poetry-check diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base index 0de3008baf..4cd82259e2 100644 --- a/Dockerfile.openpilot_base +++ b/Dockerfile.openpilot_base @@ -12,19 +12,19 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 -ENV PIPENV_SYSTEM=1 +ENV POETRY_VIRTUALENVS_CREATE=false ENV PYENV_VERSION=3.8.10 ENV PYENV_ROOT="/root/.pyenv" ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" -COPY Pipfile Pipfile.lock .python-version update_requirements.sh /tmp/ +COPY pyproject.toml poetry.lock .python-version update_requirements.sh /tmp/ COPY tools/ubuntu_setup.sh /tmp/tools/ RUN cd /tmp && \ tools/ubuntu_setup.sh && \ rm -rf /var/lib/apt/lists/* && \ rm -rf /tmp/* && \ rm -rf /root/.cache && \ - pip uninstall -y pipenv && \ + pip uninstall -y poetry && \ # remove unused architectures from gcc for panda cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \ rm -rf arm/ && \ diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 778cf8c33c..0000000000 --- a/Pipfile +++ /dev/null @@ -1,100 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -av = "*" -azure-storage-blob = "~=2.1" -control = "*" -coverage = "*" -dictdiffer = "*" -fastcluster = "*" -hexdump = "*" -hypothesis = "==6.46.7" -inputs = "*" -lru-dict = "*" -markdown-it-py = "*" -matplotlib = "*" -mypy = "*" -myst-parser = "*" -natsort = "*" -numpy = "*" -opencv-python-headless = "*" -parameterized = "*" -paramiko = "*" -pprofile = "*" -pre-commit = "*" -pycurl = "*" -pygame = "*" -pyprof2calltree = "*" -pytest = "*" -pytest-xdist = "*" -reverse_geocoder = "*" -scipy = "*" -sphinx = "*" -sphinx-sitemap = "*" -sphinx-rtd-theme = "*" -breathe = "*" -subprocess32 = "*" -tenacity = "*" -mpld3 = "*" -carla = {version = "==0.9.13", markers="platform_system != 'Darwin'"} -ft4222 = "*" -pandas = "*" -tabulate = "*" -types-pyyaml = "*" -lxml = "*" -types-atomicwrites = "*" -types-pycurl = "*" -types-requests = "*" -types-certifi = "*" - -[packages] -atomicwrites = "*" -casadi = {version = "*", markers="platform_system != 'Darwin'"} -cffi = "*" -crcmod = "*" -cryptography = "*" -Cython = "*" -flake8 = "*" -Flask = "*" -future-fstrings = "*" # for acados -gunicorn = "*" -hexdump = "*" -Jinja2 = "*" -json-rpc = "*" -libusb1 = "*" -nose = "*" -numpy = "*" -protobuf = "==3.20.1" -onnx = "*" -onnxruntime-gpu = {version = "*", markers="platform_system != 'Darwin'"} -pillow = "*" -psutil = "*" -pycapnp = "==1.1.0" -pycryptodome = "*" -PyJWT = "*" -pylint = "*" -pyopencl = "*" -pyserial = "*" -python-dateutil = "*" -PyYAML = "*" -pyzmq = "*" -requests = "*" -scons = "*" -sentry-sdk = "*" -setproctitle = "*" -six = "*" -smbus2 = "*" -sympy = "!=1.6.1" -timezonefinder = "*" -tqdm = "*" -urllib3 = "*" -utm = "*" -websocket_client = "*" -hatanaka = "==2.4" -PySide2 = "*" - -[requires] -python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index d033a517cb..0000000000 --- a/Pipfile.lock +++ /dev/null @@ -1,3072 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "c406463198490fc40dcac3dd438c77cf36f6fe681793072e96fdecf089ff7639" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.8" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "astroid": { - "hashes": [ - "sha256:81f870105d892e73bf535da77a8261aa5bde838fa4ed12bb2f435291a098c581", - "sha256:997e0c735df60d4a4caff27080a3afc51f9bdd693d3572a4a0b7090b645c36c5" - ], - "markers": "python_full_version >= '3.7.2'", - "version": "==2.12.10" - }, - "atomicwrites": { - "hashes": [ - "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11" - ], - "index": "pypi", - "version": "==1.4.1" - }, - "casadi": { - "hashes": [ - "sha256:09e103bb597d46aa338fc57bc49270068a1f07be35f9494c9f796dea4b801aeb", - "sha256:13277151efc76b221de8ca6b5ab7b8bbdd2b0e139f282866840adf88dfe53bc9", - "sha256:1c451a07b2440c00d552e040b6285b6e79b677d2978212368b28b86f5d267669", - "sha256:2322748a8d5e88750fd2fc0abcdc56cfbad1a8cd538fe0e7d7b6d8ce0cb3fa62", - "sha256:24fbac649ee26572884029dcd0e108b4a2412cad003a84ed915c4e44a94ecae7", - "sha256:253569c85f881a6a8fe5e1c0758858edb1ecb4c3d8bce4aee4b52e5dc59fc091", - "sha256:292e2768280393bad406256e0ef9c30ddcd4867dbd42148b36f9d92a32d9e199", - "sha256:353a79e50aa84ac5e0d9f04bc3b2d78a2cc8edae3b842d757756449682778944", - "sha256:36db4c84d8f3aad328faaeaeaa454a633c95a854d78ea188791b147888379342", - "sha256:3aec6737c282e7fb5be41f6c7d0649e52ce49efb3508f30bada707e809bbbb5f", - "sha256:4086669280b2335d235c664373db46dcd7f6485dba4663ce1944ea01753c5e8b", - "sha256:4143803af909f284400c02f59de4d97e5ba9319de28366215ef55ef261914f9a", - "sha256:473bb86fa64ac9703d74a474514703b4665fa9a384221ced620b5025e64532a7", - "sha256:4932b2b5361013420189dbc8d30e970672d036b37cb382f1c09c3b6cfe651a37", - "sha256:49a8b713f0ff0bbc2f2af2e71c515cdced238786e25ef504f5982618c84c67a7", - "sha256:54d89442058271007ae8573dfa33360bea10e26603545481090b45e8b90c9d10", - "sha256:55df534d003efdd120c4ebfeb6b252c443d273cdc4b97a394eb0268367477795", - "sha256:5de5c3c1381ac303e71fdef75dace34af6e1d50b46ac081051cd209b8b933837", - "sha256:5f6eb8de31735c14ecc777e3ad77b57767b5f2dbea29265909ef696f51e8be92", - "sha256:6192e2ed81c15a7dab2554f5f69b134df8d1a982f8d9f13e57bdef93364d2120", - "sha256:643e48f92eaf65eb82964816bb7e7064ddb8239959210fa6168e8bce6fe6ef94", - "sha256:6ce7ac8a301a145f98d46db0bfd13bc8b3831a5bb92e8054d531a1f233bb4b93", - "sha256:7309a75b27c57f09b00a61815fb38c40da8e62e3004598e55ea1b8f713d96221", - "sha256:77f33cb95be6a49b93d8d6b81f05193676ae09857699cedf8f1a14a4285d077e", - "sha256:7a624d40c7b5ded7916f6cc65998af4585b4557c9ea65dc1e3a6273ebb2313ec", - "sha256:a06c0b96eb9d3bc88c627eec6e465726934ca0394347dc33efc742b8c91db83d", - "sha256:a4ce51e988570160af9ccfbbb1b9679546cbb1865d3a74ef0276f37fd94d91d9", - "sha256:ab6a600a9b2ea27453d56fd4464ad0db0ae69f5cea42595fcbdaabcd40396440", - "sha256:ab85c7cf772ba54f2718ebe366b836fffff868443f7c0c02389ed0a288cbde1f", - "sha256:ac45b91616e9b8afbe266ca08e80770b28e9e6d7a5852e3677fb37e42bde2047", - "sha256:adf20c34ba2cec1840a026023d93cc6d9b3581dfda6a044f434fc75b50c9a2ce", - "sha256:bd94048388b602fc30fdac2fecb986c034110ed8d2d17af7fd13b0de45c58bd7", - "sha256:c3440c90c31b61ae1df82f6c784643393f723354dc08013f9d5cedf25507c67c", - "sha256:cd630a2e6ec6df6a4977af63080fa8d63a0053ff8c06ea0200959b47ae75201c", - "sha256:d4e49cb46404cef61f83b30bb20ec9597c50ae7f55cfd6b89c17facc74675437", - "sha256:ec26244f9d9047f1bb401f1b86ff4775e1ddf638f4b4992bbc362a27a6f56673", - "sha256:f08a99e98b0a15083f06b1e221f064a29b3ed9e20617dc55aa8e823f2f732ace", - "sha256:fbf39dcd63f1d3b63c300fce59b7ea678bd5ea1d014e1e090a5226600a4132cb" - ], - "index": "pypi", - "markers": "platform_system != 'Darwin'", - "version": "==3.5.5" - }, - "certifi": { - "hashes": [ - "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", - "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" - ], - "markers": "python_version >= '3.6'", - "version": "==2022.9.24" - }, - "cffi": { - "hashes": [ - "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", - "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", - "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", - "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", - "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", - "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", - "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", - "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", - "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", - "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", - "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", - "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", - "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", - "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", - "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", - "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", - "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", - "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", - "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", - "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", - "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", - "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", - "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", - "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", - "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", - "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", - "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", - "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", - "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", - "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", - "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", - "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", - "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", - "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", - "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", - "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", - "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", - "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", - "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", - "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", - "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", - "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", - "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", - "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", - "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", - "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", - "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", - "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", - "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", - "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", - "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", - "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", - "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", - "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", - "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", - "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", - "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", - "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", - "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", - "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", - "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", - "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", - "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", - "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" - ], - "index": "pypi", - "version": "==1.15.1" - }, - "charset-normalizer": { - "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.1" - }, - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.3" - }, - "coloredlogs": { - "hashes": [ - "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", - "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==15.0.1" - }, - "crcmod": { - "hashes": [ - "sha256:50586ab48981f11e5b117523d97bb70864a2a1af246cf6e4f5c4a21ef4611cd1", - "sha256:69a2e5c6c36d0f096a7beb4cd34e5f882ec5fd232efb710cdb85d4ff196bd52e", - "sha256:737fb308fa2ce9aed2e29075f0d5980d4a89bfbec48a368c607c5c63b3efb90e", - "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e" - ], - "index": "pypi", - "version": "==1.7" - }, - "cryptography": { - "hashes": [ - "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a", - "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f", - "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0", - "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407", - "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7", - "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6", - "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153", - "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750", - "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad", - "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6", - "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b", - "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5", - "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a", - "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d", - "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d", - "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294", - "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0", - "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a", - "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac", - "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61", - "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013", - "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e", - "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb", - "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9", - "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd", - "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818" - ], - "index": "pypi", - "version": "==38.0.1" - }, - "cython": { - "hashes": [ - "sha256:061e25151c38f2361bc790d3bcf7f9d9828a0b6a4d5afa56fbed3bd33fb2373a", - "sha256:06be83490c906b6429b4389e13487a26254ccaad2eef6f3d4ee21d8d3a4aaa2b", - "sha256:07d173d3289415bb496e72cb0ddd609961be08fe2968c39094d5712ffb78672b", - "sha256:0bbc27abdf6aebfa1bce34cd92bd403070356f28b0ecb3198ff8a182791d58b9", - "sha256:0ea8267fc373a2c5064ad77d8ff7bf0ea8b88f7407098ff51829381f8ec1d5d9", - "sha256:3875c2b2ea752816a4d7ae59d45bb546e7c4c79093c83e3ba7f4d9051dd02928", - "sha256:39afb4679b8c6bf7ccb15b24025568f4f9b4d7f9bf3cbd981021f542acecd75b", - "sha256:3f85eb2343d20d91a4ea9cf14e5748092b376a64b7e07fc224e85b2753e9070b", - "sha256:40eff7aa26e91cf108fd740ffd4daf49f39b2fdffadabc7292b4b7dc5df879f0", - "sha256:479690d2892ca56d34812fe6ab8f58e4b2e0129140f3d94518f15993c40553da", - "sha256:4a4b03ab483271f69221c3210f7cde0dcc456749ecf8243b95bc7a701e5677e0", - "sha256:513e9707407608ac0d306c8b09d55a28be23ea4152cbd356ceaec0f32ef08d65", - "sha256:5514f3b4122cb22317122a48e175a7194e18e1803ca555c4c959d7dfe68eaf98", - "sha256:5ba622326f2862f9c1f99ca8d47ade49871241920a352c917e16861e25b0e5c3", - "sha256:63b79d9e1f7c4d1f498ab1322156a0d7dc1b6004bf981a8abda3f66800e140cd", - "sha256:656dc5ff1d269de4d11ee8542f2ffd15ab466c447c1f10e5b8aba6f561967276", - "sha256:67fdd2f652f8d4840042e2d2d91e15636ba2bcdcd92e7e5ffbc68e6ef633a754", - "sha256:79e3bab19cf1b021b613567c22eb18b76c0c547b9bc3903881a07bfd9e7e64cf", - "sha256:856d2fec682b3f31583719cb6925c6cdbb9aa30f03122bcc45c65c8b6f515754", - "sha256:8669cadeb26d9a58a5e6b8ce34d2c8986cc3b5c0bfa77eda6ceb471596cb2ec3", - "sha256:8733cf4758b79304f2a4e39ebfac5e92341bce47bcceb26c1254398b2f8c1af7", - "sha256:97335b2cd4acebf30d14e2855d882de83ad838491a09be2011745579ac975833", - "sha256:afbce249133a830f121b917f8c9404a44f2950e0e4f5d1e68f043da4c2e9f457", - "sha256:b0595aee62809ba353cebc5c7978e0e443760c3e882e2c7672c73ffe46383673", - "sha256:b6da3063c5c476f5311fd76854abae6c315f1513ef7d7904deed2e774623bbb9", - "sha256:c8e8025f496b5acb6ba95da2fb3e9dacffc97d9a92711aacfdd42f9c5927e094", - "sha256:cddc47ec746a08603037731f5d10aebf770ced08666100bd2cdcaf06a85d4d1b", - "sha256:cdf10af3e2e3279dc09fdc5f95deaa624850a53913f30350ceee824dc14fc1a6", - "sha256:d968ffc403d92addf20b68924d95428d523436adfd25cf505d427ed7ba3bee8b", - "sha256:dbee03b8d42dca924e6aa057b836a064c769ddfd2a4c2919e65da2c8a362d528", - "sha256:e1958e0227a4a6a2c06fd6e35b7469de50adf174102454db397cec6e1403cce3", - "sha256:e6ffa08aa1c111a1ebcbd1cf4afaaec120bc0bbdec3f2545f8bb7d3e8e77a1cd", - "sha256:e83228e0994497900af954adcac27f64c9a57cd70a9ec768ab0cb2c01fd15cf1", - "sha256:ea1dcc07bfb37367b639415333cfbfe4a93c3be340edf1db10964bc27d42ed64", - "sha256:eca3065a1279456e81c615211d025ea11bfe4e19f0c5650b859868ca04b3fcbd", - "sha256:ed087eeb88a8cf96c60fb76c5c3b5fb87188adee5e179f89ec9ad9a43c0c54b3", - "sha256:eeb475eb6f0ccf6c039035eb4f0f928eb53ead88777e0a760eccb140ad90930b", - "sha256:eefd2b9a5f38ded8d859fe96cc28d7d06e098dc3f677e7adbafda4dcdd4a461c", - "sha256:f3fd44cc362eee8ae569025f070d56208908916794b6ab21e139cea56470a2b3", - "sha256:f9944013588a3543fca795fffb0a070a31a243aa4f2d212f118aa95e69485831" - ], - "index": "pypi", - "version": "==0.29.32" - }, - "dill": { - "hashes": [ - "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302", - "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==0.3.5.1" - }, - "flake8": { - "hashes": [ - "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db", - "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248" - ], - "index": "pypi", - "version": "==5.0.4" - }, - "flask": { - "hashes": [ - "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b", - "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526" - ], - "index": "pypi", - "version": "==2.2.2" - }, - "flatbuffers": { - "hashes": [ - "sha256:0ae7d69c5b82bf41962ca5fde9cc43033bc9501311d975fd5a25e8a7d29c1245", - "sha256:71e135d533be527192819aaab757c5e3d109cb10fbb01e687f6bdb7a61ad39d1" - ], - "version": "==2.0.7" - }, - "future-fstrings": { - "hashes": [ - "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089", - "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63" - ], - "index": "pypi", - "version": "==1.2.0" - }, - "gunicorn": { - "hashes": [ - "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", - "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" - ], - "index": "pypi", - "version": "==20.1.0" - }, - "h3": { - "hashes": [ - "sha256:08a09f7a43ed142573c602ef487a058da54ab4d86c173082b29a5057805fe2d3", - "sha256:0a96ea1844182bd0511cdcdc89e38e3026d9a3d4139fd0c5e899709edd798ffa", - "sha256:1387166f453816f91d624c6ce70876a3c20356cd28a3a759920dee23c78684cf", - "sha256:25f0c22f4802ab71c45b86d206bd30fa0a6c7fbc3b630398b60c22907e9742e6", - "sha256:2bf4d75fe42a260ac23bf4cb9f9de6e6f2aa37279b2719387711f3e0727c4653", - "sha256:2faf304020493c5ffede34264bd28ed529b8b7238103e0904c0f3e9ca880bcfd", - "sha256:33b147ecc0e19ab1f27303d0e3ae28e5a457f3347ce18ca9a58b694a8b0cdd0a", - "sha256:38a084d74b234d48aafc01e4329cd9a92966e3f45b8cf21224118643b6eaa1c0", - "sha256:3b1642085939c597a9c723ae3b187f80527ffc79cad0ded0e55be9c9bac69c6c", - "sha256:4469fdf90034b1a67e155cac4f46b077fdc404b6182ab33abcb7081c9bfbf411", - "sha256:46a1284521d86cab414981056390be944dca780fe74c6c9e463a16d1c8d24871", - "sha256:585f375ba2a95ceb16b115a378e9118159c912c26703cf1627f57a004818c3b3", - "sha256:62057c1c3d1c7fe492841e42fa360825d66fafd55ac37dc4e90b2292af21cb47", - "sha256:68227df989274b0da54de9101a50741c70c48197ba3beacfb97c88170445c18e", - "sha256:7b0ddfdd02920996d7c6672c91e83efb5432c67ff83f89a03f774e84bcfe19f8", - "sha256:7c5366d24c2c01ef3bae68547c15f1965fac6053b2596c0073766bf7544ecaf0", - "sha256:8155b2de1938eb56128fe4fd96e4f6d2022d4c34d8137bc95d73cbf329f8f89e", - "sha256:83c2b0cd8259541f95b0493a620fb781b6a18c7c1e8fac1bda4fb234ae23ab43", - "sha256:8d03622433da1a2761574311af378ff1ff841f5956db25927837c6aee9d1c13c", - "sha256:960cd005b8817314d95fbaff3e848a72385df4e3c6c9703ff99b08581c8def69", - "sha256:9b0277d82578b3ed3220167ef5c5acd8b4e0ef2fcd6c2fd69dbf29e0c4e03765", - "sha256:a33fae02a54c63acb3c30fe49388715d658d76d42858a6ad4563e7e6859a9e57", - "sha256:a59d7d10597a2da9e9729637a625ae8dff2ed4e7c6c0b4952f0a5b2db6ef7152", - "sha256:ad21cfa8d97a62984ce30692a7ddf71a32a0c744cc247c43cbdbac1536aec4de", - "sha256:be63482de86bbb91db7f3f3b7dd452b9e08a11dacbda2088386831fb0e7de59c", - "sha256:c1108a9acb755310dce50a6e3c58ae1a2460ef60901d40e1155d633c7392f858", - "sha256:c644ab3f221c7faaab2d1ccd11bc3b1106f172e9bb1c85a863b0a097f6b71cce", - "sha256:c95c0818c163b69989c9e876dd82005e60edfbaabfd45429abebfc26f9a357e8", - "sha256:cdd68e684f0c6e18604d46ee04dbcfe5c79de62238b2c29f1db0f3a5d8dfa47b", - "sha256:ce86c6dce2c923bfb16e26586bc5f0443a8be61d4f43227be8587ccb95588a46", - "sha256:e61d3c6b1b66072f5b74d46dbee7df29daac6ce9738b9a6223a67dc577114515", - "sha256:f8edf5a546b31afdcd801b60448ea890ce1ff418fb784335e1329519f13aa85e" - ], - "version": "==3.7.4" - }, - "hatanaka": { - "hashes": [ - "sha256:5a0624f6812b13abb4c996398a60338566885c1786841c4c04de9b1b91da28d2", - "sha256:8fda4aa56f27313de75a806a2f5aa83ed5bb2dc7561bebab856a774d06cf1ee7", - "sha256:c22970b99169bddaf22e5239672e856a6bc9602c435f8793d26ad49619a70a99", - "sha256:ef594d63473782fac46df5b0c92a59211a3efea1d47c1a964244a0abffc9f3f6" - ], - "index": "pypi", - "version": "==2.4" - }, - "hexdump": { - "hashes": [ - "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db" - ], - "index": "pypi", - "version": "==3.3" - }, - "humanfriendly": { - "hashes": [ - "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", - "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==10.0" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "importlib-metadata": { - "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" - ], - "markers": "python_version < '3.10'", - "version": "==4.12.0" - }, - "importlib-resources": { - "hashes": [ - "sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681", - "sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7" - ], - "markers": "python_version >= '3.7'", - "version": "==5.9.0" - }, - "isort": { - "hashes": [ - "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7", - "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951" - ], - "markers": "python_version < '4' and python_full_version >= '3.6.1'", - "version": "==5.10.1" - }, - "itsdangerous": { - "hashes": [ - "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", - "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.2" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "index": "pypi", - "version": "==3.1.2" - }, - "json-rpc": { - "hashes": [ - "sha256:84b45058e5ba95f49c7b6afcf7e03ab86bee89bf2c01f3ad8dd41fe114fc1f84", - "sha256:def0dbcf5b7084fc31d677f2f5990d988d06497f2f47f13024274cfb2d5d7589" - ], - "index": "pypi", - "version": "==1.13.0" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7", - "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a", - "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c", - "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc", - "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f", - "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09", - "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442", - "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e", - "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029", - "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61", - "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb", - "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0", - "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35", - "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42", - "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1", - "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad", - "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443", - "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd", - "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9", - "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148", - "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38", - "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55", - "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36", - "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a", - "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b", - "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44", - "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6", - "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69", - "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4", - "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84", - "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de", - "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28", - "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c", - "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1", - "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8", - "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b", - "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb" - ], - "markers": "python_version >= '3.6'", - "version": "==1.7.1" - }, - "libusb1": { - "hashes": [ - "sha256:083f75e5d15cb5e2159e64c308c5317284eae926a820d6dce53a9505d18be3b2", - "sha256:0e652b04cbe85ec8e74f9ee82b49f861fb14b5320ae51399387ad2601ccc0500", - "sha256:5792a9defee40f15d330a40d9b1800545c32e47ba7fc66b6f28f133c9fcc8538", - "sha256:6f6bb010632ada35c661d17a65e135077beef0fbb2434d5ffdb3a4a911fd9490" - ], - "index": "pypi", - "version": "==3.0.0" - }, - "markupsafe": { - "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.1" - }, - "mccabe": { - "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" - ], - "markers": "python_version >= '3.6'", - "version": "==0.7.0" - }, - "mpmath": { - "hashes": [ - "sha256:604bc21bd22d2322a177c73bdb573994ef76e62edd595d17e00aff24b0667e5c", - "sha256:79ffb45cf9f4b101a807595bcb3e72e0396202e0b1d25d689134b48c4216a81a" - ], - "version": "==1.2.1" - }, - "ncompress": { - "hashes": [ - "sha256:0349d7de11edd70a7efea9ce9dc67f0e47b5774832dd063f7ae68a9e3e36ea31", - "sha256:070044eab19586a45d1855c3e50e000ce86d6075b122a5ec8cffd480713dffac", - "sha256:13fa26ec8000d786a8079bb265508b5df4b445a4f460481a13549b4bd3c83824", - "sha256:15f10fbfa11345ff0af090e3e6ae13a1fe2b52a2bb39d4f2373c2d6aeac75e5d", - "sha256:2a104803fbe3ab0a96edb14927fa22c8142be838aabe7e938b4a52a4e82db56e", - "sha256:34754041d9bac2d6908ae0d07ba541e4d6d606cca222ddd53f3a57e15f386b0a", - "sha256:34c6496168fd4dbc13f1fc0c0fcbadded1957639956f8cbc6894c39999817e36", - "sha256:3590e66313041721ae81e72ece06b7048c9293321bb30900358638673608e264", - "sha256:393cc3c126b9451fb32fe2bc07773264c90e73afbd37da0df472ac23bfd1a2d5", - "sha256:5336a8831a7e587829ce54e9e27d1fb2e04ddbc7d2d983693e35a3a03ac3ce79", - "sha256:5a2ae8a9170fa1f45df7efa292eb8c437b18c225b63d4adca4f50f9da0e8e0c7", - "sha256:6540556d47670a8fb93878a44d0206bbdc87f32e4c5b57d6fe63691efafbb982", - "sha256:66d991155a1655ccd98e8433c4a7e811d63eb649adb55f47d8f9528a30cc4b7a", - "sha256:736dbae078107742cf6ac7ccc11ae9c5eab77ef2c02aab3ef64802877bb01cab", - "sha256:7608fbda43d04d9f476be2dbf4ef3c96e72d83b9557a48b07fbc9ff3ad29cdd2", - "sha256:78674f246878938387b6f82b10d1aa2192e02544d214541943d12ef1a45e66c6", - "sha256:8322482e72ac2802d1dca1007ec06aa281a4d5cf1cf9f8c75bb51e917382b756", - "sha256:8b9acc46cf36bb998ed215d6e76a94e2bd1e827b9a4cb5362982b7004b5a7620", - "sha256:8eb4a55cbeaeb238a3b412952077be6b3f37b3416cd0211cc22776391ff2fef7", - "sha256:916671d62167191af58d6b4a17b1c09c647e349dcff1fc0b7d764aa64c3773ee", - "sha256:94b3f4e851f5b37e1d4cf2d8da911fa10783a59cba3d7f1f2ae5bd2842558077", - "sha256:9cd040ad73a3b0e917e01cdfba507e10e0bb56849daaac3ac3d86382d4d7ad82", - "sha256:9d89acf209858e7940223cf35324e1b2effec119bb009a41f039e2ea4db22177", - "sha256:9da7c81313aed4b6c6e8020442ed8d03d04bff72947f9380ea1ce2c63ffb8ad1", - "sha256:aaa18a509d9fc173b4b47d53c834e43ced1eda63d2aa7d4613dc59b2f802a31a", - "sha256:ab9fc62baaa55faf8ed8ac67f2c64a7295fec91d7c1f306ac46aa894ca4edf91", - "sha256:af0011bae90e44121f4e4edbff3dccdce7e4c5fc5e354db7eb48410d71f496df", - "sha256:b031e06b42037b181e3514261e1e85a9eae4af990c12b9348a9f22b8042201ff", - "sha256:d11df815d280985dfa660974df11dbe051a1a18dca2f91f9d30fbd6548237b8f", - "sha256:d45ec59a8a3ce00613df0c81e5567854574dbbbf01ecd1a5a0929cd8fb04844d", - "sha256:da216a53db7cd4c0247376f87367dd71df457443567e55310f6d3d23a9aff2f2", - "sha256:e0ebd71990ef7909b6627b5341a2fe1977dcce61dd3760a29e19e3f9e4c6a275", - "sha256:e6f5bf381412e9d3847b76e8b6bd1f84dfadcd3d9c25903c8592facb437909a0", - "sha256:e7bbf10cca1376f4f17ae2c447e33a9d4067525abb0c71d488c9a5ced50552f1", - "sha256:f9ba6ab2aadd6fd90365fdad5219e4dc7bc2459b94f1e900a733dddaf4e9b2e6", - "sha256:fe0a671a2f7dc1ee0438d278ef30ab425a969536100c4352b5cb6bc0b6210818" - ], - "version": "==1.0.0" - }, - "nose": { - "hashes": [ - "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac", - "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a", - "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98" - ], - "index": "pypi", - "version": "==1.3.7" - }, - "numpy": { - "hashes": [ - "sha256:004f0efcb2fe1c0bd6ae1fcfc69cc8b6bf2407e0f18be308612007a0762b4089", - "sha256:09f6b7bdffe57fc61d869a22f506049825d707b288039d30f26a0d0d8ea05164", - "sha256:0ea3f98a0ffce3f8f57675eb9119f3f4edb81888b6874bc1953f91e0b1d4f440", - "sha256:17c0e467ade9bda685d5ac7f5fa729d8d3e76b23195471adae2d6a6941bd2c18", - "sha256:1f27b5322ac4067e67c8f9378b41c746d8feac8bdd0e0ffede5324667b8a075c", - "sha256:22d43376ee0acd547f3149b9ec12eec2f0ca4a6ab2f61753c5b29bb3e795ac4d", - "sha256:2ad3ec9a748a8943e6eb4358201f7e1c12ede35f510b1a2221b70af4bb64295c", - "sha256:301c00cf5e60e08e04d842fc47df641d4a181e651c7135c50dc2762ffe293dbd", - "sha256:39a664e3d26ea854211867d20ebcc8023257c1800ae89773cbba9f9e97bae036", - "sha256:51bf49c0cd1d52be0a240aa66f3458afc4b95d8993d2d04f0d91fa60c10af6cd", - "sha256:78a63d2df1d947bd9d1b11d35564c2f9e4b57898aae4626638056ec1a231c40c", - "sha256:7cd1328e5bdf0dee621912f5833648e2daca72e3839ec1d6695e91089625f0b4", - "sha256:8355fc10fd33a5a70981a5b8a0de51d10af3688d7a9e4a34fcc8fa0d7467bb7f", - "sha256:8c79d7cf86d049d0c5089231a5bcd31edb03555bd93d81a16870aa98c6cfb79d", - "sha256:91b8d6768a75247026e951dce3b2aac79dc7e78622fc148329135ba189813584", - "sha256:94c15ca4e52671a59219146ff584488907b1f9b3fc232622b47e2cf832e94fb8", - "sha256:98dcbc02e39b1658dc4b4508442a560fe3ca5ca0d989f0df062534e5ca3a5c1a", - "sha256:a64403f634e5ffdcd85e0b12c08f04b3080d3e840aef118721021f9b48fc1460", - "sha256:bc6e8da415f359b578b00bcfb1d08411c96e9a97f9e6c7adada554a0812a6cc6", - "sha256:bdc9febce3e68b697d931941b263c59e0c74e8f18861f4064c1f712562903411", - "sha256:c1ba66c48b19cc9c2975c0d354f24058888cdc674bebadceb3cdc9ec403fb5d1", - "sha256:c9f707b5bb73bf277d812ded9896f9512a43edff72712f31667d0a8c2f8e71ee", - "sha256:d5422d6a1ea9b15577a9432e26608c73a78faf0b9039437b075cf322c92e98e7", - "sha256:e5d5420053bbb3dd64c30e58f9363d7a9c27444c3648e61460c1237f9ec3fa14", - "sha256:e868b0389c5ccfc092031a861d4e158ea164d8b7fdbb10e3b5689b4fc6498df6", - "sha256:efd9d3abe5774404becdb0748178b48a218f1d8c44e0375475732211ea47c67e", - "sha256:f8c02ec3c4c4fcb718fdf89a6c6f709b14949408e8cf2a2be5bfa9c49548fd85", - "sha256:ffcf105ecdd9396e05a8e58e81faaaf34d3f9875f137c7372450baa5d77c9a54" - ], - "index": "pypi", - "version": "==1.23.3" - }, - "onnx": { - "hashes": [ - "sha256:13b3e77d27523b9dbf4f30dfc9c959455859d5e34e921c44f712d69b8369eff9", - "sha256:213e73610173f6b2e99f99a4b0636f80b379c417312079d603806e48ada4ca8b", - "sha256:23781594bb8b7ee985de1005b3c601648d5b0568a81e01365c48f91d1f5648e4", - "sha256:2d9a7db54e75529160337232282a4816cc50667dc7dc34be178fd6f6b79d4705", - "sha256:341c7016e23273e9ffa9b6e301eee95b8c37d0f04df7cedbdb169d2c39524c96", - "sha256:3c6e6bcffc3f5c1e148df3837dc667fa4c51999788c1b76b0b8fbba607e02da8", - "sha256:5578b93dc6c918cec4dee7fb7d9dd3b09d338301ee64ca8b4f28bc217ed42dca", - "sha256:56ceb7e094c43882b723cfaa107d85ad673cfdf91faeb28d7dcadacca4f43a07", - "sha256:81a3555fd67be2518bf86096299b48fb9154652596219890abfe90bd43a9ec13", - "sha256:8a7aa61aea339bd28f310f4af4f52ce6c4b876386228760b16308efd58f95059", - "sha256:9fd2f4e23078df197bb76a59b9cd8f5a43a6ad2edc035edb3ecfb9042093e05a", - "sha256:af90427ca04c6b7b8107c2021e1273227a3ef1a7a01f3073039cae7855a59833", - "sha256:b3629e8258db15d4e2c9b7f1be91a3186719dd94661c218c6f5fde3cc7de3d4d", - "sha256:bdbd2578424c70836f4d0f9dda16c21868ddb07cc8192f9e8a176908b43d694b", - "sha256:c11162ffc487167da140f1112f49c4f82d815824f06e58bc3095407699f05863", - "sha256:c39a7a0352c856f1df30dccf527eb6cb4909052e5eaf6fa2772a637324c526aa", - "sha256:c7a9b3ea02c30efc1d2662337e280266aca491a8e86be0d8a657f874b7cccd1e", - "sha256:f66d2996e65f490a57b3ae952e4e9189b53cc9fe3f75e601d50d4db2dc1b1cd9", - "sha256:f8800f28c746ab06e51ef8449fd1215621f4ddba91be3ffc264658937d38a2af", - "sha256:fab13feb4d94342aae6d357d480f2e47d41b9f4e584367542b21ca6defda9e0a", - "sha256:fea5156a03398fe0e23248042d8651c1eaac5f6637d4dd683b4c1f1320b9f7b4" - ], - "index": "pypi", - "version": "==1.12.0" - }, - "onnxruntime-gpu": { - "hashes": [ - "sha256:296bd9733986cb7517d15bef5535c555d3f863963a71e6575e92d2a854aee61d", - "sha256:42b0393c5122ed90fa2eb76192a486261d86e9526ccb78b2a98923c22791d2d1", - "sha256:8e46d0724ce54c5908c5760037b78de741fbd48962b370c29ebc20e608b30eda", - "sha256:b37872527d03d3df10756408ca44014bd6ac354a044ab1c4286cd42dc138e518", - "sha256:d73204323aefebe4eecab9fcf76e22b1a00394e3d838c2962a28a27301186b73", - "sha256:e2be6f7f5a1ce0bc8471ce42e10eab92cfb19d0748b857edcb5320b5e98311b7", - "sha256:ecfe97335027e569d4f46725ba89316041e562b8c499690e25e11cfee4601cd1", - "sha256:fd919373be35b9ba54210688265df38ad5e19a530449385c40dab51da407345d" - ], - "index": "pypi", - "markers": "platform_system != 'Darwin'", - "version": "==1.12.1" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "markers": "python_version >= '3.6'", - "version": "==21.3" - }, - "pillow": { - "hashes": [ - "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927", - "sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14", - "sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc", - "sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58", - "sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60", - "sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76", - "sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c", - "sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac", - "sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490", - "sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1", - "sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f", - "sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d", - "sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f", - "sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069", - "sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402", - "sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437", - "sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885", - "sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e", - "sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be", - "sha256:408673ed75594933714482501fe97e055a42996087eeca7e5d06e33218d05aa8", - "sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff", - "sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da", - "sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004", - "sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f", - "sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20", - "sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d", - "sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c", - "sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544", - "sha256:727dd1389bc5cb9827cbd1f9d40d2c2a1a0c9b32dd2261db522d22a604a6eec9", - "sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3", - "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04", - "sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c", - "sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5", - "sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4", - "sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb", - "sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4", - "sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c", - "sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467", - "sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e", - "sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421", - "sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b", - "sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8", - "sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb", - "sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3", - "sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc", - "sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf", - "sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1", - "sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a", - "sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28", - "sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0", - "sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1", - "sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8", - "sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd", - "sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4", - "sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8", - "sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f", - "sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013", - "sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59", - "sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc", - "sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4" - ], - "index": "pypi", - "version": "==9.2.0" - }, - "platformdirs": { - "hashes": [ - "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", - "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" - ], - "markers": "python_version >= '3.7'", - "version": "==2.5.2" - }, - "protobuf": { - "hashes": [ - "sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf", - "sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f", - "sha256:0d4719e724472e296062ba8e82a36d64693fcfdb550d9dff98af70ca79eafe3d", - "sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f", - "sha256:2b35602cb65d53c168c104469e714bf68670335044c38eee3c899d6a8af03ffc", - "sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7", - "sha256:32fff501b6df3050936d1839b80ea5899bf34db24792d223d7640611f67de15a", - "sha256:34400fd76f85bdae9a2e9c1444ea4699c0280962423eff4418765deceebd81b5", - "sha256:3767c64593a49c7ac0accd08ed39ce42744405f0989d468f0097a17496fdbe84", - "sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996", - "sha256:3f2ed842e8ca43b790cb4a101bcf577226e0ded98a6a6ba2d5e12095a08dc4da", - "sha256:52c1e44e25f2949be7ffa7c66acbfea940b0945dd416920231f7cb30ea5ac6db", - "sha256:5d9b5c8270461706973c3871c6fbdd236b51dfe9dab652f1fb6a36aa88287e47", - "sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067", - "sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c", - "sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7", - "sha256:72d357cc4d834cc85bd957e8b8e1f4b64c2eac9ca1a942efeb8eb2e723fca852", - "sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9", - "sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c", - "sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739", - "sha256:79cd8d0a269b714f6b32641f86928c718e8d234466919b3f552bfb069dbb159b", - "sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91", - "sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c", - "sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153", - "sha256:a4c0c6f2f95a559e59a0258d3e4b186f340cbdc5adec5ce1bc06d01972527c88", - "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9", - "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388", - "sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e", - "sha256:b309fda192850ac4184ca1777aab9655564bc8d10a9cc98f10e1c8bf11295c22", - "sha256:b3d7d4b4945fe3c001403b6c24442901a5e58c0a3059290f5a63523ed4435f82", - "sha256:c8829092c5aeb61619161269b2f8a2e36fd7cb26abbd9282d3bc453f02769146", - "sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab", - "sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde", - "sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531", - "sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8", - "sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7", - "sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20", - "sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3" - ], - "index": "pypi", - "version": "==3.20.1" - }, - "psutil": { - "hashes": [ - "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97", - "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84", - "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969", - "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf", - "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32", - "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12", - "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727", - "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06", - "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c", - "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9", - "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea", - "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8", - "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f", - "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c", - "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d", - "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339", - "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444", - "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab", - "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb", - "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b", - "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8", - "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec", - "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8", - "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d", - "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34", - "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85", - "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1", - "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9", - "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1", - "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d", - "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5", - "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c" - ], - "index": "pypi", - "version": "==5.9.2" - }, - "pycapnp": { - "hashes": [ - "sha256:0c770145a4eccfe97f53ab500283aa9bf969d4a37bffc75737a964db4f2af833", - "sha256:13badfb644e2eb7f1219aab259d18b262d1512021e4112fa1ad5e74d17bc30cf", - "sha256:1774a4fe9db5f094ba40cf00898fa4b437773e7f9c538b779275b9f422a92ebc", - "sha256:2a1746017079107232faf26af8ef4284ab0b20ce5cbe688d44e7553a67e5e5cb", - "sha256:2a7aa9af0185e5977a59228db5042dffb048b2d4bf4f665d2105b4781cf2fcbc", - "sha256:2b28d5d951602c0b832bbe63f85ebdd7685b33118b1c11c2c65a243ec9f35a66", - "sha256:47c8bc28521312660c95cfc8a552654949407f8b17bc7ed6955ad7dae34d21a4", - "sha256:60adf2674f89f629551171116b8f400b17e9a41a2ef15736767acec405d4ca50", - "sha256:61b009faba34855c9d29db107e188898c83099347e22ebcbc1d955774403247b", - "sha256:786a2e39b79e592a41e8a1eaeea6e41e2015ecb9f5b7f7c20dfc5768ba1ae077", - "sha256:a788a374ccb93354943c89f5b1caf785faf7bb90191cd6265e042aa004f8b206", - "sha256:b9a1d6306a0e3e0090574aeb08d432bd67f9eb04ab564e89ef34cd1fe320b20f", - "sha256:bdd013eae51d190a2426d00cc72d0aaed148a5be778ca86ee1adae3ab7a0613f" - ], - "index": "pypi", - "version": "==1.1.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785", - "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b" - ], - "markers": "python_version >= '3.6'", - "version": "==2.9.1" - }, - "pycparser": { - "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" - ], - "version": "==2.21" - }, - "pycryptodome": { - "hashes": [ - "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79", - "sha256:0926f7cc3735033061ef3cf27ed16faad6544b14666410727b31fea85a5b16eb", - "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e", - "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88", - "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763", - "sha256:2ea63d46157386c5053cfebcdd9bd8e0c8b7b0ac4a0507a027f5174929403884", - "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13", - "sha256:2ffd8b31561455453ca9f62cb4c24e6b8d119d6d531087af5f14b64bee2c23e6", - "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2", - "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667", - "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a", - "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d", - "sha256:60b4faae330c3624cc5a546ba9cfd7b8273995a15de94ee4538130d74953ec2e", - "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b", - "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83", - "sha256:9135dddad504592bcc18b0d2d95ce86c3a5ea87ec6447ef25cfedea12d6018b8", - "sha256:9c772c485b27967514d0df1458b56875f4b6d025566bf27399d0c239ff1b369f", - "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f", - "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676", - "sha256:a8f06611e691c2ce45ca09bbf983e2ff2f8f4f87313609d80c125aff9fad6e7f", - "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8", - "sha256:b9cc96e274b253e47ad33ae1fccc36ea386f5251a823ccb50593a935db47fdd2", - "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f", - "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9", - "sha256:d2a39a66057ab191e5c27211a7daf8f0737f23acbf6b3562b25a62df65ffcb7b", - "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1", - "sha256:ecaaef2d21b365d9c5ca8427ffc10cebed9d9102749fd502218c23cb9a05feb5", - "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c", - "sha256:ff287bcba9fbeb4f1cccc1f2e90a08d691480735a611ee83c80a7d74ad72b9d9", - "sha256:ff7ae90e36c1715a54446e7872b76102baa5c63aa980917f4aa45e8c78d1a3ec" - ], - "index": "pypi", - "version": "==3.15.0" - }, - "pyflakes": { - "hashes": [ - "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2", - "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3" - ], - "markers": "python_version >= '3.6'", - "version": "==2.5.0" - }, - "pyjwt": { - "hashes": [ - "sha256:8d82e7087868e94dd8d7d418e5088ce64f7daab4b36db654cbaedb46f9d1ca80", - "sha256:e77ab89480905d86998442ac5788f35333fa85f65047a534adc38edf3c88fc3b" - ], - "index": "pypi", - "version": "==2.5.0" - }, - "pylint": { - "hashes": [ - "sha256:5fdfd44af182866999e6123139d265334267339f29961f00c89783155eacc60b", - "sha256:7f6aad1d8d50807f7bc64f89ac75256a9baf8e6ed491cc9bc65592bc3f462cf1" - ], - "index": "pypi", - "version": "==2.15.3" - }, - "pyopencl": { - "hashes": [ - "sha256:024f7ad835f70fff2c27a3d111eec438761c42413ca78af20cc87ad3ecaba01a", - "sha256:03f3e96c8743edf16dceddef564c5198f8d988152a26a859de9d3e1e0f14888c", - "sha256:07e58b74a59cd27c390f3099597c1f05e50c441f82fb17fb84d43e5785951ecf", - "sha256:07e9ffe8d5d38066fd5a8a5540b6944617322b13d55db7e3f78609dc309e4da8", - "sha256:10bc9e39e6bb5c6f842dd4a3af869cb73a4ee29d47a74deed8120390c7bcf4ad", - "sha256:15d4843b88eb2379cb29d2ef13b93b6ce8f917bae70eb6c1584ba21c4c5c4ff6", - "sha256:21da5f08aabbc2b2fdc81466ffaac07c1db94b1f47a95bc57f633b55590ccba2", - "sha256:2f5010cfcd434c56e9bbad5fb4dba2fa64b1de6d8f9282b29a5d837268fe93cc", - "sha256:3361f7b1797cdd38c9fff54c6e34750a5665c9c573aab46fcb486fefdf6fcfca", - "sha256:4599fba8aff4c381d2f16651c025b4e6e9488100781a95634215755ea4935a0d", - "sha256:462f1ba6ee3769492bc376bdaeaf2f34f3528bd0fd0dc60569f3edf9346cc769", - "sha256:4890137300a18d94265f1342f5eb8de420029637a09020b682f09f63271170c5", - "sha256:4e55c1df1976040c01315dc09477c7369422e67f36dcf69d9f570bdf48759802", - "sha256:58641144140025b39dbf27a095e250018426a25973e7cfd87724b24c6c8a6a3e", - "sha256:5b8f4358d6bdcf719c46f91c0e9a8ff8ece05843f26de1d047ea1b1ae1875aaf", - "sha256:647ff48cb851040650d79d99eae0229bfd9cd8d931ffae8d33a887891be2b8f4", - "sha256:71ec7b12833a9e29807dc95421791c5ebed8f9435f3e99c5ac77f9f409429863", - "sha256:80db5d46608dfa9e37109bfb925be64cb8d24b06e27945cf7c8996fa9e64ae50", - "sha256:8189b95ac0c845b2639395d5dffe2c4406ac5e42c61b8db972e5dc596e5b8685", - "sha256:8906173bf2d3bc036e0acc8e4d785fc33c89951bacbb0049d64e75d7c476beed", - "sha256:9fbd13defa6f7d719540433890b5318f16a8c3c453dd5feb66a6054a79144c01", - "sha256:a238dd164b141dd9eea0fbab39f0d247bd3c5f8d31b85997aa5619c43a6cb9f5", - "sha256:a2a00fbe65fcebf071a6af59e96fc6b03c8dc95c0d5623cd7d96a083930ffb31", - "sha256:a41e0b02b4c9e6bfdf880d8f6d8d5a21fdd04cd7e7f2afd4d0c5c94994963530", - "sha256:a6bb5e7cb9612b011da83a274ee5477ee9c8892860bae5f3f105c80b512192f9", - "sha256:a78827b7d0f5ee22890a950d08cd2516b136c6af10abad696e5a8f4b62d55db5", - "sha256:b0711e2508fbf9de1d26817f79f57a43b6d84f088f6e40208582e7173a0a3b22", - "sha256:bdbbe72731fdc8152b555360efec791f9c5b71f0eed033052302d51547ca00cb", - "sha256:c4d734261075c750fe7347eb07cdc155d53deb4175be2b9d73524bcc9868072c", - "sha256:c6bd1e1d086d4b28322e88d22deeff06684360f3a9017d7d7eb2f1ae48095479", - "sha256:c8835ad22ac0e656d5b437abb99c763bb4529485c858216015c1286d6a919159", - "sha256:cd322df0f8bec18445e3be0d9dfb7899ed570e520949d337dfb42cc3306e835a", - "sha256:d04291fa318c7ce1033fba5e16f5ca5f7b28dab49213596b5139bac51812cd69", - "sha256:d1eecc9bd2c2dbc32b6f550b7e9264bb8e8bef8520e75fd4dbc627c21faebaf1", - "sha256:d493b83e1be953e7d7849704a0970d2e6915fb5b3514222ab8a6abd3d47e123e", - "sha256:dae8527318f60b557103d4d385892a86c3f470eeed1f560b830d1e8a5724a4b5", - "sha256:e0e81c075fb1c21a3080259fe7de771f1b06861140901c22e47f4e8a69bd8984" - ], - "index": "pypi", - "version": "==2022.2.3" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" - }, - "pyserial": { - "hashes": [ - "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", - "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0" - ], - "index": "pypi", - "version": "==3.5" - }, - "pyside2": { - "hashes": [ - "sha256:235240b6ec8206d9fdf0232472c6ef3241783d480425e5b54796f06e39ed23da", - "sha256:23886c6391ebd916e835fa1b5ae66938048504fd3a2934ae3189a96cd5ac0b46", - "sha256:439509e53cfe05abbf9a99422a2cbad086408b0f9bf5e6f642ff1b13b1f8b055", - "sha256:a9e2e6bbcb5d2ebb421e46e72244a0f4fe0943b2288115f80a863aacc1de1f06", - "sha256:af6b263fe63ba6dea7eaebae80aa7b291491fe66f4f0057c0aafe780cc83da9d", - "sha256:b5e1d92f26b0bbaefff67727ccbb2e1b577f2c0164b349b3d6e80febb4c5bde2" - ], - "index": "pypi", - "version": "==5.15.2.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "index": "pypi", - "version": "==2.8.2" - }, - "pytools": { - "hashes": [ - "sha256:4d62875e9a2ab2a24e393a9a8b799492f1a721bffa840af3807bfd42871dd1f4" - ], - "markers": "python_version ~= '3.6'", - "version": "==2022.1.12" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "index": "pypi", - "version": "==6.0" - }, - "pyzmq": { - "hashes": [ - "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107", - "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7", - "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d", - "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc", - "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c", - "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4", - "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8", - "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8", - "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287", - "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b", - "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f", - "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77", - "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066", - "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209", - "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd", - "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a", - "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4", - "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc", - "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58", - "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246", - "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62", - "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227", - "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b", - "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944", - "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2", - "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804", - "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8", - "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066", - "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1", - "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33", - "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639", - "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef", - "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a", - "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace", - "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00", - "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5", - "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b", - "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879", - "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340", - "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4", - "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4", - "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6", - "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3", - "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f", - "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3", - "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409", - "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913", - "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1", - "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43", - "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333", - "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75", - "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff", - "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e", - "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2", - "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef", - "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1", - "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330", - "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d", - "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0", - "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6", - "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea", - "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f", - "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff", - "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99", - "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b", - "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d", - "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be", - "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58", - "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc", - "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83", - "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d", - "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc", - "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66", - "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e" - ], - "index": "pypi", - "version": "==24.0.1" - }, - "requests": { - "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" - ], - "index": "pypi", - "version": "==2.28.1" - }, - "scons": { - "hashes": [ - "sha256:7703c4e9d2200b4854a31800c1dbd4587e1fa86e75f58795c740bcfa7eca7eaa", - "sha256:cbbd73b83cf85f1aaaf986370359de1bbfd3af97a765cb3554734f6dcec734e1" - ], - "index": "pypi", - "version": "==4.4.0" - }, - "sentry-sdk": { - "hashes": [ - "sha256:d6c71d2f85710b66822adaa954af7912bab135d6c85febd5b0f3dfd4ab37e181", - "sha256:ef925b5338625448645a778428d8f22a3d17de8b28cc8e6fba60b93393ad86fe" - ], - "index": "pypi", - "version": "==1.9.9" - }, - "setproctitle": { - "hashes": [ - "sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b", - "sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9", - "sha256:1f0cde41857a644b7353a0060b5f94f7ba7cf593ebde5a1094da1be581ac9a31", - "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83", - "sha256:1fa1a0fbee72b47dc339c87c890d3c03a72ea65c061ade3204f285582f2da30f", - "sha256:1ff863a20d1ff6ba2c24e22436a3daa3cd80be1dfb26891aae73f61b54b04aca", - "sha256:265ecbe2c6eafe82e104f994ddd7c811520acdd0647b73f65c24f51374cf9494", - "sha256:288943dec88e178bb2fd868adf491197cc0fc8b6810416b1c6775e686bab87fe", - "sha256:2e3ac25bfc4a0f29d2409650c7532d5ddfdbf29f16f8a256fc31c47d0dc05172", - "sha256:2fbd8187948284293f43533c150cd69a0e4192c83c377da837dbcd29f6b83084", - "sha256:4058564195b975ddc3f0462375c533cce310ccdd41b80ac9aed641c296c3eff4", - "sha256:4749a2b0c9ac52f864d13cee94546606f92b981b50e46226f7f830a56a9dc8e1", - "sha256:4d8938249a7cea45ab7e1e48b77685d0f2bab1ebfa9dde23e94ab97968996a7c", - "sha256:5194b4969f82ea842a4f6af2f82cd16ebdc3f1771fb2771796e6add9835c1973", - "sha256:55ce1e9925ce1765865442ede9dca0ba9bde10593fcd570b1f0fa25d3ec6b31c", - "sha256:589be87172b238f839e19f146b9ea47c71e413e951ef0dc6db4218ddacf3c202", - "sha256:5b932c3041aa924163f4aab970c2f0e6b4d9d773f4d50326e0ea1cd69240e5c5", - "sha256:5fb4f769c02f63fac90989711a3fee83919f47ae9afd4758ced5d86596318c65", - "sha256:630f6fe5e24a619ccf970c78e084319ee8be5be253ecc9b5b216b0f474f5ef18", - "sha256:65d884e22037b23fa25b2baf1a3316602ed5c5971eb3e9d771a38c3a69ce6e13", - "sha256:6c877691b90026670e5a70adfbcc735460a9f4c274d35ec5e8a43ce3f8443005", - "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02", - "sha256:7a55fe05f15c10e8c705038777656fe45e3bd676d49ad9ac8370b75c66dd7cd7", - "sha256:7aa0aac1711fadffc1d51e9d00a3bea61f68443d6ac0241a224e4d622489d665", - "sha256:7f0bed90a216ef28b9d227d8d73e28a8c9b88c0f48a082d13ab3fa83c581488f", - "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1", - "sha256:7fe9df7aeb8c64db6c34fc3b13271a363475d77bc157d3f00275a53910cb1989", - "sha256:8ff3c8cb26afaed25e8bca7b9dd0c1e36de71f35a3a0706b5c0d5172587a3827", - "sha256:9124bedd8006b0e04d4e8a71a0945da9b67e7a4ab88fdad7b1440dc5b6122c42", - "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927", - "sha256:a149a5f7f2c5a065d4e63cb0d7a4b6d3b66e6e80f12e3f8827c4f63974cbf122", - "sha256:a47d97a75fd2d10c37410b180f67a5835cb1d8fdea2648fd7f359d4277f180b9", - "sha256:a499fff50387c1520c085a07578a000123f519e5f3eee61dd68e1d301659651f", - "sha256:ab45146c71ca6592c9cc8b354a2cc9cc4843c33efcbe1d245d7d37ce9696552d", - "sha256:b2c9cb2705fc84cb8798f1ba74194f4c080aaef19d9dae843591c09b97678e98", - "sha256:b34baef93bfb20a8ecb930e395ccd2ae3268050d8cf4fe187de5e2bd806fd796", - "sha256:b617f12c9be61e8f4b2857be4a4319754756845dbbbd9c3718f468bbb1e17bcb", - "sha256:b9fb97907c830d260fa0658ed58afd48a86b2b88aac521135c352ff7fd3477fd", - "sha256:bae283e85fc084b18ffeb92e061ff7ac5af9e183c9d1345c93e178c3e5069cbe", - "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806", - "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484", - "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e", - "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575", - "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76", - "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246", - "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb", - "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099", - "sha256:e43f315c68aa61cbdef522a2272c5a5b9b8fd03c301d3167b5e1343ef50c676c", - "sha256:e49ae693306d7624015f31cb3e82708916759d592c2e5f72a35c8f4cc8aef258", - "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865", - "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b", - "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d", - "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10", - "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f", - "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94", - "sha256:faec934cfe5fd6ac1151c02e67156c3f526e82f96b24d550b5d51efa4a5527c6", - "sha256:fcd3cf4286a60fdc95451d8d14e0389a6b4f5cebe02c7f2609325eb016535963", - "sha256:fe8a988c7220c002c45347430993830666e55bc350179d91fcee0feafe64e1d4", - "sha256:fed18e44711c5af4b681c2b3b18f85e6f0f1b2370a28854c645d636d5305ccd8", - "sha256:ffc61a388a5834a97953d6444a2888c24a05f2e333f9ed49f977a87bb1ad4761" - ], - "index": "pypi", - "version": "==1.3.2" - }, - "setuptools": { - "hashes": [ - "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9", - "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1" - ], - "markers": "python_version >= '3.7'", - "version": "==65.4.0" - }, - "shiboken2": { - "hashes": [ - "sha256:63debfcc531b6a2b4985aa9b71433d2ad3bac542acffc729cc0ecaa3854390c0", - "sha256:87079c07587859a525b9800d60b1be971338ce9b371d6ead81f15ee5a46d448b", - "sha256:a0d0fdeb12b72c8af349b9642ccc67afd783dca449309f45e78cda50272fd6b7", - "sha256:eb0da44b6fa60c6bd317b8f219e500595e94e0322b33ec5b4e9f406bedaee555", - "sha256:f890f5611ab8f48b88cfecb716da2ac55aef99e2923198cefcf781842888ea65", - "sha256:ffd3d0ec3d508e592d7ee3885d27fee1f279a49989f734eb130f46d9501273a9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '3.11'", - "version": "==5.15.2.1" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "index": "pypi", - "version": "==1.16.0" - }, - "smbus2": { - "hashes": [ - "sha256:50f3c78e436b42a9583948be06961a8104cf020ebad5edfaaf2657528bef0818", - "sha256:634541ed794068a822fe7499f1577468b9d4641b68dd9bfb6d0eb7270f4d2a32" - ], - "index": "pypi", - "version": "==0.4.2" - }, - "sympy": { - "hashes": [ - "sha256:938f984ee2b1e8eae8a07b884c8b7a1146010040fccddc6539c54f401c8f6fcf", - "sha256:e32380dce63cb7c0108ed525570092fd45168bdae2faa17e528221ef72e88658" - ], - "index": "pypi", - "version": "==1.11.1" - }, - "timezonefinder": { - "hashes": [ - "sha256:96c96db94e75e072187843152e6c5dc0718500a9a91986032365abe09162d0e7", - "sha256:f2ee561b1e7692b933fcd914df38800e93db7caf278e7328de7328829b04f275" - ], - "index": "pypi", - "version": "==6.1.3" - }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" - }, - "tomlkit": { - "hashes": [ - "sha256:25d4e2e446c453be6360c67ddfb88838cfc42026322770ba13d1fbd403a93a5c", - "sha256:3235a9010fae54323e727c3ac06fb720752fe6635b3426e379daec60fbd44a83" - ], - "markers": "python_version >= '3.6' and python_version < '4'", - "version": "==0.11.4" - }, - "tqdm": { - "hashes": [ - "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4", - "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1" - ], - "index": "pypi", - "version": "==4.64.1" - }, - "typing-extensions": { - "hashes": [ - "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", - "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" - ], - "markers": "python_version < '3.10'", - "version": "==4.3.0" - }, - "urllib3": { - "hashes": [ - "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", - "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" - ], - "index": "pypi", - "version": "==1.26.12" - }, - "utm": { - "hashes": [ - "sha256:3c9a3650e98bb6eecec535418d0dfd4db8f88c8ceaca112a0ff0787e116566e2" - ], - "index": "pypi", - "version": "==0.7.0" - }, - "websocket-client": { - "hashes": [ - "sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090", - "sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef" - ], - "index": "pypi", - "version": "==1.4.1" - }, - "werkzeug": { - "hashes": [ - "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", - "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5" - ], - "markers": "python_version >= '3.7'", - "version": "==2.2.2" - }, - "wrapt": { - "hashes": [ - "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3", - "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b", - "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4", - "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2", - "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656", - "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3", - "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff", - "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310", - "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a", - "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57", - "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069", - "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383", - "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe", - "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87", - "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d", - "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b", - "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907", - "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f", - "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0", - "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28", - "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1", - "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853", - "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc", - "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3", - "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3", - "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164", - "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1", - "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c", - "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1", - "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7", - "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1", - "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320", - "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed", - "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1", - "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248", - "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c", - "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456", - "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77", - "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef", - "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1", - "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7", - "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86", - "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4", - "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d", - "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d", - "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8", - "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5", - "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471", - "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00", - "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68", - "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3", - "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d", - "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735", - "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d", - "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569", - "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7", - "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59", - "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5", - "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb", - "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b", - "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f", - "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462", - "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015", - "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af" - ], - "markers": "python_version < '3.11'", - "version": "==1.14.1" - }, - "zipp": { - "hashes": [ - "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", - "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009" - ], - "markers": "python_version >= '3.7'", - "version": "==3.8.1" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" - ], - "version": "==0.7.12" - }, - "attrs": { - "hashes": [ - "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6", - "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c" - ], - "markers": "python_version >= '3.5'", - "version": "==22.1.0" - }, - "av": { - "hashes": [ - "sha256:0340cc68f3d222bc9438b4fde12e3d68f949eeb5de9e090db182f2cb06e23d53", - "sha256:0d9cad890e6eccf2697b1c932761bee6f5e1e7faf9b8c03cf10f18f697d29ba3", - "sha256:109526152e658921731018c50a05db802e7c9f3eb04a7a5fcbd8321fb3b73134", - "sha256:17a7b6617d4201214f3dd5f628041b4fe56f4244dcd48399ed8d0cf324ca24d1", - "sha256:1cbf031f650f89943023eef80e8b2c99588bf9ba26ffef8b3b54bef7102ea3dc", - "sha256:1e2a50a146b3f33a24ea059af913ad368dbb61ed494234debe140a09f1076950", - "sha256:24dac414eafcc20423f2ec7e873706489433648f0e9af08a537996880aa55979", - "sha256:28d85b8476f7d8fb18e3af9bd6d22bb292f1d810a20f8910fe481f648372e798", - "sha256:29373aa86a055a07eebb14d253cb202033f63ba98c5a4b0233d6d4c07fc7a292", - "sha256:2b46b54ddf64409d4455f408b5970f8494c27c0273181b81c2f7d5072c9afb55", - "sha256:343b11d9b03e71da29f3ce56bc0a6c2d40aba448225dcf8296ab53c10527fff0", - "sha256:3ea180bfd89bc0a9e392c32de204cf4e51648aefe2f375d430ce39c04e3ed625", - "sha256:3facfe8dc5ba7f9ec7fd7e4c0466e577b84d5f2a1671428f7e28ebcd2cb0ccd3", - "sha256:45816a39255b39e514a72125e0b6e29eb24fe0994bef3f4f87f3b9d9960b3fa8", - "sha256:48819e401cea5be57bd03299d8e5f700082c411746d1ac23eb5e5a931d3d3ced", - "sha256:49481c2d5bc296f451ccd3f93b1cb692d7f58a804b794b99c8b7743e058cae71", - "sha256:587dd492a2ef3eb20324a0a8d67e6a2e686845d8c1dfdcad058377ac84268d67", - "sha256:6a1c2c1dcc1947473ea1e2cbbf50549e2655e49e08bdd2a6427a97276d7a92c8", - "sha256:6b01fbe8047da81892f8bd2aee5690f00465bf5215e3f6b6372863ac9408d75f", - "sha256:7a5dc26b9df656bed5e1bdeaf8bcc4ff4a2e009ee90b3b3024a86cf8476b2cbf", - "sha256:8671fa01648ce7aac76e71816c2421ddb1939bf706e2e14684608ab1ce9dbbbb", - "sha256:9b0f124e335561cf4de6b7cdc461283c5eba5f05cccb1a5e1b8ceb1cd15393d8", - "sha256:a616a6eb46b62f41ff69569cafe12b0005a6dd14389f597dee115340336a910f", - "sha256:a6a35e6028dec677caed97d19bfab3b66182690d43b0ec3c355778d740ce0509", - "sha256:a9983bc45dab65d2416d2f8a63785caa076a751590823fc8c199617d0dbad390", - "sha256:ab90aa3ac2cbdf1f22087fc0fa439f643e96979f169ecfa1d496e114c3c3a8b3", - "sha256:af951271d998f736a20e54fbc0d944f263db7b17592f11cd489947957bf46aa8", - "sha256:b07b91f534ee7a096068149404c67c3c0e5b4c373580b016151de0fcb440cd3f", - "sha256:b6be9388618af978304b56d1cf6b74c811db4f220dd320da5bd79640aa443358", - "sha256:ba3d9e3fe23fd8a14e810f291386225acbdef1c7e5376cc10c8e85c2d4280771", - "sha256:bf941896b4c800ee707211c802f94c6e0b4642d3000e25d1974d0b6032af4f66", - "sha256:d080f34ddfde551de3a5f2d0d06d7518718e3115af81e56182e158cc03111662", - "sha256:d380925732e7497c1c11545107eabe1f498cab214f49f32d1b5d6abe01a2b36b", - "sha256:d6a3c9126d658029b151484b48c656b73af1b145b143c50de5b8b983ac60e095", - "sha256:d730f3ed30eda46d06849bd71ad87d480cf0cad9fd064f33a0386dee95461e31", - "sha256:e3e4a28fa0eabd3ab5b0915e9c005e9155039f9e1a4466212434c40eb69a33fb", - "sha256:e59e4ab0e8832bf87707e5024283b3a24cc01784604f0b0e96fbfbadbd8d9fc0", - "sha256:f2a7c226724d7f7745b376b459c500d9d17bd8d0473b7ea6bf8ddb4f7957c69d" - ], - "index": "pypi", - "version": "==9.2.0" - }, - "azure-common": { - "hashes": [ - "sha256:4ac0cd3214e36b6a1b6a442686722a5d8cc449603aa833f3f0f40bda836704a3", - "sha256:5c12d3dcf4ec20599ca6b0d3e09e86e146353d443e7fcc050c9a19c1f9df20ad" - ], - "version": "==1.1.28" - }, - "azure-storage-blob": { - "hashes": [ - "sha256:a8e91a51d4f62d11127c7fd8ba0077385c5b11022f0269f8a2a71b9fc36bef31", - "sha256:b90323aad60f207f9f90a0c4cf94c10acc313c20b39403398dfba51f25f7b454" - ], - "index": "pypi", - "version": "==2.1.0" - }, - "azure-storage-common": { - "hashes": [ - "sha256:b01a491a18839b9d05a4fe3421458a0ddb5ab9443c14e487f40d16f9a1dc2fbe", - "sha256:ccedef5c67227bc4d6670ffd37cec18fb529a1b7c3a5e53e4096eb0cf23dc73f" - ], - "version": "==2.1.0" - }, - "babel": { - "hashes": [ - "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51", - "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb" - ], - "markers": "python_version >= '3.6'", - "version": "==2.10.3" - }, - "bcrypt": { - "hashes": [ - "sha256:0b0f0c7141622a31e9734b7f649451147c04ebb5122327ac0bd23744df84be90", - "sha256:1c3334446fac200499e8bc04a530ce3cf0b3d7151e0e4ac5c0dddd3d95e97843", - "sha256:2d0dd19aad87e4ab882ef1d12df505f4c52b28b69666ce83c528f42c07379227", - "sha256:594780b364fb45f2634c46ec8d3e61c1c0f1811c4f2da60e8eb15594ecbf93ed", - "sha256:7c7dd6c1f05bf89e65261d97ac3a6520f34c2acb369afb57e3ea4449be6ff8fd", - "sha256:845b1daf4df2dd94d2fdbc9454953ca9dd0e12970a0bfc9f3dcc6faea3fa96e4", - "sha256:8780e69f9deec9d60f947b169507d2c9816e4f11548f1f7ebee2af38b9b22ae4", - "sha256:bf413f2a9b0a2950fc750998899013f2e718d20fa4a58b85ca50b6df5ed1bbf9", - "sha256:bfb67f6a6c72dfb0a02f3df51550aa1862708e55128b22543e2b42c74f3620d7", - "sha256:c59c170fc9225faad04dde1ba61d85b413946e8ce2e5f5f5ff30dfd67283f319", - "sha256:dc6ec3dc19b1c193b2f7cf279d3e32e7caf447532fbcb7af0906fe4398900c33", - "sha256:ede0f506554571c8eda80db22b83c139303ec6b595b8f60c4c8157bdd0bdee36" - ], - "markers": "python_version >= '3.6'", - "version": "==4.0.0" - }, - "breathe": { - "hashes": [ - "sha256:48804dcf0e607a89fb6ad88c729ef12743a42db03ae9489be4ef8f7c4011774a", - "sha256:ac0768a5e84addad3e632028fe67749c567aba2b29088493b64c2c1634bcdba1" - ], - "index": "pypi", - "version": "==4.34.0" - }, - "carla": { - "hashes": [ - "sha256:1210cce213e968a644effd4e2e48458a072481459d073424b05725056ba3d77d", - "sha256:339fcb1e392f3ade1be82b7258de19c533e2efae111e954a6eb174efb296903d", - "sha256:5f065825ce812343bf27a80a19d647b3200b31b44a9e80cea0340e3bd20cdf81", - "sha256:954ca34d5bdd4516ceca353db907fee8cec6630d6b31a732b17dd1554e0f0f94", - "sha256:a64ee78fe91137fa7d4828c7fc06d5824bd7312e29e4ea4f31a5d74dd28bff40", - "sha256:a95d2d4218ea388c863c66b7c2ab3fe49ffefe53999305cfcb6a8107042f79af", - "sha256:d2bfaea2d6824a2d758cbe813856c69420494f5c97d2a2dfb45653ccf976f1ce" - ], - "index": "pypi", - "markers": "platform_system != 'Darwin'", - "version": "==0.9.13" - }, - "certifi": { - "hashes": [ - "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", - "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" - ], - "markers": "python_version >= '3.6'", - "version": "==2022.9.24" - }, - "cffi": { - "hashes": [ - "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", - "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", - "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", - "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", - "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", - "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", - "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", - "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", - "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", - "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", - "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", - "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", - "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", - "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", - "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", - "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", - "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", - "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", - "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", - "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", - "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", - "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", - "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", - "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", - "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", - "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", - "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", - "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", - "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", - "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", - "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", - "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", - "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", - "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", - "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", - "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", - "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", - "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", - "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", - "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", - "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", - "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", - "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", - "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", - "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", - "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", - "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", - "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", - "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", - "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", - "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", - "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", - "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", - "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", - "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", - "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", - "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", - "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", - "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", - "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", - "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", - "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", - "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", - "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" - ], - "index": "pypi", - "version": "==1.15.1" - }, - "cfgv": { - "hashes": [ - "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", - "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736" - ], - "markers": "python_full_version >= '3.6.1'", - "version": "==3.3.1" - }, - "charset-normalizer": { - "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.1" - }, - "contourpy": { - "hashes": [ - "sha256:0389349875424aa8c5e61f757e894687916bc4e9616cc6afcbd8051aa2428952", - "sha256:0395ae71164bfeb2dedd136e03c71a2718a5aa9873a46f518f4133be0d63e1d2", - "sha256:057114f698ffb9e54657e8fda6802e2f5c8fad609845cf6afaf31590ef6a33c0", - "sha256:061e1f066c419ffe25b615a1df031b4832ea1d7f2676937e69e8e00e24512005", - "sha256:06c4d1dde5ee4f909a8a95ba1eb04040c6c26946b4f3b5beaf10d45f14e940ee", - "sha256:09ed9b63f4df8a7591b7a4a26c1ad066dcaafda1f846250fdcb534074a411692", - "sha256:0f7672148f8fca48e4efc16aba24a7455b40c22d4f8abe42475dec6a12b0bb9a", - "sha256:0f89f0608a5aa8142ed0e53957916623791a88c7f5e5f07ae530c328beeb888f", - "sha256:128bd7acf569f8443ad5b2227f30ac909e4f5399ed221727eeacf0c6476187e6", - "sha256:19ea64fa0cf389d2ebc10974616acfa1fdecbd73d1fd9c72215b782f3c40f561", - "sha256:1fb782982c42cee667b892a0b0c52a9f6c7ecf1da5c5f4345845f04eaa862f93", - "sha256:218722a29c5c26677d37c44f5f8a372daf6f07870aad793a97d47eb6ad6b3290", - "sha256:2b5e334330d82866923015b455260173cb3b9e3b4e297052d758abd262031289", - "sha256:2bf5c846c257578b03d498b20f54f53551616a507d8e5463511c58bb58e9a9cf", - "sha256:2d0ad9a85f208473b1f3613c45756c7aa6fcc288266a8c7b873f896aaf741b6b", - "sha256:2f54dcc9bb9390fd0636301ead134d46d5229fe86da0db4d974c0fda349f560e", - "sha256:3109fa601d2a448cec4643abd3a31f972bf05b7c2f2e83df9d3429878f8c10ae", - "sha256:3210d93ad2af742b6a96cf39792f7181822edbb8fe11c3ef29d1583fe637a8d8", - "sha256:3b3082ade8849130203d461b98c2a061b382c46074b43b4edd5cefd81af92b8a", - "sha256:3c3f2f6b898a40207843ae01970e57e33d22a26b22f23c6a5e07b4716751085f", - "sha256:3ca40d7844b391d90b864c6a6d1bb6b88b09035fb4d866d64d43c4d26fb0ab64", - "sha256:3cfc067ddde78b76dcbc9684d82688b7d3c5158fa2254a085f9bcb9586c1e2d8", - "sha256:434942fa2f9019b9ae525fb752dc523800c49a1a28fbd6d9240b0fa959573dcc", - "sha256:46b8e24813e2fb5a3e598c1f8b9ae403e1438cb846a80cc2b33cddf19dddd7f2", - "sha256:59c827e536bb5e3ef58e06da0faba61fd89a14f30b68bcfeca41f43ca83a1942", - "sha256:60f37acd4e4227c5a29f737d9a85ca3145c529a8dd4bf70af7f0637c61b49222", - "sha256:689d7d2a840619915d0abd1ecc6e399fee202f8ad315acda2807f4ca420d0802", - "sha256:6c02e22cf09996194bcb3a4784099975cf527d5c29caf759abadf29ebdb2fe27", - "sha256:79908b9d02b1d6c1c71ff3b7ad127f3f82e14a8e091ab44b3c7e34b649fea733", - "sha256:7c9e99aac7b430f6a9f15eebf058c742097cea3369f23a2bfc5e64d374b67e3a", - "sha256:813c2944e940ef8dccea71305bacc942d4b193a021140874b3e58933ec44f5b6", - "sha256:87121b9428ac568fb84fae4af5e7852fc34f02eadc4e3e91f6c8989327692186", - "sha256:896631cd40222aef3697e4e51177d14c3709fda49d30983269d584f034acc8a4", - "sha256:970a4be7ec84ccda7c27cb4ae74930bbbd477bc8d849ed55ea798084dd5fca8c", - "sha256:9939796abcadb2810a63dfb26ff8ca4595fe7dd70a3ceae7f607a2639b714307", - "sha256:99a8071e351b50827ad976b92ed91845fb614ac67a3c41109b24f3d8bd3afada", - "sha256:9c16fa267740d67883899e054cccb4279e002f3f4872873b752c1ba15045ff49", - "sha256:a30e95274f5c0e007ccc759ec258aa5708c534ec058f153ee25ac700a2f1438b", - "sha256:a74afd8d560eaafe0d9e3e1db8c06081282a05ca4de00ee416195085a79d7d3d", - "sha256:b46a04588ceb7cf132568e0e564a854627ef87a1ed3bf536234540a79ced44b0", - "sha256:b4963cf08f4320d98ae72ec7694291b8ab85cb7da3b0cd824bc32701bc992edf", - "sha256:b50e481a4317a8efcfffcfddcd4c9b36eacba440440e70cbe0256aeb6fd6abae", - "sha256:b85553699862c09937a7a5ea14ee6229087971a7d51ae97d5f4b407f571a2c17", - "sha256:bcc98d397c3dea45d5b262029564b29cb8e945f2607a38bee6163694c0a8b4ef", - "sha256:bed3a2a823a041e8d249b1a7ec132933e1505299329b5cfe1b2b5ec689ec7675", - "sha256:bf6b4c0c723664f65c2a47c8cb6ebbf660b0b2e2d936adf2e8503d4e93359465", - "sha256:bfd634cb9685161b2a51f73a7fc4736fd0d67a56632d52319317afaa27f08243", - "sha256:c0d5ee865b5fd16bf62d72122aadcc90aab296c30c1adb0a32b4b66bd843163e", - "sha256:c2b4eab7c12f9cb460509bc34a3b086f9802f0dba27c89a63df4123819ad64af", - "sha256:c51568e94f7f232296de30002f2a50f77a7bd346673da3e4f2aaf9d2b833f2e5", - "sha256:c5158616ab39d34b76c50f40c81552ee180598f7825dc7a66fd187d29958820f", - "sha256:cdacddb18d55ffec42d1907079cdc04ec4fa8a990cdf5b9d9fe67d281fc0d12e", - "sha256:ce763369e646e59e4ca2c09735cd1bdd3048d909ad5f2bc116e83166a9352f3c", - "sha256:d45822b0a2a452327ab4f95efe368d234d5294bbf89a99968be27c7938a21108", - "sha256:d8150579bf30cdf896906baf256aa200cd50dbe6e565c17d6fd3d678e21ff5de", - "sha256:d88814befbd1433152c5f6dd536905149ba028d795a22555b149ae0a36024d9e", - "sha256:dca5be83a6dfaf933a46e3bc2b9f2685e5ec61b22f6a38ad740aac9c16e9a0ff", - "sha256:dd084459ecdb224e617e4ab3f1d5ebe4d1c48facb41f24952b76aa6ba9712bb0", - "sha256:def9a01b73c9e27d70ea03b381fb3e7aadfac1f398dbd63751313c3a46747ef5", - "sha256:df65f4b2b4e74977f0336bef12a88051ab24e6a16873cd9249f34d67cb3e345d", - "sha256:dfe924e5a63861c82332a12adeeab955dc8c8009ddbbd80cc2fcca049ff89a49", - "sha256:e67dcaa34dcd908fcccbf49194211d847c731b6ebaac661c1c889f1bf6af1e44", - "sha256:eba62b7c21a33e72dd8adab2b92dd5610d8527f0b2ac28a8e0770e71b21a13f9", - "sha256:ed9c91bf4ce614efed5388c3f989a7cfe08728ab871d995a486ea74ff88993db", - "sha256:f05d311c937da03b0cd26ac3e14cb991f6ff8fc94f98b3df9713537817539795", - "sha256:f1cc623fd6855b25da52b3275e0c9e51711b86a9dccc75f8c9ab4432fd8e42c7", - "sha256:f670686d99c867d0f24b28ce8c6f02429c6eef5e2674aab287850d0ee2d20437", - "sha256:f856652f9b533c6cd2b9ad6836a7fc0e43917d7ff15be46c5baf1350f8cdc5d9", - "sha256:fb0458d74726937ead9e2effc91144aea5a58ecee9754242f8539a782bed685a" - ], - "markers": "python_version >= '3.7'", - "version": "==1.0.5" - }, - "control": { - "hashes": [ - "sha256:0891d2d32d6006ac1faa4e238ed8223ca342a4721d202dfeccae24fb02563183" - ], - "index": "pypi", - "version": "==0.9.2" - }, - "coverage": { - "hashes": [ - "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2", - "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820", - "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827", - "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3", - "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d", - "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145", - "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875", - "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2", - "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74", - "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f", - "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c", - "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973", - "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1", - "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782", - "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0", - "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760", - "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a", - "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3", - "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7", - "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a", - "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f", - "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e", - "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86", - "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa", - "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa", - "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796", - "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a", - "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928", - "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0", - "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac", - "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c", - "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685", - "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d", - "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e", - "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f", - "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558", - "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58", - "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781", - "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a", - "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa", - "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc", - "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892", - "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d", - "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817", - "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1", - "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c", - "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908", - "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19", - "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60", - "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b" - ], - "index": "pypi", - "version": "==6.4.4" - }, - "cryptography": { - "hashes": [ - "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a", - "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f", - "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0", - "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407", - "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7", - "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6", - "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153", - "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750", - "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad", - "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6", - "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b", - "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5", - "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a", - "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d", - "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d", - "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294", - "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0", - "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a", - "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac", - "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61", - "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013", - "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e", - "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb", - "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9", - "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd", - "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818" - ], - "index": "pypi", - "version": "==38.0.1" - }, - "cycler": { - "hashes": [ - "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3", - "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f" - ], - "markers": "python_version >= '3.6'", - "version": "==0.11.0" - }, - "dictdiffer": { - "hashes": [ - "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578", - "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595" - ], - "index": "pypi", - "version": "==0.9.0" - }, - "distlib": { - "hashes": [ - "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46", - "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e" - ], - "version": "==0.3.6" - }, - "docutils": { - "hashes": [ - "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125", - "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.17.1" - }, - "execnet": { - "hashes": [ - "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5", - "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.9.0" - }, - "fastcluster": { - "hashes": [ - "sha256:03f8efe6435a7b947fa4a420676942d0267dac0d323ec5ead50f1856cc7cf96f", - "sha256:060c1cb3c84942d8d3618385e2c25998ba690c46ec8c73d64477f808abfac3f2", - "sha256:06df1d97edca68b2ffa43d81c3b5f4e4147bc12ab241c6585fadcdeb0bfa23ca", - "sha256:0bb54283b4d5ec96f167c7fd31921f169226c1261637434fdae7a69ee3c69573", - "sha256:11748a4e245c745030e9ddd8c2c37e378f8ad8bd8e869d954c84ff674495499f", - "sha256:1801c9daa9aa5bbbb0830efe8bd3034b4b7a417e4b8dd353683999be29797df2", - "sha256:2fcb0973ca0e6978e3242046338c350cbed1493108929231fae9bd35ad05a6d6", - "sha256:4093d5454bcbe48b30e32da5db43056a08889480a96e4555f28c1f7004fc5323", - "sha256:4b9cfd426966b8037bec2fc03a0d7a9c87313482c699b36ffa1432b49f84ed2e", - "sha256:58958a0333e3dfbad198394e9b7dd6254de0a3e622019b057288405b2a4a6bba", - "sha256:5fe543b6d45da27e84e5af6248722475b88943d8ef40d835cbabbb0ba5ee786b", - "sha256:6a7c7f51a6d2f5ab58b1d85e9d0af2af9600ec13bb43bc6aafc9085d2c4ccd93", - "sha256:6cf156d4203708348522393c523c2e61c81f5a6a500e0411dcba2b064551ea2f", - "sha256:6e51db0067e65687a5c46f00a11843d0bb15ca759e8a1767eebac8c4f6e3f4df", - "sha256:72503e727887a61a15f9aaa13178798d3994dfec58aa7a943e42dcfda07c0149", - "sha256:7254f81dc71cd29ef6f2d9747cf97ff907b569c9ef9d9760352391be5b57118c", - "sha256:855ab2b7e6fa9b05f19c4f3023dedfb1a35a88d831933d65d0d9e10a070a9e85", - "sha256:86a1ad972e83ba48144884fa849f87626346308b650002157123aee67d3b16fe", - "sha256:8bac5cf64691060cf86b0752dd385ef1eccff6d24bdb8b60691cf8cbf0e4f9ef", - "sha256:8d3c9eab8e69cb36dcdd64c8b3200e008aedf88e34d39e01ae6af98a9605ad18", - "sha256:9020899b67fe492d0ed87a3e993ec9962c5a0b51ea2df71d86b1766f065f1cef", - "sha256:a085e7e13f1afc517358981b2b7ed774dc9abf95f2be0da9a495d9e6b58c4409", - "sha256:a5ceb39379327316d34613f7c16c06d7a3816aa38f4437b5e8433aa1bf149e2c", - "sha256:a6f8da329c0032f2acaf4beaef958a2db0dae43d3f946f592dad5c29aa82c832", - "sha256:a952a84453123db0c2336b9a9c86162e99ad0b897bae8213107c055a64effd41", - "sha256:aa4a4c01c5fbec3623e92bc33a9f712ca416ce93255c402f5c904ac4b890ac3c", - "sha256:aab886efa7b6bba7ac124f4498153d053e5a08b822d2254926b7206cdf5a8aa6", - "sha256:ab9337b0a6a9b07b6f86fc724972d1ad729c890e2f539c1b33271c2f1f00af8b", - "sha256:c12224da0b1f2f9d2b3d715dc82ecb1a3a33b990606f97da075cc46bc6d9576f", - "sha256:c61be0bad81a21ee3e5bef91469fdd11968f33d41d142c656accba9b2992babe", - "sha256:c8be01f97bc2bf11a9188537864f8e520e1103cdc6007aa2c5d7979b1363b121", - "sha256:cb27c13225f5f77f3c5986a27ca27277cce7db12844330cf535019cd38021257", - "sha256:cf5acfe1156849279ebd44a8d1fbcbe8b8e21334f7538eda782ae31e7dade9e2", - "sha256:d0e8faef0437a25fd083df70fb86cc65ce3c9c9780d4ae377cbe6521e7746ce0", - "sha256:e03a228e018457842eb81de85be7af0b5fe8065d666dd093193e3bdcf1f13d2e", - "sha256:eb3f98791427d5d5d02d023b66bcef61e48954edfadae6527ef72d70cf32ec86", - "sha256:ffdb00782cd63bbf2c45bb048897531e868326dff5081ab9b752d294b0426c1d" - ], - "index": "pypi", - "version": "==1.2.6" - }, - "filelock": { - "hashes": [ - "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc", - "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4" - ], - "markers": "python_version >= '3.7'", - "version": "==3.8.0" - }, - "fonttools": { - "hashes": [ - "sha256:a5bc5f5d48faa4085310b8ebd4c5d33bf27c6636c5f10a7de792510af2745a81", - "sha256:f32ef6ec966cf0e7d2aa88601fed2e3a8f2851c26b5db2c80ccc8f82bee4eedc" - ], - "markers": "python_version >= '3.7'", - "version": "==4.37.3" - }, - "ft4222": { - "hashes": [ - "sha256:074f4eb234450306b9040d721eb5ab2a423d3b07d6f4a30824198afeb0a9bbb6", - "sha256:09f18a5610d0d81c568c9095798f542166b98025d119c9fa91555fa5bfddc2ee", - "sha256:0cceacb43d75a5cb3cdf2d95d4164fb2c1cfde007d9782538150bc10d7933680", - "sha256:10136015000719f68b2a4b319b612183a1601816870521e6a45c8c0b67d38325", - "sha256:1894469abffd739fc3a83f818ea29532283965c74c3c64e5c9b9e6b454971d03", - "sha256:24cdb72a7cd420c1ed009c0821555b9818b8828dc31a1a01224a35d4757c7e5d", - "sha256:286a2f3c023e9beb5c6ca6b692c3ed92a1fe44b326f7cb58807d0b99f372c7d7", - "sha256:28b472bbbb18e6f65dacd139231a53640827f2e486c54750fbcff7a16454cb6d", - "sha256:296555ca4096b5ce13e79b089622de5cf9236f3d32b074c8483ae72490e7448b", - "sha256:396f5c7c38e0c8dc1b31d5d9709d7eb86ef0ee75412867ccc352506aa3a29ae4", - "sha256:39a7d8795d32b8c126ed253a0c1a9d7971f3af83d2ceb796af47fbef03485741", - "sha256:50e37f59b8e553384cdbfab64096e3fb1c7ca9f15ae419ae0d0fdda3a2e05f54", - "sha256:511b785a23ba2fc8480dbaeda33e1f22ffe5dd58731e1c53e379989731fb42ad", - "sha256:5f91e530ee6fe6a13c08ec4dc3c7f54a704fc642b3d73f4392a9db22c5e243dd", - "sha256:65e5b7bfbe3552b771770807df0a251616bb2c8f7541e4e9f350715f225a71c0", - "sha256:6e208af13621b8a79a8c623c8deb3b971f4d4e4587156622a6558b91719f9d33", - "sha256:70aec6df75d1f8ee051c5d16a48363e4d3552feecf3466cec2700415c073e5e4", - "sha256:9670396daab3deb91847ee40c0338bca07f4041176b2aed1c49277dc1ef3497f", - "sha256:a300c2749adb674ef3d95b17a1311deaf0a3318e14ee7e9d7e56317e307b0012", - "sha256:a675b88124dfb1d2744f27823e3dfd094c0236674e453e83d486fc17358761ff", - "sha256:ab5ea9522bd0fd1b87348bf26d0a1131e87f586366271581c9b1d0acdf870173", - "sha256:baf80af3de3af376080bfb8f75f3d6aba9e9415001a6f72299cbb344e6b739cb", - "sha256:bb3cb6485d7a0d1eac0e0027eab6b9ec95e5f5722e853cdc2850d2ae70086eea", - "sha256:c5a993dd3af47ab69f5b58920dba15c98658de7a73b9c81d402fe6eaf292edab", - "sha256:c7e31cefcdcfe3653df35cd993f821b746e747b294ded8bff27d1f8bd8c5e43b", - "sha256:caec2458db0d8e29888da2c22aa4427c1d993e943ed325ef7a6b8eb24f55d163", - "sha256:d688830cf004cde39b3cc757fef8ec31ae266fceda1566ca53b3b79e5ab7b6e4" - ], - "index": "pypi", - "version": "==1.5.0" - }, - "hexdump": { - "hashes": [ - "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db" - ], - "index": "pypi", - "version": "==3.3" - }, - "hypothesis": { - "hashes": [ - "sha256:2696cdb9005946bf1d2b215cc91d3fc01625e3342eb8743ddd04b667b2f1882b", - "sha256:4ad26c5d434171ffc02aba569dd52255573d615554c062bc30734dbe6f318c61", - "sha256:69978811f1d9c19710c7d2bf8233dc43c80efa964251b72efbe8274044e073b4", - "sha256:967009fa561b3a3f8363a73d71923357271c37dc7fa27b30c2d21a1b6092b240" - ], - "index": "pypi", - "version": "==6.46.7" - }, - "identify": { - "hashes": [ - "sha256:322a5699daecf7c6fd60e68852f36f2ecbb6a36ff6e6e973e0d2bb6fca203ee6", - "sha256:ef78c0d96098a3b5fe7720be4a97e73f439af7cf088ebf47b620aeaa10fadf97" - ], - "markers": "python_version >= '3.7'", - "version": "==2.5.5" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "imagesize": { - "hashes": [ - "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", - "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.4.1" - }, - "importlib-metadata": { - "hashes": [ - "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", - "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" - ], - "markers": "python_version < '3.10'", - "version": "==4.12.0" - }, - "iniconfig": { - "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" - ], - "version": "==1.1.1" - }, - "inputs": { - "hashes": [ - "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec", - "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4" - ], - "index": "pypi", - "version": "==0.5" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "index": "pypi", - "version": "==3.1.2" - }, - "kiwisolver": { - "hashes": [ - "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b", - "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166", - "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c", - "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c", - "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0", - "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4", - "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9", - "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286", - "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767", - "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c", - "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6", - "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b", - "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004", - "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf", - "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494", - "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac", - "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626", - "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766", - "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514", - "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6", - "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f", - "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d", - "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191", - "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d", - "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51", - "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f", - "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8", - "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454", - "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb", - "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da", - "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8", - "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de", - "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a", - "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9", - "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008", - "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3", - "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32", - "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938", - "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1", - "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9", - "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d", - "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824", - "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b", - "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd", - "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2", - "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5", - "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69", - "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3", - "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae", - "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597", - "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e", - "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955", - "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca", - "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a", - "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea", - "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede", - "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4", - "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6", - "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686", - "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408", - "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871", - "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29", - "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750", - "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897", - "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0", - "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2", - "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09", - "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c" - ], - "markers": "python_version >= '3.7'", - "version": "==1.4.4" - }, - "lru-dict": { - "hashes": [ - "sha256:075b9dd46d7022b675419bc6e3631748ae184bc8af195d20365a98b4f3bb2914", - "sha256:0972d669e9e207617e06416166718b073a49bf449abbd23940d9545c0847a4d9", - "sha256:0f83cd70a6d32f9018d471be609f3af73058f700691657db4a3d3dd78d3f96dd", - "sha256:10fe823ff90b655f0b6ba124e2b576ecda8c61b8ead76b456db67831942d22f2", - "sha256:163079dbda54c3e6422b23da39fb3ecc561035d65e8496ff1950cbdb376018e1", - "sha256:1fe16ade5fd0a57e9a335f69b8055aaa6fb278fbfa250458e4f6b8255115578f", - "sha256:262a4e622010ceb960a6a5222ed011090e50954d45070fd369c0fa4d2ed7d9a9", - "sha256:2f340b61f3cdfee71f66da7dbfd9a5ea2db6974502ccff2065cdb76619840dca", - "sha256:348167f110494cfafae70c066470a6f4e4d43523933edf16ccdb8947f3b5fae0", - "sha256:3b1692755fef288b67af5cd8a973eb331d1f44cb02cbdc13660040809c2bfec6", - "sha256:3ca497cb25f19f24171f9172805f3ff135b911aeb91960bd4af8e230421ccb51", - "sha256:3d003a864899c29b0379e412709a6e516cbd6a72ee10b09d0b33226343617412", - "sha256:3fef595c4f573141d54a38bda9221b9ee3cbe0acc73d67304a1a6d5972eb2a02", - "sha256:484ac524e4615f06dc72ffbfd83f26e073c9ec256de5413634fbd024c010a8bc", - "sha256:55aeda6b6789b2d030066b4f5f6fc3596560ba2a69028f35f3682a795701b5b1", - "sha256:5a592363c93d6fc6472d5affe2819e1c7590746aecb464774a4f67e09fbefdfc", - "sha256:5b09dbe47bc4b4d45ffe56067aff190bc3c0049575da6e52127e114236e0a6a7", - "sha256:6e2a7aa9e36626fb48fdc341c7e3685a31a7b50ea4918677ea436271ad0d904d", - "sha256:70364e3cbef536adab8762b4835e18f5ca8e3fddd8bd0ec9258c42bbebd0ee77", - "sha256:720f5728e537f11a311e8b720793a224e985d20e6b7c3d34a891a391865af1a2", - "sha256:7284bdbc5579bbdc3fc8f869ed4c169f403835566ab0f84567cdbfdd05241847", - "sha256:7be1b66926277993cecdc174c15a20c8ce785c1f8b39aa560714a513eef06473", - "sha256:86d32a4498b74a75340497890a260d37bf1560ad2683969393032977dd36b088", - "sha256:878bc8ef4073e5cfb953dfc1cf4585db41e8b814c0106abde34d00ee0d0b3115", - "sha256:881104711900af45967c2e5ce3e62291dd57d5b2a224d58b7c9f60bf4ad41b8c", - "sha256:8c50ab9edaa5da5838426816a2b7bcde9d576b4fc50e6a8c062073dbc4969d78", - "sha256:8f6561f9cd5a452cb84905c6a87aa944fdfdc0f41cc057d03b71f9b29b2cc4bd", - "sha256:93336911544ebc0e466272043adab9fb9f6e9dcba6024b639c32553a3790e089", - "sha256:9447214e4857e16d14158794ef01e4501d8fad07d298d03308d9f90512df02fa", - "sha256:97c24ffc55de6013075979f440acd174e88819f30387074639fb7d7178ca253e", - "sha256:99f6cfb3e28490357a0805b409caf693e46c61f8dbb789c51355adb693c568d3", - "sha256:9be6c4039ef328676b868acea619cd100e3de1a35b3be211cf0eaf9775563b65", - "sha256:9d70257246b8207e8ef3d8b18457089f5ff0dfb087bd36eb33bce6584f2e0b3a", - "sha256:a777d48319d293b1b6a933d606c0e4899690a139b4c81173451913bbcab6f44f", - "sha256:add762163f4af7f4173fafa4092eb7c7f023cf139ef6d2015cfea867e1440d82", - "sha256:b6f64005ede008b7a866be8f3f6274dbf74e656e15e4004e9d99ad65efb01809", - "sha256:beb089c46bd95243d1ac5b2bd13627317b08bf40dd8dc16d4b7ee7ecb3cf65ca", - "sha256:c07163c9dcbb2eca377f366b1331f46302fd8b6b72ab4d603087feca00044bb0", - "sha256:c2fe692332c2f1d81fd27457db4b35143801475bfc2e57173a2403588dd82a42", - "sha256:ca8f89361e0e7aad0bf93ae03a31502e96280faeb7fb92267f4998fb230d36b2", - "sha256:d2ed4151445c3f30423c2698f72197d64b27b1cd61d8d56702ffe235584e47c2", - "sha256:db20597c4e67b4095b376ce2e83930c560f4ce481e8d05737885307ed02ba7c1", - "sha256:de972c7f4bc7b6002acff2a8de984c55fbd7f2289dba659cfd90f7a0f5d8f5d1", - "sha256:f1df1da204a9f0b5eb8393a46070f1d984fa8559435ee790d7f8f5602038fc00", - "sha256:f4d0a6d733a23865019b1c97ed6fb1fdb739be923192abf4dbb644f697a26a69", - "sha256:f874e9c2209dada1a080545331aa1277ec060a13f61684a8642788bf44b2325f", - "sha256:f877f53249c3e49bbd7612f9083127290bede6c7d6501513567ab1bf9c581381", - "sha256:f9d5815c0e85922cd0fb8344ca8b1c7cf020bf9fc45e670d34d51932c91fd7ec" - ], - "index": "pypi", - "version": "==1.1.8" - }, - "lxml": { - "hashes": [ - "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318", - "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c", - "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b", - "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000", - "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73", - "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d", - "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb", - "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8", - "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2", - "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345", - "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94", - "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e", - "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b", - "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc", - "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a", - "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9", - "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc", - "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387", - "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb", - "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7", - "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4", - "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97", - "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67", - "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627", - "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7", - "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd", - "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3", - "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7", - "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130", - "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b", - "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036", - "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785", - "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca", - "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91", - "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc", - "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536", - "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391", - "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3", - "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d", - "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21", - "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3", - "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d", - "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29", - "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715", - "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed", - "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25", - "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c", - "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785", - "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837", - "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4", - "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b", - "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2", - "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067", - "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448", - "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d", - "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2", - "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc", - "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c", - "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5", - "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84", - "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8", - "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf", - "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7", - "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e", - "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb", - "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b", - "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3", - "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad", - "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8", - "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f" - ], - "index": "pypi", - "version": "==4.9.1" - }, - "markdown-it-py": { - "hashes": [ - "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27", - "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da" - ], - "index": "pypi", - "version": "==2.1.0" - }, - "markupsafe": { - "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.1" - }, - "matplotlib": { - "hashes": [ - "sha256:0958fc3fdc59c1b716ee1a5d14e73d03d541d873241a37c5c3a86f7ef6017923", - "sha256:0ae1b9b555212c1e242666af80e7ed796705869581e2d749971db4e682ccc1f3", - "sha256:11c1987b803cc2b26725659cfe817478f0a9597878e5c4bf374cfe4e12cbbd79", - "sha256:140316427a7c384e3dd37efb3a73cd67e14b0b237a6d277def91227f43cdcec2", - "sha256:1559213b803959a2b8309122585b5226d1c2fb66c933b1a2094cf1e99cb4fb90", - "sha256:16a899b958dd76606b571bc7eaa38f09160c27dfb262e493584644cfd4a77f0f", - "sha256:1739935d293d0348d7bf662e8cd0edb9c2aa8f20ccd646db755ce0f3456d24e4", - "sha256:1a4835c177821f3729be27ae9be7b8ae209fe75e83db7d9b2bfd319a998f0a42", - "sha256:2b60d4abcb6a405ca7d909c80791b00637d22c62aa3bb0ffff7e589f763867f5", - "sha256:2ed779a896b70c8012fe301fb91ee37e713e1dda1eb8f37de04cdbf506706983", - "sha256:3ec2edf7f74829eae287aa53d64d83ad5d43ee51d29fb1d88e689d8b36028312", - "sha256:408bbf968c15e9e38df9f25a588e372e28a43240cf5884c9bc6039a5021b7d5b", - "sha256:4699bb671dbc4afdb544eb893e4deb8a34e294b7734733f65b4fd2787ba5fbc6", - "sha256:4eba6972b796d97c8fcc5266b6dc42ef27c2dce4421b846cded0f3af851b81c9", - "sha256:51092d13499be72e47c15c3a1ae0209edaca6be42b65ffbbefbe0c85f6153c6f", - "sha256:62319d57dab5ad3e3494dd97a214e22079d3f72a0c8a2fd001829c2c6abbf8d1", - "sha256:657fb7712185f82211170ac4debae0800ed4f5992b8f7ebba2a9eabaf133a857", - "sha256:66a0db13f77aa7806dba29273874cf862450c61c2e5158245d17ee85d983fe8e", - "sha256:6b98e098549d3aea2bfb93f38f0b2ecadcb423fa1504bbff902c01efdd833fd8", - "sha256:7127e2b94571318531caf098dc9e8f60f5aba1704600f0b2483bf151d535674a", - "sha256:798559837156b8e2e2df97cffca748c5c1432af6ec5004c2932e475d813f1743", - "sha256:802feae98addb9f21707649a7f229c90a59fad34511881f20b906a5e8e6ea475", - "sha256:89e1978c3fbe4e3d4c6ad7db7e6f982607cb2546f982ccbe42708392437b1972", - "sha256:9295ca10a140c21e40d2ee43ef423213dc20767f6cea6b87c36973564bc51095", - "sha256:9711ef291e184b5a73c9d3af3f2d5cfe25d571c8dd95aa498415f74ac7e221a8", - "sha256:b0320f882214f6ffde5992081520b57b55450510bdaa020e96aacff9b7ae10e6", - "sha256:b5bd3b3ff191f81509d9a1afd62e1e3cda7a7889c35b5b6359a1241fe1511015", - "sha256:baa19508d8445f5648cd1ffe4fc6d4f7daf8b876f804e9a453df6c3708f6200b", - "sha256:c5108ebe67da60a9204497d8d403316228deb52b550388190c53a57394d41531", - "sha256:ccea337fb9a44866c5300c594b13d4d87e827ebc3c353bff15d298bac976b654", - "sha256:cd73a16a759865831be5a8fb6546f2a908c8d7d7f55c75f94ee7c2ca13cc95de", - "sha256:d840712f4b4c7d2a119f993d7e43ca9bcaa73aeaa24c322fa2bdf4f689a3ee09", - "sha256:df26a09d955b3ab9b6bc18658b9403ed839096c97d7abe8806194e228a485a3c", - "sha256:e01382c06ac3710155a0ca923047c5abe03c676d08f03e146c6a240d0a910713", - "sha256:e572c67958f7d55eae77f5f64dc7bd31968cc9f24c233926833efe63c60545f2", - "sha256:eca6f59cd0729edaeaa7032d582dffce518a420d4961ef3e8c93dce86be352c3", - "sha256:efd2e12f8964f8fb4ba1984df71d85d02ef0531e687e59f78ec8fc07271a3857", - "sha256:efe9e8037b989b14bb1887089ae763385431cc06fe488406413079cfd2a3a089", - "sha256:f0d5b9b14ccc7f539143ac9eb1c6b57d26d69ca52d30c3d719a7bc4123579e44", - "sha256:f1954d71cdf15c19e7f3bf2235a4fe1600ba42f34d472c9495bcf54d75a43e4e", - "sha256:fbbceb0a0dfe9213f6314510665a32ef25fe29b50657567cd00115fbfcb3b20d" - ], - "index": "pypi", - "version": "==3.6.0" - }, - "mdit-py-plugins": { - "hashes": [ - "sha256:b1279701cee2dbf50e188d3da5f51fee8d78d038cdf99be57c6b9d1aa93b4073", - "sha256:ecc24f51eeec6ab7eecc2f9724e8272c2fb191c2e93cf98109120c2cace69750" - ], - "markers": "python_version ~= '3.6'", - "version": "==0.3.0" - }, - "mdurl": { - "hashes": [ - "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", - "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" - ], - "markers": "python_version >= '3.7'", - "version": "==0.1.2" - }, - "mpld3": { - "hashes": [ - "sha256:1a167dbef836dd7c66d8aa71c06a32d50bffa18725f304d93cb74fdb3545043b", - "sha256:41938e65de4ba41a1b53d92e7c8609e7172e09b33ef5db42bb6f73701106c8b7" - ], - "index": "pypi", - "version": "==0.5.8" - }, - "mypy": { - "hashes": [ - "sha256:794f385653e2b749387a42afb1e14c2135e18daeb027e0d97162e4b7031210f8", - "sha256:ad77c13037d3402fbeffda07d51e3f228ba078d1c7096a73759c9419ea031bf4", - "sha256:fa38f82f53e1e7beb45557ff167c177802ba7b387ad017eab1663d567017c8ee" - ], - "index": "pypi", - "version": "==0.981" - }, - "mypy-extensions": { - "hashes": [ - "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" - ], - "version": "==0.4.3" - }, - "myst-parser": { - "hashes": [ - "sha256:4965e51918837c13bf1c6f6fe2c6bddddf193148360fbdaefe743a4981358f6a", - "sha256:739a4d96773a8e55a2cacd3941ce46a446ee23dcd6b37e06f73f551ad7821d86" - ], - "index": "pypi", - "version": "==0.18.0" - }, - "natsort": { - "hashes": [ - "sha256:04fe18fdd2b9e5957f19f687eb117f102ef8dde6b574764e536e91194bed4f5f", - "sha256:57f85b72c688b09e053cdac302dd5b5b53df5f73ae20b4874fcbffd8bf783d11" - ], - "index": "pypi", - "version": "==8.2.0" - }, - "nodeenv": { - "hashes": [ - "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e", - "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==1.7.0" - }, - "numpy": { - "hashes": [ - "sha256:004f0efcb2fe1c0bd6ae1fcfc69cc8b6bf2407e0f18be308612007a0762b4089", - "sha256:09f6b7bdffe57fc61d869a22f506049825d707b288039d30f26a0d0d8ea05164", - "sha256:0ea3f98a0ffce3f8f57675eb9119f3f4edb81888b6874bc1953f91e0b1d4f440", - "sha256:17c0e467ade9bda685d5ac7f5fa729d8d3e76b23195471adae2d6a6941bd2c18", - "sha256:1f27b5322ac4067e67c8f9378b41c746d8feac8bdd0e0ffede5324667b8a075c", - "sha256:22d43376ee0acd547f3149b9ec12eec2f0ca4a6ab2f61753c5b29bb3e795ac4d", - "sha256:2ad3ec9a748a8943e6eb4358201f7e1c12ede35f510b1a2221b70af4bb64295c", - "sha256:301c00cf5e60e08e04d842fc47df641d4a181e651c7135c50dc2762ffe293dbd", - "sha256:39a664e3d26ea854211867d20ebcc8023257c1800ae89773cbba9f9e97bae036", - "sha256:51bf49c0cd1d52be0a240aa66f3458afc4b95d8993d2d04f0d91fa60c10af6cd", - "sha256:78a63d2df1d947bd9d1b11d35564c2f9e4b57898aae4626638056ec1a231c40c", - "sha256:7cd1328e5bdf0dee621912f5833648e2daca72e3839ec1d6695e91089625f0b4", - "sha256:8355fc10fd33a5a70981a5b8a0de51d10af3688d7a9e4a34fcc8fa0d7467bb7f", - "sha256:8c79d7cf86d049d0c5089231a5bcd31edb03555bd93d81a16870aa98c6cfb79d", - "sha256:91b8d6768a75247026e951dce3b2aac79dc7e78622fc148329135ba189813584", - "sha256:94c15ca4e52671a59219146ff584488907b1f9b3fc232622b47e2cf832e94fb8", - "sha256:98dcbc02e39b1658dc4b4508442a560fe3ca5ca0d989f0df062534e5ca3a5c1a", - "sha256:a64403f634e5ffdcd85e0b12c08f04b3080d3e840aef118721021f9b48fc1460", - "sha256:bc6e8da415f359b578b00bcfb1d08411c96e9a97f9e6c7adada554a0812a6cc6", - "sha256:bdc9febce3e68b697d931941b263c59e0c74e8f18861f4064c1f712562903411", - "sha256:c1ba66c48b19cc9c2975c0d354f24058888cdc674bebadceb3cdc9ec403fb5d1", - "sha256:c9f707b5bb73bf277d812ded9896f9512a43edff72712f31667d0a8c2f8e71ee", - "sha256:d5422d6a1ea9b15577a9432e26608c73a78faf0b9039437b075cf322c92e98e7", - "sha256:e5d5420053bbb3dd64c30e58f9363d7a9c27444c3648e61460c1237f9ec3fa14", - "sha256:e868b0389c5ccfc092031a861d4e158ea164d8b7fdbb10e3b5689b4fc6498df6", - "sha256:efd9d3abe5774404becdb0748178b48a218f1d8c44e0375475732211ea47c67e", - "sha256:f8c02ec3c4c4fcb718fdf89a6c6f709b14949408e8cf2a2be5bfa9c49548fd85", - "sha256:ffcf105ecdd9396e05a8e58e81faaaf34d3f9875f137c7372450baa5d77c9a54" - ], - "index": "pypi", - "version": "==1.23.3" - }, - "opencv-python-headless": { - "hashes": [ - "sha256:21e70f8b0c04098cdf466d27184fe6c3820aaef944a22548db95099959c95889", - "sha256:2c032c373e447c3fc2a670bca20e2918a1205a6e72854df60425fd3f82c78c32", - "sha256:3bacd806cce1f1988e58f3d6f761538e0215d6621d316de94c009dc0acbd6ad3", - "sha256:d5291d7e10aa2c19cab6fd86f0d61af8617290ecd2d7ffcb051e446868d04cc5", - "sha256:e6c069bc963d7e8fcec21b3e33e594d35948badd63eccb2e80f88b0a12102c03", - "sha256:eec6281054346103d6af93f173b7c6a206beb2663d3adc04aa3ddc66e85093df", - "sha256:ffbf26fcd697af996408440a93bc69c49c05a36845771f984156dfbeaa95d497" - ], - "index": "pypi", - "version": "==4.6.0.66" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "markers": "python_version >= '3.6'", - "version": "==21.3" - }, - "pandas": { - "hashes": [ - "sha256:0d8d7433d19bfa33f11c92ad9997f15a902bda4f5ad3a4814a21d2e910894484", - "sha256:1642fc6138b4e45d57a12c1b464a01a6d868c0148996af23f72dde8d12486bbc", - "sha256:171cef540bfcec52257077816a4dbbac152acdb8236ba11d3196ae02bf0959d8", - "sha256:1b82ccc7b093e0a93f8dffd97a542646a3e026817140e2c01266aaef5fdde11b", - "sha256:1d34b1f43d9e3f4aea056ba251f6e9b143055ebe101ed04c847b41bb0bb4a989", - "sha256:207d63ac851e60ec57458814613ef4b3b6a5e9f0b33c57623ba2bf8126c311f8", - "sha256:2504c032f221ef9e4a289f5e46a42b76f5e087ecb67d62e342ccbba95a32a488", - "sha256:33a9d9e21ab2d91e2ab6e83598419ea6a664efd4c639606b299aae8097c1c94f", - "sha256:3ee61b881d2f64dd90c356eb4a4a4de75376586cd3c9341c6c0fcaae18d52977", - "sha256:41aec9f87455306496d4486df07c1b98c15569c714be2dd552a6124cd9fda88f", - "sha256:4e30a31039574d96f3d683df34ccb50bb435426ad65793e42a613786901f6761", - "sha256:5cc47f2ebaa20ef96ae72ee082f9e101b3dfbf74f0e62c7a12c0b075a683f03c", - "sha256:62e61003411382e20d7c2aec1ee8d7c86c8b9cf46290993dd8a0a3be44daeb38", - "sha256:73844e247a7b7dac2daa9df7339ecf1fcf1dfb8cbfd11e3ffe9819ae6c31c515", - "sha256:85a516a7f6723ca1528f03f7851fa8d0360d1d6121cf15128b290cf79b8a7f6a", - "sha256:86d87279ebc5bc20848b4ceb619073490037323f80f515e0ec891c80abad958a", - "sha256:8a4fc04838615bf0a8d3a03ed68197f358054f0df61f390bcc64fbe39e3d71ec", - "sha256:8e8e5edf97d8793f51d258c07c629bd49d271d536ce15d66ac00ceda5c150eb3", - "sha256:947ed9f896ee61adbe61829a7ae1ade493c5a28c66366ec1de85c0642009faac", - "sha256:a68a9b9754efff364b0c5ee5b0f18e15ca640c01afe605d12ba8b239ca304d6b", - "sha256:c76f1d104844c5360c21d2ef0e1a8b2ccf8b8ebb40788475e255b9462e32b2be", - "sha256:c7f38d91f21937fe2bec9449570d7bf36ad7136227ef43b321194ec249e2149d", - "sha256:de34636e2dc04e8ac2136a8d3c2051fd56ebe9fd6cd185581259330649e73ca9", - "sha256:e178ce2d7e3b934cf8d01dc2d48d04d67cb0abfaffdcc8aa6271fd5a436f39c8", - "sha256:e252a9e49b233ff96e2815c67c29702ac3a062098d80a170c506dff3470fd060", - "sha256:e9c5049333c5bebf993033f4bf807d163e30e8fada06e1da7fa9db86e2392009", - "sha256:fc987f7717e53d372f586323fff441263204128a1ead053c1b98d7288f836ac9" - ], - "index": "pypi", - "version": "==1.5.0" - }, - "parameterized": { - "hashes": [ - "sha256:41bbff37d6186430f77f900d777e5bb6a24928a1c46fb1de692f8b52b8833b5c", - "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9" - ], - "index": "pypi", - "version": "==0.8.1" - }, - "paramiko": { - "hashes": [ - "sha256:003e6bee7c034c21fbb051bf83dc0a9ee4106204dd3c53054c71452cc4ec3938", - "sha256:655f25dc8baf763277b933dfcea101d636581df8d6b9774d1fb653426b72c270" - ], - "index": "pypi", - "version": "==2.11.0" - }, - "pillow": { - "hashes": [ - "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927", - "sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14", - "sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc", - "sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58", - "sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60", - "sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76", - "sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c", - "sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac", - "sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490", - "sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1", - "sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f", - "sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d", - "sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f", - "sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069", - "sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402", - "sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437", - "sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885", - "sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e", - "sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be", - "sha256:408673ed75594933714482501fe97e055a42996087eeca7e5d06e33218d05aa8", - "sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff", - "sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da", - "sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004", - "sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f", - "sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20", - "sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d", - "sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c", - "sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544", - "sha256:727dd1389bc5cb9827cbd1f9d40d2c2a1a0c9b32dd2261db522d22a604a6eec9", - "sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3", - "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04", - "sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c", - "sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5", - "sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4", - "sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb", - "sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4", - "sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c", - "sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467", - "sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e", - "sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421", - "sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b", - "sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8", - "sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb", - "sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3", - "sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc", - "sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf", - "sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1", - "sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a", - "sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28", - "sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0", - "sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1", - "sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8", - "sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd", - "sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4", - "sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8", - "sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f", - "sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013", - "sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59", - "sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc", - "sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4" - ], - "index": "pypi", - "version": "==9.2.0" - }, - "platformdirs": { - "hashes": [ - "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", - "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" - ], - "markers": "python_version >= '3.7'", - "version": "==2.5.2" - }, - "pluggy": { - "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" - ], - "markers": "python_version >= '3.6'", - "version": "==1.0.0" - }, - "pprofile": { - "hashes": [ - "sha256:b2bb56603dadf40c0bc0f61621f22c20e41638425f729945d9b7f8e4ae8cdd4a" - ], - "index": "pypi", - "version": "==2.1.0" - }, - "pre-commit": { - "hashes": [ - "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7", - "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959" - ], - "index": "pypi", - "version": "==2.20.0" - }, - "py": { - "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.11.0" - }, - "pycparser": { - "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" - ], - "version": "==2.21" - }, - "pycurl": { - "hashes": [ - "sha256:a863ad18ff478f5545924057887cdae422e1b2746e41674615f687498ea5b88a" - ], - "index": "pypi", - "version": "==7.45.1" - }, - "pygame": { - "hashes": [ - "sha256:0427c103f741234336e5606d2fad86f5403c1a3d1dc55c309fbff3c984f0c9ae", - "sha256:07ca9f683075aea9bd977af9f09a720ebf747343d3ea8103e4f1735283b02330", - "sha256:0e06ae8e1c830f1b9c36a2bc6bb11de840232e95b78e2c349c6ed803a303be19", - "sha256:0e97d38308c441942577fea7fcd1326308bc56d6be6c024218e94d075d322e0f", - "sha256:119dee20c372c85dc47b717119534d15a60c64ceab8b0eb09278866d10486afe", - "sha256:1219a963941bd53aa754e8449364c142004fe706c33a9c22ff2a76521a82d078", - "sha256:1fddec8829e96424800c806582d73a5173b7d48946cccf7d035839ca09850db8", - "sha256:20676da24e3e3e6b9fc4eecc7ba09d77ef46c3a83a028763ba1d222476c2e3fb", - "sha256:2405414d8c572668e04739875661e030a0c588e197fa95463fe301c3d0a0510b", - "sha256:24254c4244f0d9bdc904f5d3f38e86757ca4c6aa0e44a6d55ef5e016bc7274d6", - "sha256:24b4f7f30fa2b3d092b60be6fcc725fb91d569fc87a9bcc91614ee8b0c005726", - "sha256:3bb0674aa789848ddc264bfc60c54965bf3bb659c141de4f600e379acc9b944c", - "sha256:3c8d6637ff75351e581327efefa9d04eeb0f257b533392b6cc6b15ceca4f7c5e", - "sha256:40e4d8d65985bb467d9c5a1305fb53fd6820c61d764979600becab973339676f", - "sha256:4aa3ae32320cc704d63e185864e44f6265c2a6e52c9384afe152cc3d51b3a2ef", - "sha256:50d9a21edd551669862c27c9272747401b20b1939abaacb842c08ea1cdd1c04d", - "sha256:5c7600bf307de1ca1dca0cc7840e34604d5b0b0a5a5dad345c3fa62b054b886d", - "sha256:5d0c14152d0ca8ef5fbcc5ed9981462bdf59a9ae85a291e62d8a8d0b7e5cbe43", - "sha256:5e88b0d4338b94960686f59396f23f7f684fed4859fcc3b9f40286d72c1c61af", - "sha256:5ebbefb8b576572c8fc97a3321d37dc2b4afea6b6e3877a67f7158d8c2c4cefe", - "sha256:636f51f56615d67459b11918206bb4da30cd7d7042027bf997c218ccd6c77902", - "sha256:660c80c0b2e80f1f801715583b759fb4c7bc0c11eb3b534e89c9fc4bfbc38acd", - "sha256:6ecda8dd4583982bb65f9c682f244a5e94524dcf628379766227e9ed97201a49", - "sha256:754c2906f2ef47173a14493e1de116b2a56a2c8e1764f1202ba844d080248a5b", - "sha256:7889dce887ec83c9a0bef8d9eb3669d8863fdaf37c45bacec707d8ad90b24a38", - "sha256:7fdb93b4282962c9a2ebf1af994ee698be823dd913218ed97a5f2fb372b10b66", - "sha256:8e87716114e97322fb177e223d889a4be369a0f73212f4f8507fe0cd43253b23", - "sha256:93c4cbfc942dd00410eaa9e84252129f9f9993f37f683006d7b49ab245342254", - "sha256:9649419254d3282dae41f23837de4108b17bc62187c3acd8af2ae3801b765cbd", - "sha256:97a74ba186deee68318a52637012ef6abf5be6282c659e1d1ba6ad08cf35ec85", - "sha256:9d6452419e01a0f848aed0597f69fd10a4c2a7750c15d1b0607f86090a39dcf3", - "sha256:9d7b021b8dde5d528363e474bc18bd6f79a9666eef89fb4859bcb8f0a536c9de", - "sha256:a0ccf8e3dce7ca67d523a6020b7e3dbf4b26797a9a8db5cc4c7b5ef20fb64701", - "sha256:a56a811d8821f7b9a594e3d0e0dd8bd39b25e3eea8963d5963263b90fd2ea5c2", - "sha256:c5ea87da5fe4b6164c3854f3b0c9146811dbad0dd7fa74297683dfacc485ae1c", - "sha256:c99b95e62cdda29c2e60235d7763447c168a6a877403e6f9ca5b2e2bb297c2ce", - "sha256:c9ce7f3d8af14d7e04eb7eb41c5e5313c43508c252bb2b9eb53e51fc87ada9fd", - "sha256:ca5ef1315fa67c241a657ab077be44f230c05740c95f0b46409457dceefdc7e5", - "sha256:d2d3c50ee9847b743db6cd7b1bb17a94c2c2abc16679d70f5e745cabdf19e655", - "sha256:d6d0eca28f886f0477cd0721ac688189155a587f2bb8eae740e52ca56c3ad23c", - "sha256:dad6bf3fdd3752d7519422f3732be779b98fe7c87d32c3efe2fdffdcbeebb6ca", - "sha256:db2f40d5a75fd9cdda473c58b0d8b294da6e0179f00bb3b1fc2f7f29cac09bea", - "sha256:dc4444d61d48c5546df5137cdf81554887ddb6e2ef1be7f51eb77ea3b6bdd56f", - "sha256:dcc285ee1f1d0e2672cc52f880fd3f564b1505de710e817f692fbf64a72ca657", - "sha256:dd528dbb91eca16f7522c975d0f9e94b95f6b5024c82c3247dc0383d242d33c6", - "sha256:e09044e9e1aa8512d6a9c7ce5f94b881824bcfc401105f3c24f546dfc3bb4aa5", - "sha256:e18c9466131378421d00fc40b637425229238d506a073d9c537b230b355a25d6", - "sha256:e1bb25986db77a48f632469c6bc61baf7508ce945aa6161c02180d4ee5ac5b8d", - "sha256:e4b4cd440d50a9f8551b8989e856aab175593af07eb825cad22fd2f8f6f2ffce", - "sha256:e627300a66a90651fb39e41601d447b1fdbbfffca3f08ef0278d6cc0436b2160", - "sha256:e7a8e18677e0064b7a422f6653a622652d932826a27e50f279d55a8b122a1a83", - "sha256:e8632f6b2ddb90f6f3950744bd65d5ef15af615e3034057fa30ff836f48a7179", - "sha256:ea36f4f93524554a35cac2359df63b50af6556ed866830aa1f07f0d8580280ea", - "sha256:f149e182d0eeef15d8a9b4c9dad1b87dc6eba3a99bd3c44a777a3a2b053a3dca", - "sha256:fc2e5db54491e8f27785fc5204c96f540d3557dcf5b0a9a857b6594d6b32561b", - "sha256:fc30e834f65b893d1b4c230070183bf98e6b70c41c1511687e8436a33d5ce49d", - "sha256:fcc9586e17875c0cdf8764597955f9daa979098fd4f80be07ed68276ac225480", - "sha256:ff961c3280d6ee5f4163f4772f963d7a4dbe42e36c6dd54b79ad436c1f046e5d" - ], - "index": "pypi", - "version": "==2.1.2" - }, - "pygments": { - "hashes": [ - "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1", - "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42" - ], - "markers": "python_version >= '3.6'", - "version": "==2.13.0" - }, - "pynacl": { - "hashes": [ - "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858", - "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d", - "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", - "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1", - "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92", - "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff", - "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba", - "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394", - "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", - "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543" - ], - "markers": "python_version >= '3.6'", - "version": "==1.5.0" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" - }, - "pyprof2calltree": { - "hashes": [ - "sha256:a635672ff31677486350b2be9a823ef92f740e6354a6aeda8fa4a8a3768e8f2f" - ], - "index": "pypi", - "version": "==1.4.5" - }, - "pytest": { - "hashes": [ - "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7", - "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39" - ], - "index": "pypi", - "version": "==7.1.3" - }, - "pytest-forked": { - "hashes": [ - "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e", - "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8" - ], - "markers": "python_version >= '3.6'", - "version": "==1.4.0" - }, - "pytest-xdist": { - "hashes": [ - "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf", - "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65" - ], - "index": "pypi", - "version": "==2.5.0" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "index": "pypi", - "version": "==2.8.2" - }, - "pytz": { - "hashes": [ - "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197", - "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5" - ], - "version": "==2022.2.1" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "index": "pypi", - "version": "==6.0" - }, - "requests": { - "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" - ], - "index": "pypi", - "version": "==2.28.1" - }, - "reverse-geocoder": { - "hashes": [ - "sha256:2a2e781b5f69376d922b78fe8978f1350c84fce0ddb07e02c834ecf98b57c75c" - ], - "index": "pypi", - "version": "==1.5.1" - }, - "scipy": { - "hashes": [ - "sha256:0419485dbcd0ed78c0d5bf234c5dd63e86065b39b4d669e45810d42199d49521", - "sha256:09412eb7fb60b8f00b328037fd814d25d261066ebc43a1e339cdce4f7502877e", - "sha256:26d28c468900e6d5fdb37d2812ab46db0ccd22c63baa095057871faa3a498bc9", - "sha256:34441dfbee5b002f9e15285014fd56e5e3372493c3e64ae297bae2c4b9659f5a", - "sha256:39ab9240cd215a9349c85ab908dda6d732f7d3b4b192fa05780812495536acc4", - "sha256:3bc1ab68b9a096f368ba06c3a5e1d1d50957a86665fc929c4332d21355e7e8f4", - "sha256:3c6f5d1d4b9a5e4fe5e14f26ffc9444fc59473bbf8d45dc4a9a15283b7063a72", - "sha256:47d1a95bd9d37302afcfe1b84c8011377c4f81e33649c5a5785db9ab827a6ade", - "sha256:71487c503e036740635f18324f62a11f283a632ace9d35933b2b0a04fd898c98", - "sha256:7a412c476a91b080e456229e413792bbb5d6202865dae963d1e6e28c2bb58691", - "sha256:825951b88f56765aeb6e5e38ac9d7d47407cfaaeb008d40aa1b45a2d7ea2731e", - "sha256:8cc81ac25659fec73599ccc52c989670e5ccd8974cf34bacd7b54a8d809aff1a", - "sha256:8d3faa40ac16c6357aaf7ea50394ea6f1e8e99d75e927a51102b1943b311b4d9", - "sha256:90c805f30c46cf60f1e76e947574f02954d25e3bb1e97aa8a07bc53aa31cf7d1", - "sha256:96d7cf7b25c9f23c59a766385f6370dab0659741699ecc7a451f9b94604938ce", - "sha256:b97b479f39c7e4aaf807efd0424dec74bbb379108f7d22cf09323086afcd312c", - "sha256:bc4e2c77d4cd015d739e75e74ebbafed59ba8497a7ed0fd400231ed7683497c4", - "sha256:c61b4a91a702e8e04aeb0bfc40460e1f17a640977c04dda8757efb0199c75332", - "sha256:d79da472015d0120ba9b357b28a99146cd6c17b9609403164b1a8ed149b4dfc8", - "sha256:e8fe305d9d67a81255e06203454729405706907dccbdfcc330b7b3482a6c371d", - "sha256:eb954f5aca4d26f468bbebcdc5448348eb287f7bea536c6306f62ea062f63d9a", - "sha256:f7c39f7dbb57cce00c108d06d731f3b0e2a4d3a95c66d96bce697684876ce4d4", - "sha256:f950a04b33e17b38ff561d5a0951caf3f5b47caa841edd772ffb7959f20a6af0" - ], - "index": "pypi", - "version": "==1.9.1" - }, - "setuptools": { - "hashes": [ - "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9", - "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1" - ], - "markers": "python_version >= '3.7'", - "version": "==65.4.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "index": "pypi", - "version": "==1.16.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", - "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" - ], - "version": "==2.2.0" - }, - "sortedcontainers": { - "hashes": [ - "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", - "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0" - ], - "version": "==2.4.0" - }, - "sphinx": { - "hashes": [ - "sha256:3dcf00fcf82cf91118db9b7177edea4fc01998976f893928d0ab0c58c54be2ca", - "sha256:c009bb2e9ac5db487bcf53f015504005a330ff7c631bb6ab2604e0d65bae8b54" - ], - "index": "pypi", - "version": "==5.2.1" - }, - "sphinx-rtd-theme": { - "hashes": [ - "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8", - "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c" - ], - "index": "pypi", - "version": "==1.0.0" - }, - "sphinx-sitemap": { - "hashes": [ - "sha256:65adda39233cb17c0da10ba1cebaa2df73e271cdb6f8efd5cec8eef3b3cf7737" - ], - "index": "pypi", - "version": "==2.2.0" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", - "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", - "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", - "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" - ], - "markers": "python_version >= '3.6'", - "version": "==2.0.0" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", - "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.3" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd", - "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952" - ], - "markers": "python_version >= '3.5'", - "version": "==1.1.5" - }, - "subprocess32": { - "hashes": [ - "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b", - "sha256:e45d985aef903c5b7444d34350b05da91a9e0ea015415ab45a21212786c649d0", - "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d" - ], - "index": "pypi", - "version": "==3.5.4" - }, - "tabulate": { - "hashes": [ - "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc", - "sha256:436f1c768b424654fce8597290d2764def1eea6a77cfa5c33be00b1bc0f4f63d", - "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519" - ], - "index": "pypi", - "version": "==0.8.10" - }, - "tenacity": { - "hashes": [ - "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac", - "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445" - ], - "index": "pypi", - "version": "==8.1.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" - }, - "types-atomicwrites": { - "hashes": [ - "sha256:458a985b2cfaa963becec21ba63faaa5dd241e237ba8bf024732b37b18690de6", - "sha256:ef824f7e639c178e3e571f60d228c7745198756ebfcc5d249a0e3e02e04b2858" - ], - "index": "pypi", - "version": "==1.4.5" - }, - "types-certifi": { - "hashes": [ - "sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f", - "sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a" - ], - "index": "pypi", - "version": "==2021.10.8.3" - }, - "types-pycurl": { - "hashes": [ - "sha256:82e00aa2981595bfa55e5a3bac42221eb3435b0026dffbe1177f6ac9f2d51200", - "sha256:9eab3414da4a1b1e9a628bd288fc5172b8c182e1d9fb6d8d082441b0fd64baed" - ], - "index": "pypi", - "version": "==7.45.1" - }, - "types-pyyaml": { - "hashes": [ - "sha256:7f7da2fd11e9bc1e5e9eb3ea1be84f4849747017a59fc2eee0ea34ed1147c2e0", - "sha256:8f890028123607379c63550179ddaec4517dc751f4c527a52bb61934bf495989" - ], - "index": "pypi", - "version": "==6.0.11" - }, - "types-requests": { - "hashes": [ - "sha256:7ee827eb8ce611b02b5117cfec5da6455365b6a575f5e3ff19f655ba603e6b4e", - "sha256:af5f55e803cabcfb836dad752bd6d8a0fc8ef1cd84243061c0e27dee04ccf4fd" - ], - "index": "pypi", - "version": "==2.28.11" - }, - "types-urllib3": { - "hashes": [ - "sha256:a1b3aaea7dda3eb1b51699ee723aadd235488e4dc4648e030f09bc429ecff42f", - "sha256:cf7918503d02d3576e503bbfb419b0e047c4617653bba09624756ab7175e15c9" - ], - "version": "==1.26.24" - }, - "typing-extensions": { - "hashes": [ - "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", - "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" - ], - "markers": "python_version < '3.10'", - "version": "==4.3.0" - }, - "urllib3": { - "hashes": [ - "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", - "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" - ], - "index": "pypi", - "version": "==1.26.12" - }, - "virtualenv": { - "hashes": [ - "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da", - "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27" - ], - "markers": "python_version >= '3.6'", - "version": "==20.16.5" - }, - "zipp": { - "hashes": [ - "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", - "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009" - ], - "markers": "python_version >= '3.7'", - "version": "==3.8.1" - } - } -} diff --git a/docs/docker/Dockerfile b/docs/docker/Dockerfile index cefe9be855..0d5883f566 100644 --- a/docs/docker/Dockerfile +++ b/docs/docker/Dockerfile @@ -4,16 +4,11 @@ ENV PYTHONUNBUFFERED 1 ENV OPENPILOT_PATH /home/batman/openpilot/ ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} +ENV POETRY_VIRUALENVS_CREATE false RUN mkdir -p ${OPENPILOT_PATH} WORKDIR ${OPENPILOT_PATH} -COPY Pipfile Pipfile.lock $OPENPILOT_PATH -RUN pip install --no-cache-dir pipenv==2021.5.29 pip==21.3.1 && \ - pipenv install --system --deploy --dev --clear && \ - pip uninstall -y pipenv - - COPY SConstruct ${OPENPILOT_PATH} COPY ./pyextra ${OPENPILOT_PATH}/pyextra diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000000..7ad02c58cd --- /dev/null +++ b/poetry.lock @@ -0,0 +1,7963 @@ +[[package]] +name = "adal" +version = "1.2.7" +description = "Note: This library is already replaced by MSAL Python, available here: https://pypi.org/project/msal/ .ADAL Python remains available here as a legacy. The ADAL for Python library makes it easy for python application to authenticate to Azure Active Directory (AAD) in order to access AAD protected web resources." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +cryptography = ">=1.1.0" +PyJWT = ">=1.0.0,<3" +python-dateutil = ">=2.1.0,<3" +requests = ">=2.0.0,<3" + +[[package]] +name = "aenum" +version = "3.1.11" +description = "Advanced Enumerations (compatible with Python's stdlib Enum), NamedTuples, and NamedConstants" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "aiohttp" +version = "3.8.3" +description = "Async http client/server framework (asyncio)" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +aiosignal = ">=1.1.2" +async-timeout = ">=4.0.0a3,<5.0" +attrs = ">=17.3.0" +charset-normalizer = ">=2.0,<3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns", "cchardet"] + +[[package]] +name = "aiosignal" +version = "1.2.0" +description = "aiosignal: a list of registered asynchronous callbacks" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "alabaster" +version = "0.7.12" +description = "A configurable sidebar-enabled Sphinx theme" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "albumentations" +version = "1.3.0" +description = "Fast image augmentation library and easy to use wrapper around other libraries" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +numpy = ">=1.11.1" +opencv-python-headless = ">=4.1.1" +PyYAML = "*" +qudida = ">=0.0.4" +scikit-image = ">=0.16.1" +scipy = "*" + +[package.extras] +develop = ["imgaug (>=0.4.0)", "pytest"] +imgaug = ["imgaug (>=0.4.0)"] +tests = ["pytest"] + +[[package]] +name = "anyio" +version = "3.6.2" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] +trio = ["trio (>=0.16,<0.22)"] + +[[package]] +name = "apex" +version = "0.1" +description = "PyTorch Extensions written by NVIDIA" +category = "dev" +optional = false +python-versions = "*" + +[package.source] +type = "url" +url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "applicationinsights" +version = "0.11.10" +description = "This project extends the Application Insights API surface to support Python." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "argcomplete" +version = "1.12.3" +description = "Bash tab completion for argparse" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +test = ["coverage", "flake8", "pexpect", "wheel"] + +[[package]] +name = "argon2-cffi" +version = "21.3.0" +description = "The secure Argon2 password hashing algorithm." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["cogapp", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "pre-commit", "pytest", "sphinx", "sphinx-notfound-page", "tomli"] +docs = ["furo", "sphinx", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pytest"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + +[[package]] +name = "astroid" +version = "2.12.12" +description = "An abstract syntax tree for Python with inference support." +category = "main" +optional = false +python-versions = ">=3.7.2" + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""} + +[[package]] +name = "asttokens" +version = "2.0.8" +description = "Annotate AST trees with source code positions" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + +[package.extras] +test = ["astroid (<=2.5.3)", "pytest"] + +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "atomicwrites" +version = "1.4.1" +description = "Atomic file writes." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "22.1.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] +docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] + +[[package]] +name = "av" +version = "9.2.0" +description = "Pythonic bindings for FFmpeg's libraries." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "azure-cli-core" +version = "2.41.0" +description = "Microsoft Azure Command-Line Tools Core Module" +category = "dev" +optional = false +python-versions = ">=3.7.0" + +[package.dependencies] +argcomplete = ">=1.8,<2.0" +azure-cli-telemetry = ">=1.0.0,<1.1.0" +azure-mgmt-core = ">=1.2.0,<2" +cryptography = "*" +humanfriendly = ">=10.0,<11.0" +jmespath = "*" +knack = ">=0.10.0,<0.11.0" +msal = {version = "1.20.0b1", extras = ["broker"]} +msal-extensions = ">=1.0.0,<1.1.0" +msrestazure = ">=0.6.4,<0.7.0" +packaging = ">=20.9,<22.0" +paramiko = ">=2.0.8,<3.0.0" +pkginfo = ">=1.5.0.1" +psutil = {version = ">=5.9,<6.0", markers = "sys_platform != \"cygwin\""} +PyJWT = ">=2.1.0" +pyopenssl = ">=17.1.0" +requests = {version = "*", extras = ["socks"]} + +[[package]] +name = "azure-cli-telemetry" +version = "1.0.8" +description = "Microsoft Azure CLI Telemetry Package" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +applicationinsights = ">=0.11.1,<0.12" +portalocker = ">=1.6,<3" + +[[package]] +name = "azure-common" +version = "1.1.28" +description = "Microsoft Azure Client Library for Python (Common)" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "azure-core" +version = "1.26.0" +description = "Microsoft Azure Core Library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +requests = ">=2.18.4" +six = ">=1.11.0" +typing-extensions = ">=4.0.1" + +[package.extras] +aio = ["aiohttp (>=3.0)"] + +[[package]] +name = "azure-mgmt-core" +version = "1.3.2" +description = "Microsoft Azure Management Core Library for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +azure-core = ">=1.24.0,<2.0.0" + +[[package]] +name = "azure-nspkg" +version = "3.0.2" +description = "Microsoft Azure Namespace Package [Internal]" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "azure-storage-blob" +version = "2.1.0" +description = "Microsoft Azure Storage Blob Client Library for Python" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +azure-common = ">=1.1.5" +azure-storage-common = ">=2.1,<3.0" + +[[package]] +name = "azure-storage-common" +version = "2.1.0" +description = "Microsoft Azure Storage Common Client Library for Python" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +azure-common = ">=1.1.5" +cryptography = "*" +python-dateutil = "*" +requests = "*" + +[[package]] +name = "azure-storage-nspkg" +version = "3.1.0" +description = "Microsoft Azure Storage Namespace Package [Internal]" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +azure-nspkg = ">=2.0.0" + +[[package]] +name = "babel" +version = "2.10.3" +description = "Internationalization utilities" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pytz = ">=2015.7" + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "bcrypt" +version = "4.0.1" +description = "Modern password hashing for your software and your servers" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "beautifulsoup4" +version = "4.11.1" +description = "Screen-scraping library" +category = "dev" +optional = false +python-versions = ">=3.6.0" + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bidict" +version = "0.22.0" +description = "The bidirectional mapping library for Python." +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "bleach" +version = "5.0.1" +description = "An easy safelist-based HTML-sanitizing tool." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.2)"] +dev = ["Sphinx (==4.3.2)", "black (==22.3.0)", "build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "mypy (==0.961)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)"] + +[[package]] +name = "blosc" +version = "1.9.2" +description = "Blosc data compressor" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "breathe" +version = "4.34.0" +description = "Sphinx Doxygen renderer" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +docutils = ">=0.12" +Sphinx = ">=4.0,<5.0.0 || >5.0.0,<6" + +[[package]] +name = "cachecontrol" +version = "0.12.11" +description = "httplib2 caching for requests" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +lockfile = {version = ">=0.9", optional = true, markers = "extra == \"filecache\""} +msgpack = ">=0.5.2" +requests = "*" + +[package.extras] +filecache = ["lockfile (>=0.9)"] +redis = ["redis (>=2.10.5)"] + +[[package]] +name = "cachy" +version = "0.3.0" +description = "Cachy provides a simple yet effective caching library." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +memcached = ["python-memcached (>=1.59,<2.0)"] +msgpack = ["msgpack-python (>=0.5,<0.6)"] +redis = ["redis (>=3.3.6,<4.0.0)"] + +[[package]] +name = "carla" +version = "0.9.13" +description = "Python API for communicating with the CARLA server." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "casadi" +version = "3.5.5" +description = "CasADi -- framework for algorithmic differentiation and numeric optimization" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "certifi" +version = "2022.9.24" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +unicode-backport = ["unicodedata2"] + +[[package]] +name = "cleo" +version = "1.0.0a5" +description = "Cleo allows you to create beautiful and testable command-line interfaces." +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +crashtest = ">=0.3.1,<0.4.0" +pylev = ">=1.3.0,<2.0.0" + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "cloudpickle" +version = "2.2.0" +description = "Extended pickling support for Python objects" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "colorama" +version = "0.4.5" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coloredlogs" +version = "15.0.1" +description = "Colored terminal output for Python's logging module" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +humanfriendly = ">=9.1" + +[package.extras] +cron = ["capturer (>=2.4)"] + +[[package]] +name = "configargparse" +version = "1.5.3" +description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +test = ["PyYAML", "mock", "pytest"] +yaml = ["PyYAML"] + +[[package]] +name = "contourpy" +version = "1.0.5" +description = "Python library for calculating contours of 2D quadrilateral grids" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["docutils (<0.18)", "sphinx", "sphinx-rtd-theme"] +test = ["Pillow", "flake8", "isort", "matplotlib", "pytest"] +test-minimal = ["pytest"] +test-no-codebase = ["Pillow", "matplotlib", "pytest"] + +[[package]] +name = "control" +version = "0.9.2" +description = "Python Control Systems Library" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +matplotlib = "*" +numpy = "*" +scipy = "*" + +[package.extras] +slycot = ["slycot (>=0.4.0)"] +test = ["pytest", "pytest-timeout"] + +[[package]] +name = "coverage" +version = "6.5.0" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "crashtest" +version = "0.3.1" +description = "Manage Python errors with ease" +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[[package]] +name = "crcmod" +version = "1.7" +description = "CRC Generator" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "cryptography" +version = "37.0.4" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx_rtd_theme"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools_rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] + +[[package]] +name = "cupy-cuda113" +version = "10.6.0" +description = "CuPy: NumPy & SciPy for GPU" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +fastrlock = ">=0.5" +numpy = ">=1.18,<1.25" + +[package.extras] +all = ["Cython (>=0.29.22,<3)", "optuna (>=2.0)", "scipy (>=1.4,<1.11)"] +stylecheck = ["autopep8 (==1.5.5)", "flake8 (==3.8.4)", "mypy (==0.950)", "pbr (==5.5.1)", "pycodestyle (==2.6.0)", "types-setuptools (==57.4.14)"] +test = ["hypothesis (>=6.37.2)", "pytest (>=6.2)"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "cython" +version = "0.29.32" +description = "The Cython compiler for writing C extensions for the Python language." +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "datadog" +version = "0.44.0" +description = "The Datadog Python library" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" + +[package.dependencies] +requests = ">=2.6.0" + +[[package]] +name = "debugpy" +version = "1.6.3" +description = "An implementation of the Debug Adapter Protocol for Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] + +[[package]] +name = "dictdiffer" +version = "0.9.0" +description = "Dictdiffer is a library that helps you to diff and patch dictionaries." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +all = ["Sphinx (>=3)", "check-manifest (>=0.42)", "mock (>=1.3.0)", "numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "sphinx-rtd-theme (>=0.2)", "tox (>=3.7.0)"] +docs = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)"] +numpy = ["numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)"] +tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "tox (>=3.7.0)"] + +[[package]] +name = "dill" +version = "0.3.5.1" +description = "serialize all of python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "docutils" +version = "0.17.1" +description = "Docutils -- Python Documentation Utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "dotmap" +version = "1.3.30" +description = "ordered, dynamically-expandable dot-access dictionary" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "dulwich" +version = "0.20.46" +description = "Python Git Library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +urllib3 = ">=1.25" + +[package.extras] +fastimport = ["fastimport"] +https = ["urllib3 (>=1.24.1)"] +paramiko = ["paramiko"] +pgp = ["gpg"] + +[[package]] +name = "efficientnet-pytorch" +version = "0.6.3" +description = "EfficientNet implemented in PyTorch." +category = "dev" +optional = false +python-versions = ">=3.5.0" + +[package.dependencies] +torch = "*" + +[[package]] +name = "elastic-transport" +version = "8.4.0" +description = "Transport classes and utilities shared among Python Elastic client libraries" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.2,<2" + +[package.extras] +develop = ["aiohttp", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "pytest-mock", "requests", "trustme"] + +[[package]] +name = "elasticsearch" +version = "8.4.3" +description = "Python client for Elasticsearch" +category = "dev" +optional = false +python-versions = ">=3.6, <4" + +[package.dependencies] +elastic-transport = ">=8,<9" + +[package.extras] +async = ["aiohttp (>=3,<4)"] +requests = ["requests (>=2.4.0,<3.0.0)"] + +[[package]] +name = "entrypoints" +version = "0.4" +description = "Discover and load entry points from installed packages." +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "execnet" +version = "1.9.0" +description = "execnet: rapid multi-Python deployment" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +testing = ["pre-commit"] + +[[package]] +name = "executing" +version = "1.1.1" +description = "Get the currently executing AST node of a frame, and other information" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +tests = ["asttokens", "littleutils", "pytest", "rich"] + +[[package]] +name = "fastcluster" +version = "1.2.6" +description = "Fast hierarchical clustering routines for R and Python." +category = "dev" +optional = false +python-versions = ">=3" + +[package.dependencies] +numpy = ">=1.9" + +[package.extras] +test = ["scipy (>=1.6.3)"] + +[[package]] +name = "fastjsonschema" +version = "2.16.2" +description = "Fastest Python implementation of JSON schema" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + +[[package]] +name = "fastrlock" +version = "0.8" +description = "Fast, re-entrant optimistic lock implemented in Cython" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "filelock" +version = "3.8.0" +description = "A platform independent file lock." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] +testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flake8" +version = "4.0.1" +description = "the modular source code checker: pep8 pyflakes and co" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.8.0,<2.9.0" +pyflakes = ">=2.4.0,<2.5.0" + +[[package]] +name = "flask" +version = "2.2.2" +description = "A simple framework for building complex web applications." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +click = ">=8.0" +importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""} +itsdangerous = ">=2.0" +Jinja2 = ">=3.0" +Werkzeug = ">=2.2.2" + +[package.extras] +async = ["asgiref (>=3.2)"] +dotenv = ["python-dotenv"] + +[[package]] +name = "flask-cors" +version = "3.0.10" +description = "A Flask extension adding a decorator for CORS support" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +Flask = ">=0.9" +Six = "*" + +[[package]] +name = "flask-socketio" +version = "5.3.1" +description = "Socket.IO integration for Flask applications" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +Flask = ">=0.9" +python-socketio = ">=5.0.2" + +[[package]] +name = "flatbuffers" +version = "22.9.24" +description = "The FlatBuffers serialization format for Python" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "fonttools" +version = "4.37.4" +description = "Tools to manipulate font files" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=14.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + +[[package]] +name = "frozenlist" +version = "1.3.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "ft4222" +version = "1.6.0" +description = "Python wrapper around libFT4222." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "future" +version = "0.18.2" +description = "Clean single-source support for Python 3 and 2" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "future-fstrings" +version = "1.2.0" +description = "A backport of fstrings to python<3.6" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +rewrite = ["tokenize-rt (>=3)"] + +[[package]] +name = "geoalchemy2" +version = "0.12.5" +description = "Using SQLAlchemy with Spatial Databases" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +packaging = "*" +SQLAlchemy = ">=1.4" + +[[package]] +name = "gevent" +version = "22.10.1" +description = "Coroutine-based network library" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5" + +[package.dependencies] +cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} +greenlet = {version = ">=1.1.3,<2.0", markers = "platform_python_implementation == \"CPython\""} +setuptools = "*" +"zope.event" = "*" +"zope.interface" = "*" + +[package.extras] +dnspython = ["dnspython (>=1.16.0,<2.0)", "idna"] +docs = ["repoze.sphinx.autointerface", "sphinxcontrib-programoutput", "zope.schema"] +monitor = ["psutil (>=5.7.0)"] +recommended = ["backports.socketpair", "cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "psutil (>=5.7.0)", "selectors2"] +test = ["backports.socketpair", "cffi (>=1.12.2)", "contextvars (==2.4)", "coverage (>=5.0)", "coveralls (>=1.7.0)", "dnspython (>=1.16.0,<2.0)", "futures", "idna", "mock", "objgraph", "psutil (>=5.7.0)", "requests", "selectors2"] + +[[package]] +name = "greenlet" +version = "1.1.3.post0" +description = "Lightweight in-process concurrent programming" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" + +[package.extras] +docs = ["Sphinx"] + +[[package]] +name = "gunicorn" +version = "20.1.0" +description = "WSGI HTTP Server for UNIX" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +setuptools = ">=3.0" + +[package.extras] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +tornado = ["tornado (>=0.2)"] + +[[package]] +name = "h3" +version = "3.7.4" +description = "Hierarchical hexagonal geospatial indexing system" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +all = ["flake8", "numpy", "pylint", "pytest", "pytest-cov"] +numpy = ["numpy"] +test = ["flake8", "pylint", "pytest", "pytest-cov"] + +[[package]] +name = "hatanaka" +version = "2.4.0" +description = "Effortlessly compress / decompress any RINEX file" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +importlib-resources = "*" +ncompress = "*" + +[package.extras] +dev = ["pytest"] +tests = ["pytest"] + +[[package]] +name = "hexdump" +version = "3.3" +description = "dump binary data to hex format and restore from there" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "html5lib" +version = "1.1" +description = "HTML parser based on the WHATWG HTML specification" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +six = ">=1.9" +webencodings = "*" + +[package.extras] +all = ["chardet (>=2.2)", "genshi", "lxml"] +chardet = ["chardet (>=2.2)"] +genshi = ["genshi"] +lxml = ["lxml"] + +[[package]] +name = "humanfriendly" +version = "10.0" +description = "Human friendly output for text interfaces using Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""} + +[[package]] +name = "hypothesis" +version = "6.46.7" +description = "A library for property-based testing" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=19.2.0" +sortedcontainers = ">=2.1.0,<3.0.0" + +[package.extras] +all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=2.2)", "dpcontracts (>=0.4)", "importlib-metadata (>=3.6)", "lark-parser (>=0.6.5)", "libcst (>=0.3.16)", "numpy (>=1.9.0)", "pandas (>=0.25)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2022.1)"] +cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"] +codemods = ["libcst (>=0.3.16)"] +dateutil = ["python-dateutil (>=1.4)"] +django = ["django (>=2.2)"] +dpcontracts = ["dpcontracts (>=0.4)"] +ghostwriter = ["black (>=19.10b0)"] +lark = ["lark-parser (>=0.6.5)"] +numpy = ["numpy (>=1.9.0)"] +pandas = ["pandas (>=0.25)"] +pytest = ["pytest (>=4.6)"] +pytz = ["pytz (>=2014.1)"] +redis = ["redis (>=3.0.0)"] +zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2022.1)"] + +[[package]] +name = "identify" +version = "2.5.6" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "imageio" +version = "2.22.2" +description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = "*" +pillow = ">=8.3.2" + +[package.extras] +all-plugins = ["astropy", "av", "imageio-ffmpeg", "opencv-python", "psutil", "tifffile"] +all-plugins-pypy = ["av", "imageio-ffmpeg", "psutil", "tifffile"] +build = ["wheel"] +dev = ["black", "flake8", "fsspec[github]", "invoke", "pytest", "pytest-cov"] +docs = ["numpydoc", "pydata-sphinx-theme", "sphinx"] +ffmpeg = ["imageio-ffmpeg", "psutil"] +fits = ["astropy"] +full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "invoke", "itk", "numpydoc", "opencv-python", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx", "tifffile", "wheel"] +gdal = ["gdal"] +itk = ["itk"] +linting = ["black", "flake8"] +opencv = ["opencv-python"] +pyav = ["av"] +test = ["fsspec[github]", "invoke", "pytest", "pytest-cov"] +tifffile = ["tifffile"] + +[[package]] +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "importlib-metadata" +version = "4.13.0" +description = "Read metadata from Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +perf = ["ipython"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] + +[[package]] +name = "importlib-resources" +version = "5.10.0" +description = "Read resources from Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "influxdb-client" +version = "1.33.0" +description = "InfluxDB 2.0 Python client library" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +certifi = ">=14.05.14" +python-dateutil = ">=2.5.3" +reactivex = ">=4.0.4" +setuptools = ">=21.0.0" +urllib3 = ">=1.26.0" + +[package.extras] +async = ["aiocsv (>=1.2.2)", "aiohttp (>=3.8.1)"] +ciso = ["ciso8601 (>=2.1.1)"] +extra = ["numpy", "pandas (>=0.25.3)"] +test = ["aioresponses (>=0.7.3)", "coverage (>=4.0.3)", "flake8 (>=5.0.3)", "httpretty (==1.0.5)", "jinja2 (==3.1.2)", "nose (>=1.3.7)", "pluggy (>=0.3.1)", "psutil (>=5.6.3)", "py (>=1.4.31)", "pytest (>=5.0.0)", "pytest-cov (>=3.0.0)", "randomize (>=0.13)", "sphinx (==1.8.5)", "sphinx-rtd-theme"] + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "inputs" +version = "0.5" +description = "Cross-platform Python support for keyboards, mice and gamepads." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "ipykernel" +version = "6.16.1" +description = "IPython Kernel for Jupyter" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +debugpy = ">=1.0" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=17" +tornado = ">=6.1" +traitlets = ">=5.1.0" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.5.0" +description = "IPython: Productive Interactive Computing" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">3.0.1,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" + +[package.extras] +all = ["Sphinx (>=1.3)", "black", "curio", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "testpath", "trio"] +black = ["black"] +doc = ["Sphinx (>=1.3)"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +description = "Vestigial utilities from IPython" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "ipywidgets" +version = "8.0.2" +description = "Jupyter interactive widgets" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +ipykernel = ">=4.5.1" +ipython = ">=6.1.0" +jupyterlab-widgets = ">=3.0,<4.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=4.0,<5.0" + +[package.extras] +test = ["jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] + +[[package]] +name = "isodate" +version = "0.6.1" +description = "An ISO 8601 date/time/duration parser and formatter" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + +[[package]] +name = "isort" +version = "5.10.1" +description = "A Python utility / library to sort Python imports." +category = "main" +optional = false +python-versions = ">=3.6.1,<4.0" + +[package.extras] +colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "itsdangerous" +version = "2.1.2" +description = "Safely pass data to untrusted environments and back." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "jaraco-classes" +version = "3.2.3" +description = "Utility functions for Python class constructs" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "jedi" +version = "0.18.1" +description = "An autocompletion tool for Python that can be used for text editors." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +parso = ">=0.8.0,<0.9.0" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jeepney" +version = "0.8.0" +description = "Low-level, pure Python DBus protocol wrapper." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["async_generator", "trio"] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "joblib" +version = "1.2.0" +description = "Lightweight pipelining with Python functions" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "json-logging-py" +version = "0.2" +description = "JSON / Logstash formatters for Python logging" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "json-rpc" +version = "1.13.0" +description = "JSON-RPC transport implementation" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "json5" +version = "0.9.10" +description = "A Python implementation of the JSON5 data format." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +dev = ["hypothesis"] + +[[package]] +name = "jsonschema" +version = "4.16.0" +description = "An implementation of JSON Schema validation for Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=17.4.0" +importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} +pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} +pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jupyter" +version = "1.0.0" +description = "Jupyter metapackage. Install all the Jupyter components in one go." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +ipykernel = "*" +ipywidgets = "*" +jupyter-console = "*" +nbconvert = "*" +notebook = "*" +qtconsole = "*" + +[[package]] +name = "jupyter-client" +version = "7.4.3" +description = "Jupyter protocol implementation and client libraries" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +entrypoints = "*" +jupyter-core = ">=4.9.2" +nest-asyncio = ">=1.5.4" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = "*" + +[package.extras] +doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyter-console" +version = "6.4.4" +description = "Jupyter terminal console" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +ipykernel = "*" +ipython = "*" +jupyter-client = ">=7.0.0" +prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" +pygments = "*" + +[package.extras] +test = ["pexpect"] + +[[package]] +name = "jupyter-core" +version = "4.11.2" +description = "Jupyter core package. A base package on which Jupyter projects rely." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = "*" + +[package.extras] +test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyter-server" +version = "1.21.0" +description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +anyio = ">=3.1.0,<4" +argon2-cffi = "*" +jinja2 = "*" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.7.0" +nbconvert = ">=6.4.4" +nbformat = ">=5.2.0" +packaging = "*" +prometheus-client = "*" +pywinpty = {version = "*", markers = "os_name == \"nt\""} +pyzmq = ">=17" +Send2Trash = "*" +terminado = ">=0.8.3" +tornado = ">=6.1.0" +traitlets = ">=5.1" +websocket-client = "*" + +[package.extras] +test = ["coverage", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-mock", "pytest-timeout", "pytest-tornasync", "requests"] + +[[package]] +name = "jupyterlab" +version = "3.4.8" +description = "JupyterLab computational environment" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +ipython = "*" +jinja2 = ">=2.1" +jupyter-core = "*" +jupyter-server = ">=1.16,<2.0" +jupyterlab-server = ">=2.10,<3.0" +nbclassic = "*" +notebook = "<7" +packaging = "*" +tomli = "*" +tornado = ">=6.1.0" + +[package.extras] +test = ["check-manifest", "coverage", "jupyterlab-server[test]", "pre-commit", "pytest (>=6.0)", "pytest-check-links (>=0.5)", "pytest-console-scripts", "pytest-cov", "requests", "requests-cache", "virtualenv"] +ui-tests = ["build"] + +[[package]] +name = "jupyterlab-pygments" +version = "0.2.2" +description = "Pygments theme using JupyterLab CSS variables" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "jupyterlab-server" +version = "2.16.1" +description = "A set of server components for JupyterLab and JupyterLab like applications." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +babel = "*" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jinja2 = ">=3.0.3" +json5 = "*" +jsonschema = ">=3.0.1" +jupyter-server = ">=1.8,<3" +packaging = "*" +requests = "*" + +[package.extras] +docs = ["autodoc-traits", "docutils (<0.19)", "jinja2 (<3.1.0)", "mistune (<1)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi"] +openapi = ["openapi-core (>=0.14.2)", "ruamel-yaml"] +test = ["codecov", "ipykernel", "jupyter-server[test]", "openapi-core (>=0.14.2,<0.15.0)", "openapi-spec-validator (<0.5)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "ruamel-yaml", "strict-rfc3339"] + +[[package]] +name = "jupyterlab-vim" +version = "0.15.1" +description = "Code cell vim bindings" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.3" +description = "Jupyter interactive widgets for JupyterLab" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "keyring" +version = "23.9.3" +description = "Store and access your passwords safely." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +"jaraco.classes" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = "<0.1.0 || >0.1.0,<0.1.1 || >0.1.1", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] +testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "kiwisolver" +version = "1.4.4" +description = "A fast implementation of the Cassowary constraint solver" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "knack" +version = "0.10.0" +description = "A Command-Line Interface framework" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +argcomplete = "*" +jmespath = "*" +pygments = "*" +pyyaml = "*" +tabulate = "*" + +[[package]] +name = "lazy-object-proxy" +version = "1.7.1" +description = "A fast and thorough lazy object proxy." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "libusb1" +version = "3.0.0" +description = "Pure-python wrapper for libusb-1.0" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "lockfile" +version = "0.12.2" +description = "Platform-independent file locking module" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "lru-dict" +version = "1.1.8" +description = "An Dict like LRU container." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "lxml" +version = "4.9.1" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=0.29.7)"] + +[[package]] +name = "mako" +version = "1.2.3" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + +[[package]] +name = "markdown" +version = "3.4.1" +description = "Python implementation of Markdown." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} + +[package.extras] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markdown-it-py" +version = "2.1.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"] +code-style = ["pre-commit (==2.6)"] +compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"] +linkify = ["linkify-it-py (>=1.0,<2.0)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "matplotlib" +version = "3.6.1" +description = "Python plotting package" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.19" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=7" + +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "mdit-py-plugins" +version = "0.3.1" +description = "Collection of plugins for markdown-it-py" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +markdown-it-py = ">=1.0.0,<3.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["attrs", "myst-parser (>=0.16.1,<0.17.0)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "mistune" +version = "2.0.4" +description = "A sane Markdown parser with useful plugins and renderers" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "more-itertools" +version = "9.0.0" +description = "More routines for operating on iterables, beyond itertools" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "mpld3" +version = "0.5.8" +description = "D3 Viewer for Matplotlib" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +jinja2 = "*" +matplotlib = "*" + +[[package]] +name = "mpmath" +version = "1.2.1" +description = "Python library for arbitrary-precision floating-point arithmetic" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] +tests = ["pytest (>=4.6)"] + +[[package]] +name = "msal" +version = "1.20.0b1" +description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +cryptography = ">=0.6,<40" +PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} +pymsalruntime = {version = ">=0.11.2,<0.12", optional = true, markers = "python_version >= \"3.6\" and platform_system == \"Windows\" and extra == \"broker\""} +requests = ">=2.0.0,<3" + +[package.extras] +broker = ["pymsalruntime (>=0.11.2,<0.12)"] + +[[package]] +name = "msal-extensions" +version = "1.0.0" +description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +msal = ">=0.4.1,<2.0.0" +portalocker = [ + {version = ">=1.0,<3", markers = "python_version >= \"3.5\" and platform_system != \"Windows\""}, + {version = ">=1.6,<3", markers = "python_version >= \"3.5\" and platform_system == \"Windows\""}, +] + +[[package]] +name = "msgpack" +version = "1.0.4" +description = "MessagePack serializer" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "msgpack-numpy" +version = "0.4.8" +description = "Numpy data serialization using msgpack" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +msgpack = ">=0.5.2" +numpy = ">=1.9.0" + +[[package]] +name = "msgpack-python" +version = "0.5.6" +description = "MessagePack (de)serializer." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "msrest" +version = "0.7.1" +description = "AutoRest swagger generator Python client runtime." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +azure-core = ">=1.24.0" +certifi = ">=2017.4.17" +isodate = ">=0.6.0" +requests = ">=2.16,<3.0" +requests-oauthlib = ">=0.5.0" + +[package.extras] +async = ["aiodns", "aiohttp (>=3.0)"] + +[[package]] +name = "msrestazure" +version = "0.6.4" +description = "AutoRest swagger generator Python client runtime. Azure-specific module." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +adal = ">=0.6.0,<2.0.0" +msrest = ">=0.6.0,<2.0.0" +six = "*" + +[[package]] +name = "multidict" +version = "6.0.2" +description = "multidict implementation" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "munch" +version = "2.5.0" +description = "A dot-accessible dictionary (a la JavaScript objects)" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + +[package.extras] +testing = ["astroid (>=1.5.3,<1.6.0)", "astroid (>=2.0)", "coverage", "pylint (>=1.7.2,<1.8.0)", "pylint (>=2.3.1,<2.4.0)", "pytest"] +yaml = ["PyYAML (>=5.1.0)"] + +[[package]] +name = "mypy" +version = "0.961" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "myst-parser" +version = "0.18.1" +description = "An extended commonmark compliant parser, with bridges to docutils & sphinx." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +docutils = ">=0.15,<0.20" +jinja2 = "*" +markdown-it-py = ">=1.0.0,<3.0.0" +mdit-py-plugins = ">=0.3.1,<0.4.0" +pyyaml = "*" +sphinx = ">=4,<6" +typing-extensions = "*" + +[package.extras] +code-style = ["pre-commit (>=2.12,<3.0)"] +linkify = ["linkify-it-py (>=1.0,<2.0)"] +rtd = ["ipython", "sphinx-book-theme", "sphinx-design", "sphinxcontrib.mermaid (>=0.7.1,<0.8.0)", "sphinxext-opengraph (>=0.6.3,<0.7.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=6,<7)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx (<5.2)", "sphinx-pytest"] + +[[package]] +name = "natsort" +version = "8.2.0" +description = "Simple yet flexible natural sorting in Python." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +fast = ["fastnumbers (>=2.0.0)"] +icu = ["PyICU (>=1.0.0)"] + +[[package]] +name = "nbclassic" +version = "0.4.7" +description = "A web-based notebook environment for interactive computing" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +argon2-cffi = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=6.1.1" +jupyter-core = ">=4.6.1" +jupyter-server = ">=1.8" +nbconvert = ">=5" +nbformat = "*" +nest-asyncio = ">=1.5" +notebook-shim = ">=0.1.0" +prometheus-client = "*" +pyzmq = ">=17" +Send2Trash = ">=1.8.0" +terminado = ">=0.8.3" +tornado = ">=6.1" +traitlets = ">=4.2.1" + +[package.extras] +docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +json-logging = ["json-logging"] +test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-tornasync", "requests", "requests-unixsocket", "selenium (==4.1.5)", "testpath"] + +[[package]] +name = "nbclient" +version = "0.7.0" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +category = "dev" +optional = false +python-versions = ">=3.7.0" + +[package.dependencies] +jupyter-client = ">=6.1.5" +nbformat = ">=5.0" +nest-asyncio = "*" +traitlets = ">=5.2.2" + +[package.extras] +sphinx = ["Sphinx (>=1.7)", "autodoc-traits", "mock", "moto", "myst-parser", "sphinx-book-theme"] +test = ["black", "check-manifest", "flake8", "ipykernel", "ipython", "ipywidgets", "mypy", "nbconvert", "pip (>=18.1)", "pre-commit", "pytest (>=4.1)", "pytest-asyncio", "pytest-cov (>=2.6.1)", "setuptools (>=60.0)", "testpath", "twine (>=1.11.0)", "xmltodict"] + +[[package]] +name = "nbconvert" +version = "7.2.2" +description = "Converting Jupyter Notebooks" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +beautifulsoup4 = "*" +bleach = "*" +defusedxml = "*" +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +jinja2 = ">=3.0" +jupyter-core = ">=4.7" +jupyterlab-pygments = "*" +markupsafe = ">=2.0" +mistune = ">=2.0.3,<3" +nbclient = ">=0.5.0" +nbformat = ">=5.1" +packaging = "*" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +tinycss2 = "*" +traitlets = ">=5.0" + +[package.extras] +all = ["ipykernel", "ipython", "ipywidgets (>=7)", "myst-parser", "nbsphinx (>=0.2.12)", "pre-commit", "pyppeteer (>=1,<1.1)", "pyqtwebengine (>=5.15)", "pytest", "pytest-cov", "pytest-dependency", "sphinx (==5.0.2)", "sphinx-rtd-theme", "tornado (>=6.1)"] +docs = ["ipython", "myst-parser", "nbsphinx (>=0.2.12)", "sphinx (==5.0.2)", "sphinx-rtd-theme"] +qtpdf = ["pyqtwebengine (>=5.15)"] +qtpng = ["pyqtwebengine (>=5.15)"] +serve = ["tornado (>=6.1)"] +test = ["ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)", "pytest", "pytest-cov", "pytest-dependency"] +webpdf = ["pyppeteer (>=1,<1.1)"] + +[[package]] +name = "nbformat" +version = "5.7.0" +description = "The Jupyter Notebook format" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +fastjsonschema = "*" +jsonschema = ">=2.6" +jupyter-core = "*" +traitlets = ">=5.1" + +[package.extras] +test = ["check-manifest", "pep440", "pre-commit", "pytest", "testpath"] + +[[package]] +name = "ncompress" +version = "1.0.0" +description = "LZW compression and decompression" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "nest-asyncio" +version = "1.5.6" +description = "Patch asyncio to allow nested event loops" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "networkx" +version = "2.3" +description = "Python package for creating and manipulating graphs and networks" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +decorator = ">=4.3.0" + +[package.extras] +all = ["gdal", "lxml", "matplotlib", "nose", "numpy", "pandas", "pydot", "pygraphviz", "pyyaml", "scipy"] +gdal = ["gdal"] +lxml = ["lxml"] +matplotlib = ["matplotlib"] +nose = ["nose"] +numpy = ["numpy"] +pandas = ["pandas"] +pydot = ["pydot"] +pygraphviz = ["pygraphviz"] +pyyaml = ["pyyaml"] +scipy = ["scipy"] + +[[package]] +name = "nodeenv" +version = "1.7.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "nose" +version = "1.3.7" +description = "nose extends unittest to make testing easier" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "notebook" +version = "6.4.12" +description = "A web-based notebook environment for interactive computing" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +argon2-cffi = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=5.3.4" +jupyter-core = ">=4.6.1" +nbconvert = ">=5" +nbformat = "*" +nest-asyncio = ">=1.5" +prometheus-client = "*" +pyzmq = ">=17" +Send2Trash = ">=1.8.0" +terminado = ">=0.8.3" +tornado = ">=6.1" +traitlets = ">=4.2.1" + +[package.extras] +docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +json-logging = ["json-logging"] +test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixsocket", "selenium", "testpath"] + +[[package]] +name = "notebook-shim" +version = "0.2.0" +description = "A shim layer for notebook traits and config" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +jupyter-server = ">=1.8,<3" + +[package.extras] +test = ["pytest", "pytest-console-scripts", "pytest-tornasync"] + +[[package]] +name = "numpy" +version = "1.23.4" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.8" + +[[package]] +name = "nvidia-ml-py3" +version = "7.352.0" +description = "Python Bindings for the NVIDIA Management Library" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "oauthlib" +version = "3.2.2" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +rsa = ["cryptography (>=3.0.0)"] +signals = ["blinker (>=1.4.0)"] +signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] + +[[package]] +name = "onnx" +version = "1.12.0" +description = "Open Neural Network Exchange" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = ">=1.16.6" +protobuf = ">=3.12.2,<=3.20.1" +typing-extensions = ">=3.6.2.1" + +[package.extras] +lint = ["clang-format (==13.0.0)", "flake8", "mypy (==0.782)", "types-protobuf (==3.18.4)"] + +[[package]] +name = "onnxoptimizer" +version = "0.2.7" +description = "Open Neural Network Exchange" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +onnx = "*" + +[package.extras] +mypy = ["mypy (==0.600)"] + +[[package]] +name = "onnxruntime-gpu" +version = "1.12.1" +description = "ONNX Runtime is a runtime accelerator for Machine Learning models" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +coloredlogs = "*" +flatbuffers = "*" +numpy = ">=1.21.0" +packaging = "*" +protobuf = "*" +sympy = "*" + +[[package]] +name = "opencv-python-headless" +version = "4.5.5.64" +description = "Wrapper package for OpenCV python bindings." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +numpy = [ + {version = ">=1.21.2", markers = "python_version >= \"3.6\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, + {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\""}, + {version = ">=1.14.5", markers = "python_version >= \"3.7\""}, + {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, +] + +[package.source] +type = "url" +url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" +[[package]] +name = "osmium" +version = "3.4.1" +description = "Python bindings for libosmium, the data processing library for OSM data" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +requests = "*" + +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + +[[package]] +name = "pandas" +version = "1.5.1" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = {version = ">=1.20.3", markers = "python_version < \"3.10\""} +python-dateutil = ">=2.8.1" +pytz = ">=2020.1" + +[package.extras] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] + +[[package]] +name = "pandocfilters" +version = "1.5.0" +description = "Utilities for writing pandoc filters in python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "parameterized" +version = "0.8.1" +description = "Parameterized testing with any Python test framework" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +dev = ["jinja2"] + +[[package]] +name = "paramiko" +version = "2.11.0" +description = "SSH2 protocol library" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +bcrypt = ">=3.1.3" +cryptography = ">=2.5" +pynacl = ">=1.0.1" +six = "*" + +[package.extras] +all = ["bcrypt (>=3.1.3)", "gssapi (>=1.4.1)", "invoke (>=1.3)", "pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "pywin32 (>=2.1.8)"] +ed25519 = ["bcrypt (>=3.1.3)", "pynacl (>=1.0.1)"] +gssapi = ["gssapi (>=1.4.1)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] +invoke = ["invoke (>=1.3)"] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pillow" +version = "9.2.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pillow-avif-plugin" +version = "1.2.2" +description = "A pillow plugin that adds avif support via libavif" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pipenv" +version = "2022.10.12" +description = "Python Development Workflow for Humans." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +certifi = "*" +setuptools = ">=36.2.1" +virtualenv = "*" +virtualenv-clone = ">=0.2.5" + +[package.extras] +dev = ["black", "bs4", "flake8 (>=3.3.0,<4.0)", "invoke", "parver", "sphinx", "towncrier"] +tests = ["flaky", "mock", "pytest (>=5.0)", "pytest-timeout", "pytest-xdist"] + +[[package]] +name = "pkginfo" +version = "1.8.3" +description = "Query metadatdata from sdists / bdists / installed packages." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.extras] +testing = ["coverage", "nose"] + +[[package]] +name = "pkgutil-resolve-name" +version = "1.3.10" +description = "Resolve a name to an object." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "platformdirs" +version = "2.5.2" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "plotly" +version = "5.10.0" +description = "An open-source, interactive data visualization library for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +tenacity = ">=6.2.0" + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "poetry" +version = "1.2.2" +description = "Python dependency management and packaging made easy." +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +cachecontrol = {version = ">=0.12.9,<0.13.0", extras = ["filecache"]} +cachy = ">=0.3.0,<0.4.0" +cleo = ">=1.0.0a5,<2.0.0" +crashtest = ">=0.3.0,<0.4.0" +dulwich = ">=0.20.46,<0.21.0" +html5lib = ">=1.0,<2.0" +importlib-metadata = {version = ">=4.4,<5.0", markers = "python_version < \"3.10\""} +jsonschema = ">=4.10.0,<5.0.0" +keyring = ">=21.2.0" +packaging = ">=20.4" +pexpect = ">=4.7.0,<5.0.0" +pkginfo = ">=1.5,<2.0" +platformdirs = ">=2.5.2,<3.0.0" +poetry-core = "1.3.2" +poetry-plugin-export = ">=1.1.2,<2.0.0" +requests = ">=2.18,<3.0" +requests-toolbelt = ">=0.9.1,<0.10.0" +shellingham = ">=1.5,<2.0" +tomlkit = ">=0.11.1,<0.11.2 || >0.11.2,<0.11.3 || >0.11.3,<1.0.0" +urllib3 = ">=1.26.0,<2.0.0" +virtualenv = ">=20.4.3,<20.4.5 || >20.4.5,<20.4.6 || >20.4.6" +xattr = {version = ">=0.9.7,<0.10.0", markers = "sys_platform == \"darwin\""} + +[[package]] +name = "poetry-core" +version = "1.3.2" +description = "Poetry PEP 517 Build Backend" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[[package]] +name = "poetry-plugin-export" +version = "1.1.2" +description = "Poetry plugin to export the dependencies to various formats" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +poetry = ">=1.2.0,<2.0.0" +poetry-core = ">=1.1.0,<2.0.0" + +[[package]] +name = "portalocker" +version = "2.6.0" +description = "Wraps the portalocker recipe for easy usage" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} + +[package.extras] +docs = ["sphinx (>=1.7.1)"] +redis = ["redis"] +tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=3.0.3)"] + +[[package]] +name = "pprofile" +version = "2.1.0" +description = "Line-granularity, thread-aware deterministic and statistic pure-python profiler" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pre-commit" +version = "2.20.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +toml = "*" +virtualenv = ">=20.0.8" + +[[package]] +name = "pretrainedmodels" +version = "0.7.4" +description = "Pretrained models for Pytorch" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +munch = "*" +torch = "*" +torchvision = "*" +tqdm = "*" + +[[package]] +name = "prometheus-client" +version = "0.15.0" +description = "Python client for the Prometheus monitoring system." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.31" +description = "Library for building powerful interactive command lines in Python" +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "protobuf" +version = "3.20.1" +description = "Protocol Buffers" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "psutil" +version = "5.9.3" +description = "Cross-platform lib for process and system monitoring in Python." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pycapnp" +version = "1.1.0" +description = "A cython wrapping of the C++ Cap'n Proto library" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pycodestyle" +version = "2.8.0" +description = "Python style guide checker" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pycryptodome" +version = "3.15.0" +description = "Cryptographic library for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pycuda" +version = "2022.1" +description = "Python wrapper for Nvidia CUDA" +category = "dev" +optional = false +python-versions = "~=3.6" + +[package.dependencies] +appdirs = ">=1.4.0" +mako = "*" +pytools = ">=2011.2" + +[[package]] +name = "pycurl" +version = "7.45.1" +description = "PycURL -- A Python Interface To The cURL library" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "pyflakes" +version = "2.4.0" +description = "passive checker of Python programs" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pygame" +version = "2.1.2" +description = "Python Game Development" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "pygments" +version = "2.13.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pyjwt" +version = "2.6.0" +description = "JSON Web Token implementation in Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pylev" +version = "1.4.0" +description = "A pure Python Levenshtein implementation that's not freaking GPL'd." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pylint" +version = "2.15.4" +description = "python code static checker" +category = "main" +optional = false +python-versions = ">=3.7.2" + +[package.dependencies] +astroid = ">=2.12.11,<=2.14.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = ">=0.2" +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pymsalruntime" +version = "0.11.2" +description = "The MSALRuntime Python Interop Package" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "pymysql" +version = "0.9.3" +description = "Pure Python MySQL Driver" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +rsa = ["cryptography"] + +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx_rtd_theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + +[[package]] +name = "pyopencl" +version = "2022.2.4" +description = "Python wrapper for OpenCL" +category = "main" +optional = false +python-versions = "~=3.6" + +[package.dependencies] +numpy = "*" +platformdirs = ">=2.2.0" +pytools = ">=2021.2.7" + +[package.extras] +oclgrind = ["oclgrind-binary-distribution (>=18.3)"] +pocl = ["pocl-binary-distribution (>=1.2)"] +test = ["Mako", "pytest (>=7.0.0)"] + +[[package]] +name = "pyopenssl" +version = "22.0.0" +description = "Python wrapper module around the OpenSSL library" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cryptography = ">=35.0" + +[package.extras] +docs = ["sphinx", "sphinx-rtd-theme"] +test = ["flaky", "pretend", "pytest (>=3.0.1)"] + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyprof2calltree" +version = "1.4.5" +description = "Help visualize profiling data from cProfile with kcachegrind and qcachegrind" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyproj" +version = "3.4.0" +description = "Python interface to PROJ (cartographic projections and coordinate transformations library)" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +certifi = "*" + +[[package]] +name = "pyreadline3" +version = "3.4.1" +description = "A python implementation of GNU readline." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyrsistent" +version = "0.18.1" +description = "Persistent/Functional/Immutable data structures" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pyserial" +version = "3.5" +description = "Python Serial Port Extension" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +cp2110 = ["hidapi"] + +[[package]] +name = "pysocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pytest" +version = "7.1.3" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +tomli = ">=1.0.0" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-forked" +version = "1.4.0" +description = "run tests in isolated forked subprocesses" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +py = "*" +pytest = ">=3.10" + +[[package]] +name = "pytest-xdist" +version = "2.5.0" +description = "pytest xdist plugin for distributed testing and loop-on-failing modes" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.2.0" +pytest-forked = "*" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-engineio" +version = "4.3.4" +description = "Engine.IO server and client for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +asyncio-client = ["aiohttp (>=3.4)"] +client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] + +[[package]] +name = "python-logstash" +version = "0.4.8" +description = "Python logging handler for Logstash." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "python-socketio" +version = "5.7.2" +description = "Socket.IO server and client for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +bidict = ">=0.21.0" +python-engineio = ">=4.3.0" + +[package.extras] +asyncio-client = ["aiohttp (>=3.4)"] +client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] + +[[package]] +name = "pytools" +version = "2022.1.12" +description = "A collection of tools for Python" +category = "main" +optional = false +python-versions = "~=3.6" + +[package.dependencies] +platformdirs = ">=2.2.0" +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +numpy = ["numpy (>=1.6.0)"] + +[[package]] +name = "pytz" +version = "2022.5" +description = "World timezone definitions, modern and historical" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pywavelets" +version = "1.4.1" +description = "PyWavelets, wavelet transform module" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = ">=1.17.3" + +[[package]] +name = "pywin32" +version = "304" +description = "Python for Window Extensions" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pywin32-ctypes" +version = "0.2.0" +description = "" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pywinpty" +version = "2.0.8" +description = "Pseudo terminal support for Windows from Python." +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "pyzmq" +version = "23.2.1" +description = "Python bindings for 0MQ" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} +py = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "qtconsole" +version = "5.3.2" +description = "Jupyter Qt console" +category = "dev" +optional = false +python-versions = ">= 3.7" + +[package.dependencies] +ipykernel = ">=4.1" +ipython-genutils = "*" +jupyter-client = ">=4.1" +jupyter-core = "*" +pygments = "*" +pyzmq = ">=17.1" +qtpy = ">=2.0.1" +traitlets = "<5.2.1 || >5.2.1,<5.2.2 || >5.2.2" + +[package.extras] +doc = ["Sphinx (>=1.3)"] +test = ["flaky", "pytest", "pytest-qt"] + +[[package]] +name = "qtpy" +version = "2.2.1" +description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +packaging = "*" + +[package.extras] +test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] + +[[package]] +name = "qudida" +version = "0.0.4" +description = "QUick and DIrty Domain Adaptation" +category = "dev" +optional = false +python-versions = ">=3.5.0" + +[package.dependencies] +numpy = ">=0.18.0" +opencv-python-headless = ">=4.0.1" +scikit-learn = ">=0.19.1" +typing-extensions = "*" + +[[package]] +name = "reactivex" +version = "4.0.4" +description = "ReactiveX (Rx) for Python" +category = "dev" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +typing-extensions = ">=4.1.1,<5.0.0" + +[[package]] +name = "redis" +version = "4.3.4" +description = "Python client for Redis database and key-value store" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +async-timeout = ">=4.0.2" +deprecated = ">=1.2.3" +packaging = ">=20.4" + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7", optional = true, markers = "extra == \"socks\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-oauthlib" +version = "1.3.1" +description = "OAuthlib authentication support for Requests." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +oauthlib = ">=3.0.0" +requests = ">=2.0.0" + +[package.extras] +rsa = ["oauthlib[signedtoken] (>=3.0.0)"] + +[[package]] +name = "requests-toolbelt" +version = "0.9.1" +description = "A utility belt for advanced users of python-requests" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "reverse-geocoder" +version = "1.5.1" +description = "Fast, offline reverse geocoder" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = ">=1.11.0" +scipy = ">=0.17.1" + +[[package]] +name = "s2sphere" +version = "0.2.5" +description = "Python implementation of the S2 Geometry Library" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +future = ">=0.15" + +[package.extras] +docs = ["Sphinx (>=1.6.5)", "sphinx-rtd-theme (>=0.1.9)"] +tests = ["flake8 (>=2.5.4)", "hacking (>=0.11.0)", "nose (>=1.3.4)", "numpy (>=1.11.0)"] + +[[package]] +name = "scikit-image" +version = "0.19.3" +description = "Image processing in Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +imageio = ">=2.4.1" +networkx = ">=2.2" +numpy = ">=1.17.0" +packaging = ">=20.0" +pillow = ">=6.1.0,<7.1.0 || >7.1.0,<7.1.1 || >7.1.1,<8.3.0 || >8.3.0" +PyWavelets = ">=1.1.1" +scipy = ">=1.4.1" +tifffile = ">=2019.7.26" + +[package.extras] +data = ["pooch (>=1.3.0)"] +docs = ["cloudpickle (>=0.2.1)", "dask[array] (>=0.15.0,!=2.17.0)", "ipywidgets", "kaleido", "matplotlib (>=3.3)", "myst-parser", "numpydoc (>=1.0)", "pandas (>=0.23.0)", "plotly (>=4.14.0)", "pooch (>=1.3.0)", "pytest-runner", "scikit-learn", "seaborn (>=0.7.1)", "sphinx (>=1.8)", "sphinx-copybutton", "sphinx-gallery (>=0.10.1)", "tifffile (>=2020.5.30)"] +optional = ["SimpleITK", "astropy (>=3.1.2)", "cloudpickle (>=0.2.1)", "dask[array] (>=1.0.0,!=2.17.0)", "matplotlib (>=3.0.3)", "pooch (>=1.3.0)", "pyamg", "qtpy"] +test = ["asv", "codecov", "flake8", "matplotlib (>=3.0.3)", "pooch (>=1.3.0)", "pytest (>=5.2.0)", "pytest-cov (>=2.7.0)", "pytest-faulthandler", "pytest-localserver"] + +[[package]] +name = "scikit-learn" +version = "1.1.2" +description = "A set of python modules for machine learning and data mining" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +joblib = ">=1.0.0" +numpy = ">=1.17.3" +scipy = ">=1.3.2" +threadpoolctl = ">=2.0.0" + +[package.extras] +benchmark = ["matplotlib (>=3.1.2)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.2)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.1.2)", "pandas (>=1.0.5)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=22.3.0)", "flake8 (>=3.8.2)", "matplotlib (>=3.1.2)", "mypy (>=0.961)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pyamg (>=4.0.0)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "scikit-image (>=0.16.2)"] + +[[package]] +name = "scipy" +version = "1.9.3" +description = "Fundamental algorithms for scientific computing in Python" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = ">=1.18.5,<1.26.0" + +[package.extras] +dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] +test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "scons" +version = "4.4.0" +description = "Open Source next-generation build tool." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + +[[package]] +name = "segmentation-models-pytorch" +version = "0.2.1" +description = "Image segmentation models with pre-trained backbones. PyTorch." +category = "dev" +optional = false +python-versions = ">=3.0.0" + +[package.dependencies] +efficientnet-pytorch = "0.6.3" +pretrainedmodels = "0.7.4" +timm = "0.4.12" +torchvision = ">=0.5.0" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "send2trash" +version = "1.8.0" +description = "Send file to trash natively under Mac OS X, Windows and Linux." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +nativelib = ["pyobjc-framework-Cocoa", "pywin32"] +objc = ["pyobjc-framework-Cocoa"] +win32 = ["pywin32"] + +[[package]] +name = "sentry-sdk" +version = "1.10.0" +description = "Python client for Sentry (https://sentry.io)" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +certifi = "*" +urllib3 = {version = ">=1.26.11", markers = "python_version >= \"3.6\""} + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +chalice = ["chalice (>=1.16.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)"] +httpx = ["httpx (>=0.16.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +tornado = ["tornado (>=5)"] + +[[package]] +name = "setproctitle" +version = "1.3.2" +description = "A Python module to customize the process title" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "setuptools" +version = "65.5.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "setuptools-scm" +version = "7.0.5" +description = "the blessed package to manage your versions by scm tags" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +packaging = ">=20.0" +setuptools = "*" +tomli = ">=1.0.0" +typing-extensions = "*" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + +[[package]] +name = "shellingham" +version = "1.5.0" +description = "Tool to Detect Surrounding Shell" +category = "main" +optional = false +python-versions = ">=3.4" + +[[package]] +name = "simplejson" +version = "3.17.6" +description = "Simple, fast, extensible JSON encoder/decoder for Python" +category = "dev" +optional = false +python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "smbus2" +version = "0.4.2" +description = "smbus2 is a drop-in replacement for smbus-cffi/smbus-python in pure Python" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +docs = ["sphinx (>=1.5.3)"] +qa = ["flake8"] +test = ["mock", "nose"] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "soupsieve" +version = "2.3.2.post1" +description = "A modern CSS selector implementation for Beautiful Soup." +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "sphinx" +version = "5.3.0" +description = "Python documentation generator" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.14,<0.20" +imagesize = ">=1.3" +importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.12" +requests = ">=2.5.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] +test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] + +[[package]] +name = "sphinx-rtd-theme" +version = "1.0.0" +description = "Read the Docs theme for Sphinx" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +docutils = "<0.18" +sphinx = ">=1.6" + +[package.extras] +dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"] + +[[package]] +name = "sphinx-sitemap" +version = "2.2.0" +description = "Sitemap generator for Sphinx" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" +sphinx = ">=1.2" + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.2" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sqlalchemy" +version = "1.4.42" +description = "Database Abstraction Library" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} + +[package.extras] +aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql", "pymysql (<1)"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "stack-data" +version = "0.5.1" +description = "Extract data from python stack frames and tracebacks for informative displays" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +asttokens = "*" +executing = "*" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "subprocess32" +version = "3.5.4" +description = "A backport of the subprocess module from Python 3 for use on 2.x." +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" + +[[package]] +name = "sympy" +version = "1.11.1" +description = "Computer algebra system (CAS) in Python" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +mpmath = ">=0.19" + +[[package]] +name = "tabulate" +version = "0.8.10" +description = "Pretty-print tabular data" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "tenacity" +version = "8.1.0" +description = "Retry code until it succeeds" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "terminado" +version = "0.16.0" +description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +ptyprocess = {version = "*", markers = "os_name != \"nt\""} +pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} +tornado = ">=6.1.0" + +[package.extras] +test = ["pre-commit", "pytest (>=6.0)", "pytest-timeout"] + +[[package]] +name = "threadpoolctl" +version = "3.1.0" +description = "threadpoolctl" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "tifffile" +version = "2022.10.10" +description = "Read and write TIFF files" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = ">=1.19.2" + +[package.extras] +all = ["fsspec", "imagecodecs (>=2022.2.22)", "lxml", "matplotlib (>=3.3)", "zarr"] + +[[package]] +name = "timezonefinder" +version = "6.1.3" +description = "fast python package for finding the timezone of any point on earth (coordinates) offline" +category = "main" +optional = false +python-versions = ">=3.8,<3.11" + +[package.dependencies] +cffi = ">=1.15.1,<2.0.0" +h3 = ">=3.7.3,<4.0.0" +numpy = ">=1.22,<2.0" +setuptools = ">=65.3.0,<66.0.0" + +[package.extras] +numba = ["numba (>=0.55.2,<0.56.0)"] + +[[package]] +name = "timm" +version = "0.4.12" +description = "(Unofficial) PyTorch Image Models" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +torch = ">=1.4" +torchvision = "*" + +[[package]] +name = "tinycss2" +version = "1.2.1" +description = "A tiny CSS parser" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "tomlkit" +version = "0.11.5" +description = "Style preserving TOML library" +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[[package]] +name = "torch" +version = "1.11.0+cu113" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +category = "dev" +optional = false +python-versions = ">=3.7.0" + +[package.dependencies] +typing-extensions = "*" + +[package.source] +type = "url" +url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" +[[package]] +name = "torchsummary" +version = "1.5.1" +description = "Model summary in PyTorch similar to `model.summary()` in Keras" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "torchvision" +version = "0.12.0+cu113" +description = "image and video datasets and models for torch deep learning" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = "*" +pillow = ">=5.3.0,<8.3.0 || >=8.4.0" +requests = "*" +torch = "1.11.0" +typing-extensions = "*" + +[package.extras] +scipy = ["scipy"] + +[package.source] +type = "url" +url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" +[[package]] +name = "tornado" +version = "6.2" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +category = "dev" +optional = false +python-versions = ">= 3.7" + +[[package]] +name = "tqdm" +version = "4.64.1" +description = "Fast, Extensible Progress Meter" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "traitlets" +version = "5.5.0" +description = "" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["pre-commit", "pytest"] + +[[package]] +name = "triton" +version = "1.1.1" +description = "A language and compiler for custom Deep Learning operations" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +filelock = "*" +torch = "*" + +[[package]] +name = "types-atomicwrites" +version = "1.4.5.1" +description = "Typing stubs for atomicwrites" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "types-certifi" +version = "2021.10.8.3" +description = "Typing stubs for certifi" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "types-pycurl" +version = "7.45.1" +description = "Typing stubs for pycurl" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "types-pyyaml" +version = "6.0.12" +description = "Typing stubs for PyYAML" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "types-requests" +version = "2.28.11.2" +description = "Typing stubs for requests" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +types-urllib3 = "<1.27" + +[[package]] +name = "types-urllib3" +version = "1.26.25.1" +description = "Typing stubs for urllib3" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "typing-extensions" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "utm" +version = "0.7.0" +description = "Bidirectional UTM-WGS84 converter for python" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "virtualenv" +version = "20.16.5" +description = "Virtual Python Environment builder" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +distlib = ">=0.3.5,<1" +filelock = ">=3.4.1,<4" +platformdirs = ">=2.4,<3" + +[package.extras] +docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"] +testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "virtualenv-clone" +version = "0.5.7" +description = "script to clone virtualenvs." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "wcwidth" +version = "0.2.5" +description = "Measures the displayed width of unicode strings in a terminal" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "websocket-client" +version = "1.4.1" +description = "WebSocket client for Python with low level API options" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"] +optional = ["python-socks", "wsaccel"] +test = ["websockets"] + +[[package]] +name = "werkzeug" +version = "2.2.2" +description = "The comprehensive WSGI web application library." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog"] + +[[package]] +name = "widgetsnbextension" +version = "4.0.3" +description = "Jupyter interactive widgets for Jupyter Notebook" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "xattr" +version = "0.9.9" +description = "Python wrapper for extended filesystem attributes" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +cffi = ">=1.0" + +[[package]] +name = "yarl" +version = "1.8.1" +description = "Yet another URL library" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[[package]] +name = "zerorpc" +version = "0.6.3" +description = "zerorpc is a flexible RPC based on zeromq." +category = "dev" +optional = false +python-versions = "*" +develop = false + +[package.dependencies] +future = "*" +gevent = ">=1.1" +msgpack = ">=0.5.2" +msgpack-numpy = ">=0.4.3" +pyzmq = ">=13.1.0" + +[package.source] +type = "git" +url = "git@github.com:commaai/zerorpc-python.git" +reference = "master" +resolved_reference = "0e27fd795bb9a7ec9cab81a771a2e35a91e397c9" + +[[package]] +name = "zipp" +version = "3.9.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "zope-event" +version = "4.5.0" +description = "Very basic event publishing system" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +setuptools = "*" + +[package.extras] +docs = ["Sphinx"] +test = ["zope.testrunner"] + +[[package]] +name = "zope-interface" +version = "5.5.0" +description = "Interfaces for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +setuptools = "*" + +[package.extras] +docs = ["Sphinx", "repoze.sphinx.autointerface"] +test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] +testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] + +[metadata] +lock-version = "1.1" +python-versions = "~3.8" +content-hash = "f357744f2550b64cbd25e35881d6ec3c1180c90f830eb8d9f53322d6de485561" + +[metadata.files] +adal = [ + {file = "adal-1.2.7-py2.py3-none-any.whl", hash = "sha256:2a7451ed7441ddbc57703042204a3e30ef747478eea022c70f789fc7f084bc3d"}, + {file = "adal-1.2.7.tar.gz", hash = "sha256:d74f45b81317454d96e982fd1c50e6fb5c99ac2223728aea8764433a39f566f1"}, +] +aenum = [ + {file = "aenum-3.1.11-py2-none-any.whl", hash = "sha256:525b4870a27d0b471c265bda692bc657f1e0dd7597ad4186d072c59f9db666f6"}, + {file = "aenum-3.1.11-py3-none-any.whl", hash = "sha256:12ae89967f2e25c0ce28c293955d643f891603488bc3d9946158ba2b35203638"}, + {file = "aenum-3.1.11.tar.gz", hash = "sha256:aed2c273547ae72a0d5ee869719c02a643da16bf507c80958faadc7e038e3f73"}, +] +aiohttp = [ + {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"}, + {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e"}, + {file = "aiohttp-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97decbb3372d4b69e4d4c8117f44632551c692bb1361b356a02b97b69e18a62"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309aa21c1d54b8ef0723181d430347d7452daaff93e8e2363db8e75c72c2fb2d"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad5383a67514e8e76906a06741febd9126fc7c7ff0f599d6fcce3e82b80d026f"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20acae4f268317bb975671e375493dbdbc67cddb5f6c71eebdb85b34444ac46b"}, + {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05a3c31c6d7cd08c149e50dc7aa2568317f5844acd745621983380597f027a18"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6f76310355e9fae637c3162936e9504b4767d5c52ca268331e2756e54fd4ca5"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:256deb4b29fe5e47893fa32e1de2d73c3afe7407738bd3c63829874661d4822d"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5c59fcd80b9049b49acd29bd3598cada4afc8d8d69bd4160cd613246912535d7"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:059a91e88f2c00fe40aed9031b3606c3f311414f86a90d696dd982e7aec48142"}, + {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2feebbb6074cdbd1ac276dbd737b40e890a1361b3cc30b74ac2f5e24aab41f7b"}, + {file = "aiohttp-3.8.3-cp310-cp310-win32.whl", hash = "sha256:5bf651afd22d5f0c4be16cf39d0482ea494f5c88f03e75e5fef3a85177fecdeb"}, + {file = "aiohttp-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:653acc3880459f82a65e27bd6526e47ddf19e643457d36a2250b85b41a564715"}, + {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:86fc24e58ecb32aee09f864cb11bb91bc4c1086615001647dbfc4dc8c32f4008"}, + {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75e14eac916f024305db517e00a9252714fce0abcb10ad327fb6dcdc0d060f1d"}, + {file = "aiohttp-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1fde0f44029e02d02d3993ad55ce93ead9bb9b15c6b7ccd580f90bd7e3de476"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab94426ddb1ecc6a0b601d832d5d9d421820989b8caa929114811369673235c"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89d2e02167fa95172c017732ed7725bc8523c598757f08d13c5acca308e1a061"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9a2c72fc95d59b881cf38a4b2be9381b9527f9d328771e90f72ac76f31ad8"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7149272fb5834fc186328e2c1fa01dda3e1fa940ce18fded6d412e8f2cf76d"}, + {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7018ecc5fe97027214556afbc7c502fbd718d0740e87eb1217b17efd05b3d276"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88c70ed9da9963d5496d38320160e8eb7e5f1886f9290475a881db12f351ab5d"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:da22885266bbfb3f78218dc40205fed2671909fbd0720aedba39b4515c038091"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:e65bc19919c910127c06759a63747ebe14f386cda573d95bcc62b427ca1afc73"}, + {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:08c78317e950e0762c2983f4dd58dc5e6c9ff75c8a0efeae299d363d439c8e34"}, + {file = "aiohttp-3.8.3-cp311-cp311-win32.whl", hash = "sha256:45d88b016c849d74ebc6f2b6e8bc17cabf26e7e40c0661ddd8fae4c00f015697"}, + {file = "aiohttp-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:96372fc29471646b9b106ee918c8eeb4cca423fcbf9a34daa1b93767a88a2290"}, + {file = "aiohttp-3.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c971bf3786b5fad82ce5ad570dc6ee420f5b12527157929e830f51c55dc8af77"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff25f48fc8e623d95eca0670b8cc1469a83783c924a602e0fbd47363bb54aaca"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e381581b37db1db7597b62a2e6b8b57c3deec95d93b6d6407c5b61ddc98aca6d"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db19d60d846283ee275d0416e2a23493f4e6b6028825b51290ac05afc87a6f97"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25892c92bee6d9449ffac82c2fe257f3a6f297792cdb18ad784737d61e7a9a85"}, + {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398701865e7a9565d49189f6c90868efaca21be65c725fc87fc305906be915da"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4a4fbc769ea9b6bd97f4ad0b430a6807f92f0e5eb020f1e42ece59f3ecfc4585"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b29bfd650ed8e148f9c515474a6ef0ba1090b7a8faeee26b74a8ff3b33617502"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e56b9cafcd6531bab5d9b2e890bb4937f4165109fe98e2b98ef0dcfcb06ee9d"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ec40170327d4a404b0d91855d41bfe1fe4b699222b2b93e3d833a27330a87a6d"}, + {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2df5f139233060578d8c2c975128fb231a89ca0a462b35d4b5fcf7c501ebdbe1"}, + {file = "aiohttp-3.8.3-cp36-cp36m-win32.whl", hash = "sha256:f973157ffeab5459eefe7b97a804987876dd0a55570b8fa56b4e1954bf11329b"}, + {file = "aiohttp-3.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:437399385f2abcd634865705bdc180c8314124b98299d54fe1d4c8990f2f9494"}, + {file = "aiohttp-3.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:09e28f572b21642128ef31f4e8372adb6888846f32fecb288c8b0457597ba61a"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f3553510abdbec67c043ca85727396ceed1272eef029b050677046d3387be8d"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e168a7560b7c61342ae0412997b069753f27ac4862ec7867eff74f0fe4ea2ad9"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db4c979b0b3e0fa7e9e69ecd11b2b3174c6963cebadeecfb7ad24532ffcdd11a"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e164e0a98e92d06da343d17d4e9c4da4654f4a4588a20d6c73548a29f176abe2"}, + {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8a78079d9a39ca9ca99a8b0ac2fdc0c4d25fc80c8a8a82e5c8211509c523363"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:21b30885a63c3f4ff5b77a5d6caf008b037cb521a5f33eab445dc566f6d092cc"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4b0f30372cef3fdc262f33d06e7b411cd59058ce9174ef159ad938c4a34a89da"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8135fa153a20d82ffb64f70a1b5c2738684afa197839b34cc3e3c72fa88d302c"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ad61a9639792fd790523ba072c0555cd6be5a0baf03a49a5dd8cfcf20d56df48"}, + {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978b046ca728073070e9abc074b6299ebf3501e8dee5e26efacb13cec2b2dea0"}, + {file = "aiohttp-3.8.3-cp37-cp37m-win32.whl", hash = "sha256:0d2c6d8c6872df4a6ec37d2ede71eff62395b9e337b4e18efd2177de883a5033"}, + {file = "aiohttp-3.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:21d69797eb951f155026651f7e9362877334508d39c2fc37bd04ff55b2007091"}, + {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ca9af5f8f5812d475c5259393f52d712f6d5f0d7fdad9acdb1107dd9e3cb7eb"}, + {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d90043c1882067f1bd26196d5d2db9aa6d268def3293ed5fb317e13c9413ea4"}, + {file = "aiohttp-3.8.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d737fc67b9a970f3234754974531dc9afeea11c70791dcb7db53b0cf81b79784"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf909ea0a3fc9596e40d55d8000702a85e27fd578ff41a5500f68f20fd32e6c"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5835f258ca9f7c455493a57ee707b76d2d9634d84d5d7f62e77be984ea80b849"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da37dcfbf4b7f45d80ee386a5f81122501ec75672f475da34784196690762f4b"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f44875f2804bc0511a69ce44a9595d5944837a62caecc8490bbdb0e18b1342"}, + {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:527b3b87b24844ea7865284aabfab08eb0faf599b385b03c2aa91fc6edd6e4b6"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5ba88df9aa5e2f806650fcbeedbe4f6e8736e92fc0e73b0400538fd25a4dd96"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e7b8813be97cab8cb52b1375f41f8e6804f6507fe4660152e8ca5c48f0436017"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2dea10edfa1a54098703cb7acaa665c07b4e7568472a47f4e64e6319d3821ccf"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:713d22cd9643ba9025d33c4af43943c7a1eb8547729228de18d3e02e278472b6"}, + {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2d252771fc85e0cf8da0b823157962d70639e63cb9b578b1dec9868dd1f4f937"}, + {file = "aiohttp-3.8.3-cp38-cp38-win32.whl", hash = "sha256:66bd5f950344fb2b3dbdd421aaa4e84f4411a1a13fca3aeb2bcbe667f80c9f76"}, + {file = "aiohttp-3.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:84b14f36e85295fe69c6b9789b51a0903b774046d5f7df538176516c3e422446"}, + {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16c121ba0b1ec2b44b73e3a8a171c4f999b33929cd2397124a8c7fcfc8cd9e06"}, + {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d6aaa4e7155afaf994d7924eb290abbe81a6905b303d8cb61310a2aba1c68ba"}, + {file = "aiohttp-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43046a319664a04b146f81b40e1545d4c8ac7b7dd04c47e40bf09f65f2437346"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599418aaaf88a6d02a8c515e656f6faf3d10618d3dd95866eb4436520096c84b"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a2964319d359f494f16011e23434f6f8ef0434acd3cf154a6b7bec511e2fb7"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73a4131962e6d91109bca6536416aa067cf6c4efb871975df734f8d2fd821b37"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598adde339d2cf7d67beaccda3f2ce7c57b3b412702f29c946708f69cf8222aa"}, + {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75880ed07be39beff1881d81e4a907cafb802f306efd6d2d15f2b3c69935f6fb"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0239da9fbafd9ff82fd67c16704a7d1bccf0d107a300e790587ad05547681c8"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4e3a23ec214e95c9fe85a58470b660efe6534b83e6cbe38b3ed52b053d7cb6ad"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:47841407cc89a4b80b0c52276f3cc8138bbbfba4b179ee3acbd7d77ae33f7ac4"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:54d107c89a3ebcd13228278d68f1436d3f33f2dd2af5415e3feaeb1156e1a62c"}, + {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c37c5cce780349d4d51739ae682dec63573847a2a8dcb44381b174c3d9c8d403"}, + {file = "aiohttp-3.8.3-cp39-cp39-win32.whl", hash = "sha256:f178d2aadf0166be4df834c4953da2d7eef24719e8aec9a65289483eeea9d618"}, + {file = "aiohttp-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7"}, + {file = "aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"}, +] +aiosignal = [ + {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, + {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, +] +alabaster = [ + {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, + {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, +] +albumentations = [ + {file = "albumentations-1.3.0-py3-none-any.whl", hash = "sha256:294165d87d03bc8323e484927f0a5c1a3c64b0e7b9c32a979582a6c93c363bdf"}, + {file = "albumentations-1.3.0.tar.gz", hash = "sha256:be1af36832c8893314f2a5550e8ac19801e04770734c1b70fa3c996b41f37bed"}, +] +anyio = [ + {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, + {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, +] +apex = [] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +applicationinsights = [ + {file = "applicationinsights-0.11.10-py2.py3-none-any.whl", hash = "sha256:e89a890db1c6906b6a7d0bcfd617dac83974773c64573147c8d6654f9cf2a6ea"}, + {file = "applicationinsights-0.11.10.tar.gz", hash = "sha256:0b761f3ef0680acf4731906dfc1807faa6f2a57168ae74592db0084a6099f7b3"}, +] +appnope = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] +argcomplete = [ + {file = "argcomplete-1.12.3-py2.py3-none-any.whl", hash = "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81"}, + {file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"}, +] +argon2-cffi = [ + {file = "argon2-cffi-21.3.0.tar.gz", hash = "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b"}, + {file = "argon2_cffi-21.3.0-py3-none-any.whl", hash = "sha256:8c976986f2c5c0e5000919e6de187906cfd81fb1c72bf9d88c01177e77da7f80"}, +] +argon2-cffi-bindings = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] +astroid = [ + {file = "astroid-2.12.12-py3-none-any.whl", hash = "sha256:72702205200b2a638358369d90c222d74ebc376787af8fb2f7f2a86f7b5cc85f"}, + {file = "astroid-2.12.12.tar.gz", hash = "sha256:1c00a14f5a3ed0339d38d2e2e5b74ea2591df5861c0936bb292b84ccf3a78d83"}, +] +asttokens = [ + {file = "asttokens-2.0.8-py2.py3-none-any.whl", hash = "sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86"}, + {file = "asttokens-2.0.8.tar.gz", hash = "sha256:c61e16246ecfb2cde2958406b4c8ebc043c9e6d73aaa83c941673b35e5d3a76b"}, +] +async-timeout = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, +] +attrs = [ + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, +] +av = [ + {file = "av-9.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29373aa86a055a07eebb14d253cb202033f63ba98c5a4b0233d6d4c07fc7a292"}, + {file = "av-9.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:343b11d9b03e71da29f3ce56bc0a6c2d40aba448225dcf8296ab53c10527fff0"}, + {file = "av-9.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ea180bfd89bc0a9e392c32de204cf4e51648aefe2f375d430ce39c04e3ed625"}, + {file = "av-9.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b07b91f534ee7a096068149404c67c3c0e5b4c373580b016151de0fcb440cd3f"}, + {file = "av-9.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9983bc45dab65d2416d2f8a63785caa076a751590823fc8c199617d0dbad390"}, + {file = "av-9.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:0340cc68f3d222bc9438b4fde12e3d68f949eeb5de9e090db182f2cb06e23d53"}, + {file = "av-9.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e3e4a28fa0eabd3ab5b0915e9c005e9155039f9e1a4466212434c40eb69a33fb"}, + {file = "av-9.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a3c9126d658029b151484b48c656b73af1b145b143c50de5b8b983ac60e095"}, + {file = "av-9.2.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3facfe8dc5ba7f9ec7fd7e4c0466e577b84d5f2a1671428f7e28ebcd2cb0ccd3"}, + {file = "av-9.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af951271d998f736a20e54fbc0d944f263db7b17592f11cd489947957bf46aa8"}, + {file = "av-9.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:109526152e658921731018c50a05db802e7c9f3eb04a7a5fcbd8321fb3b73134"}, + {file = "av-9.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:587dd492a2ef3eb20324a0a8d67e6a2e686845d8c1dfdcad058377ac84268d67"}, + {file = "av-9.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28d85b8476f7d8fb18e3af9bd6d22bb292f1d810a20f8910fe481f648372e798"}, + {file = "av-9.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6a35e6028dec677caed97d19bfab3b66182690d43b0ec3c355778d740ce0509"}, + {file = "av-9.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a616a6eb46b62f41ff69569cafe12b0005a6dd14389f597dee115340336a910f"}, + {file = "av-9.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d730f3ed30eda46d06849bd71ad87d480cf0cad9fd064f33a0386dee95461e31"}, + {file = "av-9.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:6b01fbe8047da81892f8bd2aee5690f00465bf5215e3f6b6372863ac9408d75f"}, + {file = "av-9.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba3d9e3fe23fd8a14e810f291386225acbdef1c7e5376cc10c8e85c2d4280771"}, + {file = "av-9.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6be9388618af978304b56d1cf6b74c811db4f220dd320da5bd79640aa443358"}, + {file = "av-9.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e59e4ab0e8832bf87707e5024283b3a24cc01784604f0b0e96fbfbadbd8d9fc0"}, + {file = "av-9.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b0f124e335561cf4de6b7cdc461283c5eba5f05cccb1a5e1b8ceb1cd15393d8"}, + {file = "av-9.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49481c2d5bc296f451ccd3f93b1cb692d7f58a804b794b99c8b7743e058cae71"}, + {file = "av-9.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:1cbf031f650f89943023eef80e8b2c99588bf9ba26ffef8b3b54bef7102ea3dc"}, + {file = "av-9.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:48819e401cea5be57bd03299d8e5f700082c411746d1ac23eb5e5a931d3d3ced"}, + {file = "av-9.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d9cad890e6eccf2697b1c932761bee6f5e1e7faf9b8c03cf10f18f697d29ba3"}, + {file = "av-9.2.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080f34ddfde551de3a5f2d0d06d7518718e3115af81e56182e158cc03111662"}, + {file = "av-9.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b46b54ddf64409d4455f408b5970f8494c27c0273181b81c2f7d5072c9afb55"}, + {file = "av-9.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bf941896b4c800ee707211c802f94c6e0b4642d3000e25d1974d0b6032af4f66"}, + {file = "av-9.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d380925732e7497c1c11545107eabe1f498cab214f49f32d1b5d6abe01a2b36b"}, + {file = "av-9.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1c2c1dcc1947473ea1e2cbbf50549e2655e49e08bdd2a6427a97276d7a92c8"}, + {file = "av-9.2.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e2a50a146b3f33a24ea059af913ad368dbb61ed494234debe140a09f1076950"}, + {file = "av-9.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45816a39255b39e514a72125e0b6e29eb24fe0994bef3f4f87f3b9d9960b3fa8"}, + {file = "av-9.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ab90aa3ac2cbdf1f22087fc0fa439f643e96979f169ecfa1d496e114c3c3a8b3"}, + {file = "av-9.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24dac414eafcc20423f2ec7e873706489433648f0e9af08a537996880aa55979"}, + {file = "av-9.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17a7b6617d4201214f3dd5f628041b4fe56f4244dcd48399ed8d0cf324ca24d1"}, + {file = "av-9.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8671fa01648ce7aac76e71816c2421ddb1939bf706e2e14684608ab1ce9dbbbb"}, + {file = "av-9.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a5dc26b9df656bed5e1bdeaf8bcc4ff4a2e009ee90b3b3024a86cf8476b2cbf"}, + {file = "av-9.2.0.tar.gz", hash = "sha256:f2a7c226724d7f7745b376b459c500d9d17bd8d0473b7ea6bf8ddb4f7957c69d"}, +] +azure-cli-core = [ + {file = "azure-cli-core-2.41.0.tar.gz", hash = "sha256:f76fa9a44fd1e858397ba2951d260309e70710f367dd609eea03d6c0d8b05d3e"}, + {file = "azure_cli_core-2.41.0-py3-none-any.whl", hash = "sha256:b4cdf765106ff481361d6d84ae0403c46ea6c414ea511b38a316241c03f69252"}, +] +azure-cli-telemetry = [ + {file = "azure-cli-telemetry-1.0.8.tar.gz", hash = "sha256:ca996d162ab689c865f6b60be23b9757c26c3d97928e3319858eea83462df08d"}, + {file = "azure_cli_telemetry-1.0.8-py3-none-any.whl", hash = "sha256:502cbd90723a16603822909befd096ca0b1707de1e70cf730e7b4700ddd7a456"}, +] +azure-common = [ + {file = "azure-common-1.1.28.zip", hash = "sha256:4ac0cd3214e36b6a1b6a442686722a5d8cc449603aa833f3f0f40bda836704a3"}, + {file = "azure_common-1.1.28-py2.py3-none-any.whl", hash = "sha256:5c12d3dcf4ec20599ca6b0d3e09e86e146353d443e7fcc050c9a19c1f9df20ad"}, +] +azure-core = [ + {file = "azure-core-1.26.0.zip", hash = "sha256:b0036a0d256329e08d1278dff7df36be30031d2ec9b16c691bc61e4732f71fe0"}, + {file = "azure_core-1.26.0-py3-none-any.whl", hash = "sha256:578ea3ae56bca48880c96797871b6c954b5ae78d10d54360182c7604dc837f25"}, +] +azure-mgmt-core = [ + {file = "azure-mgmt-core-1.3.2.zip", hash = "sha256:07f4afe823a55d704b048d61edfdc1318c051ed59f244032126350be95e9d501"}, + {file = "azure_mgmt_core-1.3.2-py3-none-any.whl", hash = "sha256:fd829f67086e5cf6f7eb016c9e80bb0fb293cbbbd4d8738dc90af9aa1055fb7b"}, +] +azure-nspkg = [ + {file = "azure-nspkg-3.0.2.zip", hash = "sha256:e7d3cea6af63e667d87ba1ca4f8cd7cb4dfca678e4c55fc1cedb320760e39dd0"}, + {file = "azure_nspkg-3.0.2-py2-none-any.whl", hash = "sha256:1d0bbb2157cf57b1bef6c8c8e5b41133957364456c43b0a43599890023cca0a8"}, + {file = "azure_nspkg-3.0.2-py3-none-any.whl", hash = "sha256:31a060caca00ed1ebd369fc7fe01a56768c927e404ebc92268f4d9d636435e28"}, +] +azure-storage-blob = [ + {file = "azure-storage-blob-2.1.0.tar.gz", hash = "sha256:b90323aad60f207f9f90a0c4cf94c10acc313c20b39403398dfba51f25f7b454"}, + {file = "azure_storage_blob-2.1.0-py2.py3-none-any.whl", hash = "sha256:a8e91a51d4f62d11127c7fd8ba0077385c5b11022f0269f8a2a71b9fc36bef31"}, +] +azure-storage-common = [ + {file = "azure-storage-common-2.1.0.tar.gz", hash = "sha256:ccedef5c67227bc4d6670ffd37cec18fb529a1b7c3a5e53e4096eb0cf23dc73f"}, + {file = "azure_storage_common-2.1.0-py2.py3-none-any.whl", hash = "sha256:b01a491a18839b9d05a4fe3421458a0ddb5ab9443c14e487f40d16f9a1dc2fbe"}, +] +azure-storage-nspkg = [ + {file = "azure-storage-nspkg-3.1.0.tar.gz", hash = "sha256:6f3bbe8652d5f542767d8433e7f96b8df7f518774055ac7c92ed7ca85f653811"}, + {file = "azure_storage_nspkg-3.1.0-py2.py3-none-any.whl", hash = "sha256:7da3bd6c73b8c464a57f53ae9af8328490d2267c66430d8a7621997e52a9703e"}, +] +babel = [ + {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, + {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, +] +backcall = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] +bcrypt = [ + {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"}, + {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"}, + {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"}, + {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"}, + {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"}, + {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"}, + {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"}, + {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"}, + {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"}, +] +beautifulsoup4 = [ + {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, + {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, +] +bidict = [ + {file = "bidict-0.22.0-py3-none-any.whl", hash = "sha256:415126d23a0c81e1a8c584a8fb1f6905ea090c772571803aeee0a2242e8e7ba0"}, + {file = "bidict-0.22.0.tar.gz", hash = "sha256:5c826b3e15e97cc6e615de295756847c282a79b79c5430d3bfc909b1ac9f5bd8"}, +] +bleach = [ + {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, + {file = "bleach-5.0.1.tar.gz", hash = "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"}, +] +blosc = [ + {file = "blosc-1.9.2.tar.gz", hash = "sha256:89196a2112035836f027a29835ee247b0c7a45cece4cd9e4b740a1428aa174bf"}, +] +breathe = [ + {file = "breathe-4.34.0-py3-none-any.whl", hash = "sha256:48804dcf0e607a89fb6ad88c729ef12743a42db03ae9489be4ef8f7c4011774a"}, + {file = "breathe-4.34.0.tar.gz", hash = "sha256:ac0768a5e84addad3e632028fe67749c567aba2b29088493b64c2c1634bcdba1"}, +] +cachecontrol = [ + {file = "CacheControl-0.12.11-py2.py3-none-any.whl", hash = "sha256:2c75d6a8938cb1933c75c50184549ad42728a27e9f6b92fd677c3151aa72555b"}, + {file = "CacheControl-0.12.11.tar.gz", hash = "sha256:a5b9fcc986b184db101aa280b42ecdcdfc524892596f606858e0b7a8b4d9e144"}, +] +cachy = [ + {file = "cachy-0.3.0-py2.py3-none-any.whl", hash = "sha256:338ca09c8860e76b275aff52374330efedc4d5a5e45dc1c5b539c1ead0786fe7"}, + {file = "cachy-0.3.0.tar.gz", hash = "sha256:186581f4ceb42a0bbe040c407da73c14092379b1e4c0e327fdb72ae4a9b269b1"}, +] +carla = [ + {file = "carla-0.9.13-cp27-cp27mu-manylinux_2_27_x86_64.whl", hash = "sha256:339fcb1e392f3ade1be82b7258de19c533e2efae111e954a6eb174efb296903d"}, + {file = "carla-0.9.13-cp36-cp36m-manylinux_2_27_x86_64.whl", hash = "sha256:5f065825ce812343bf27a80a19d647b3200b31b44a9e80cea0340e3bd20cdf81"}, + {file = "carla-0.9.13-cp36-cp36m-win_amd64.whl", hash = "sha256:1210cce213e968a644effd4e2e48458a072481459d073424b05725056ba3d77d"}, + {file = "carla-0.9.13-cp37-cp37m-manylinux_2_27_x86_64.whl", hash = "sha256:a95d2d4218ea388c863c66b7c2ab3fe49ffefe53999305cfcb6a8107042f79af"}, + {file = "carla-0.9.13-cp37-cp37m-win_amd64.whl", hash = "sha256:954ca34d5bdd4516ceca353db907fee8cec6630d6b31a732b17dd1554e0f0f94"}, + {file = "carla-0.9.13-cp38-cp38-manylinux_2_27_x86_64.whl", hash = "sha256:d2bfaea2d6824a2d758cbe813856c69420494f5c97d2a2dfb45653ccf976f1ce"}, + {file = "carla-0.9.13-cp38-cp38-win_amd64.whl", hash = "sha256:a64ee78fe91137fa7d4828c7fc06d5824bd7312e29e4ea4f31a5d74dd28bff40"}, +] +casadi = [ + {file = "casadi-3.5.5-cp27-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:d4e49cb46404cef61f83b30bb20ec9597c50ae7f55cfd6b89c17facc74675437"}, + {file = "casadi-3.5.5-cp27-none-manylinux1_i686.whl", hash = "sha256:f08a99e98b0a15083f06b1e221f064a29b3ed9e20617dc55aa8e823f2f732ace"}, + {file = "casadi-3.5.5-cp27-none-manylinux1_x86_64.whl", hash = "sha256:09e103bb597d46aa338fc57bc49270068a1f07be35f9494c9f796dea4b801aeb"}, + {file = "casadi-3.5.5-cp27-none-win32.whl", hash = "sha256:a4ce51e988570160af9ccfbbb1b9679546cbb1865d3a74ef0276f37fd94d91d9"}, + {file = "casadi-3.5.5-cp27-none-win_amd64.whl", hash = "sha256:54d89442058271007ae8573dfa33360bea10e26603545481090b45e8b90c9d10"}, + {file = "casadi-3.5.5-cp34-none-manylinux1_x86_64.whl", hash = "sha256:4143803af909f284400c02f59de4d97e5ba9319de28366215ef55ef261914f9a"}, + {file = "casadi-3.5.5-cp34-none-win32.whl", hash = "sha256:7a624d40c7b5ded7916f6cc65998af4585b4557c9ea65dc1e3a6273ebb2313ec"}, + {file = "casadi-3.5.5-cp34-none-win_amd64.whl", hash = "sha256:3aec6737c282e7fb5be41f6c7d0649e52ce49efb3508f30bada707e809bbbb5f"}, + {file = "casadi-3.5.5-cp35-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:6192e2ed81c15a7dab2554f5f69b134df8d1a982f8d9f13e57bdef93364d2120"}, + {file = "casadi-3.5.5-cp35-none-manylinux1_i686.whl", hash = "sha256:49a8b713f0ff0bbc2f2af2e71c515cdced238786e25ef504f5982618c84c67a7"}, + {file = "casadi-3.5.5-cp35-none-manylinux1_x86_64.whl", hash = "sha256:13277151efc76b221de8ca6b5ab7b8bbdd2b0e139f282866840adf88dfe53bc9"}, + {file = "casadi-3.5.5-cp35-none-manylinux2014_aarch64.whl", hash = "sha256:253569c85f881a6a8fe5e1c0758858edb1ecb4c3d8bce4aee4b52e5dc59fc091"}, + {file = "casadi-3.5.5-cp35-none-win32.whl", hash = "sha256:5de5c3c1381ac303e71fdef75dace34af6e1d50b46ac081051cd209b8b933837"}, + {file = "casadi-3.5.5-cp35-none-win_amd64.whl", hash = "sha256:4932b2b5361013420189dbc8d30e970672d036b37cb382f1c09c3b6cfe651a37"}, + {file = "casadi-3.5.5-cp36-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:2322748a8d5e88750fd2fc0abcdc56cfbad1a8cd538fe0e7d7b6d8ce0cb3fa62"}, + {file = "casadi-3.5.5-cp36-none-manylinux1_i686.whl", hash = "sha256:ab6a600a9b2ea27453d56fd4464ad0db0ae69f5cea42595fcbdaabcd40396440"}, + {file = "casadi-3.5.5-cp36-none-manylinux1_x86_64.whl", hash = "sha256:5f6eb8de31735c14ecc777e3ad77b57767b5f2dbea29265909ef696f51e8be92"}, + {file = "casadi-3.5.5-cp36-none-manylinux2014_aarch64.whl", hash = "sha256:adf20c34ba2cec1840a026023d93cc6d9b3581dfda6a044f434fc75b50c9a2ce"}, + {file = "casadi-3.5.5-cp36-none-win32.whl", hash = "sha256:7309a75b27c57f09b00a61815fb38c40da8e62e3004598e55ea1b8f713d96221"}, + {file = "casadi-3.5.5-cp36-none-win_amd64.whl", hash = "sha256:ab85c7cf772ba54f2718ebe366b836fffff868443f7c0c02389ed0a288cbde1f"}, + {file = "casadi-3.5.5-cp37-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:ec26244f9d9047f1bb401f1b86ff4775e1ddf638f4b4992bbc362a27a6f56673"}, + {file = "casadi-3.5.5-cp37-none-manylinux1_i686.whl", hash = "sha256:1c451a07b2440c00d552e040b6285b6e79b677d2978212368b28b86f5d267669"}, + {file = "casadi-3.5.5-cp37-none-manylinux1_x86_64.whl", hash = "sha256:24fbac649ee26572884029dcd0e108b4a2412cad003a84ed915c4e44a94ecae7"}, + {file = "casadi-3.5.5-cp37-none-manylinux2014_aarch64.whl", hash = "sha256:a06c0b96eb9d3bc88c627eec6e465726934ca0394347dc33efc742b8c91db83d"}, + {file = "casadi-3.5.5-cp37-none-win32.whl", hash = "sha256:36db4c84d8f3aad328faaeaeaa454a633c95a854d78ea188791b147888379342"}, + {file = "casadi-3.5.5-cp37-none-win_amd64.whl", hash = "sha256:643e48f92eaf65eb82964816bb7e7064ddb8239959210fa6168e8bce6fe6ef94"}, + {file = "casadi-3.5.5-cp38-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:6ce7ac8a301a145f98d46db0bfd13bc8b3831a5bb92e8054d531a1f233bb4b93"}, + {file = "casadi-3.5.5-cp38-none-manylinux1_i686.whl", hash = "sha256:473bb86fa64ac9703d74a474514703b4665fa9a384221ced620b5025e64532a7"}, + {file = "casadi-3.5.5-cp38-none-manylinux1_x86_64.whl", hash = "sha256:292e2768280393bad406256e0ef9c30ddcd4867dbd42148b36f9d92a32d9e199"}, + {file = "casadi-3.5.5-cp38-none-manylinux2014_aarch64.whl", hash = "sha256:353a79e50aa84ac5e0d9f04bc3b2d78a2cc8edae3b842d757756449682778944"}, + {file = "casadi-3.5.5-cp38-none-win32.whl", hash = "sha256:77f33cb95be6a49b93d8d6b81f05193676ae09857699cedf8f1a14a4285d077e"}, + {file = "casadi-3.5.5-cp38-none-win_amd64.whl", hash = "sha256:fbf39dcd63f1d3b63c300fce59b7ea678bd5ea1d014e1e090a5226600a4132cb"}, + {file = "casadi-3.5.5-cp39-none-macosx_10_13_x86_64.macosx_10_13_intel.whl", hash = "sha256:4086669280b2335d235c664373db46dcd7f6485dba4663ce1944ea01753c5e8b"}, + {file = "casadi-3.5.5-cp39-none-manylinux1_i686.whl", hash = "sha256:c3440c90c31b61ae1df82f6c784643393f723354dc08013f9d5cedf25507c67c"}, + {file = "casadi-3.5.5-cp39-none-manylinux1_x86_64.whl", hash = "sha256:bd94048388b602fc30fdac2fecb986c034110ed8d2d17af7fd13b0de45c58bd7"}, + {file = "casadi-3.5.5-cp39-none-manylinux2014_aarch64.whl", hash = "sha256:cd630a2e6ec6df6a4977af63080fa8d63a0053ff8c06ea0200959b47ae75201c"}, + {file = "casadi-3.5.5-cp39-none-win32.whl", hash = "sha256:ac45b91616e9b8afbe266ca08e80770b28e9e6d7a5852e3677fb37e42bde2047"}, + {file = "casadi-3.5.5-cp39-none-win_amd64.whl", hash = "sha256:55df534d003efdd120c4ebfeb6b252c443d273cdc4b97a394eb0268367477795"}, +] +certifi = [ + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, +] +cffi = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] +cfgv = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] +cleo = [ + {file = "cleo-1.0.0a5-py3-none-any.whl", hash = "sha256:ff53056589300976e960f75afb792dfbfc9c78dcbb5a448e207a17b643826360"}, + {file = "cleo-1.0.0a5.tar.gz", hash = "sha256:097c9d0e0332fd53cc89fc11eb0a6ba0309e6a3933c08f7b38558555486925d3"}, +] +click = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] +cloudpickle = [ + {file = "cloudpickle-2.2.0-py3-none-any.whl", hash = "sha256:7428798d5926d8fcbfd092d18d01a2a03daf8237d8fcdc8095d256b8490796f0"}, + {file = "cloudpickle-2.2.0.tar.gz", hash = "sha256:3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f"}, +] +colorama = [ + {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, + {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, +] +coloredlogs = [ + {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"}, + {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"}, +] +configargparse = [ + {file = "ConfigArgParse-1.5.3-py3-none-any.whl", hash = "sha256:18f6535a2db9f6e02bd5626cc7455eac3e96b9ab3d969d366f9aafd5c5c00fe7"}, + {file = "ConfigArgParse-1.5.3.tar.gz", hash = "sha256:1b0b3cbf664ab59dada57123c81eff3d9737e0d11d8cf79e3d6eb10823f1739f"}, +] +contourpy = [ + {file = "contourpy-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:87121b9428ac568fb84fae4af5e7852fc34f02eadc4e3e91f6c8989327692186"}, + {file = "contourpy-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1fb782982c42cee667b892a0b0c52a9f6c7ecf1da5c5f4345845f04eaa862f93"}, + {file = "contourpy-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:689d7d2a840619915d0abd1ecc6e399fee202f8ad315acda2807f4ca420d0802"}, + {file = "contourpy-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d88814befbd1433152c5f6dd536905149ba028d795a22555b149ae0a36024d9e"}, + {file = "contourpy-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df65f4b2b4e74977f0336bef12a88051ab24e6a16873cd9249f34d67cb3e345d"}, + {file = "contourpy-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6b4c0c723664f65c2a47c8cb6ebbf660b0b2e2d936adf2e8503d4e93359465"}, + {file = "contourpy-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bcc98d397c3dea45d5b262029564b29cb8e945f2607a38bee6163694c0a8b4ef"}, + {file = "contourpy-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2bf5c846c257578b03d498b20f54f53551616a507d8e5463511c58bb58e9a9cf"}, + {file = "contourpy-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdacddb18d55ffec42d1907079cdc04ec4fa8a990cdf5b9d9fe67d281fc0d12e"}, + {file = "contourpy-1.0.5-cp310-cp310-win32.whl", hash = "sha256:434942fa2f9019b9ae525fb752dc523800c49a1a28fbd6d9240b0fa959573dcc"}, + {file = "contourpy-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:3b3082ade8849130203d461b98c2a061b382c46074b43b4edd5cefd81af92b8a"}, + {file = "contourpy-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:057114f698ffb9e54657e8fda6802e2f5c8fad609845cf6afaf31590ef6a33c0"}, + {file = "contourpy-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:218722a29c5c26677d37c44f5f8a372daf6f07870aad793a97d47eb6ad6b3290"}, + {file = "contourpy-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c02e22cf09996194bcb3a4784099975cf527d5c29caf759abadf29ebdb2fe27"}, + {file = "contourpy-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0d5ee865b5fd16bf62d72122aadcc90aab296c30c1adb0a32b4b66bd843163e"}, + {file = "contourpy-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45822b0a2a452327ab4f95efe368d234d5294bbf89a99968be27c7938a21108"}, + {file = "contourpy-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dca5be83a6dfaf933a46e3bc2b9f2685e5ec61b22f6a38ad740aac9c16e9a0ff"}, + {file = "contourpy-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c3f2f6b898a40207843ae01970e57e33d22a26b22f23c6a5e07b4716751085f"}, + {file = "contourpy-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c2b4eab7c12f9cb460509bc34a3b086f9802f0dba27c89a63df4123819ad64af"}, + {file = "contourpy-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09ed9b63f4df8a7591b7a4a26c1ad066dcaafda1f846250fdcb534074a411692"}, + {file = "contourpy-1.0.5-cp311-cp311-win32.whl", hash = "sha256:f670686d99c867d0f24b28ce8c6f02429c6eef5e2674aab287850d0ee2d20437"}, + {file = "contourpy-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:c51568e94f7f232296de30002f2a50f77a7bd346673da3e4f2aaf9d2b833f2e5"}, + {file = "contourpy-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7c9e99aac7b430f6a9f15eebf058c742097cea3369f23a2bfc5e64d374b67e3a"}, + {file = "contourpy-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3210d93ad2af742b6a96cf39792f7181822edbb8fe11c3ef29d1583fe637a8d8"}, + {file = "contourpy-1.0.5-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128bd7acf569f8443ad5b2227f30ac909e4f5399ed221727eeacf0c6476187e6"}, + {file = "contourpy-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813c2944e940ef8dccea71305bacc942d4b193a021140874b3e58933ec44f5b6"}, + {file = "contourpy-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a74afd8d560eaafe0d9e3e1db8c06081282a05ca4de00ee416195085a79d7d3d"}, + {file = "contourpy-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d0ad9a85f208473b1f3613c45756c7aa6fcc288266a8c7b873f896aaf741b6b"}, + {file = "contourpy-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:60f37acd4e4227c5a29f737d9a85ca3145c529a8dd4bf70af7f0637c61b49222"}, + {file = "contourpy-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:b50e481a4317a8efcfffcfddcd4c9b36eacba440440e70cbe0256aeb6fd6abae"}, + {file = "contourpy-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:0395ae71164bfeb2dedd136e03c71a2718a5aa9873a46f518f4133be0d63e1d2"}, + {file = "contourpy-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3ca40d7844b391d90b864c6a6d1bb6b88b09035fb4d866d64d43c4d26fb0ab64"}, + {file = "contourpy-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3109fa601d2a448cec4643abd3a31f972bf05b7c2f2e83df9d3429878f8c10ae"}, + {file = "contourpy-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:06c4d1dde5ee4f909a8a95ba1eb04040c6c26946b4f3b5beaf10d45f14e940ee"}, + {file = "contourpy-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f54dcc9bb9390fd0636301ead134d46d5229fe86da0db4d974c0fda349f560e"}, + {file = "contourpy-1.0.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46b8e24813e2fb5a3e598c1f8b9ae403e1438cb846a80cc2b33cddf19dddd7f2"}, + {file = "contourpy-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:061e1f066c419ffe25b615a1df031b4832ea1d7f2676937e69e8e00e24512005"}, + {file = "contourpy-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:19ea64fa0cf389d2ebc10974616acfa1fdecbd73d1fd9c72215b782f3c40f561"}, + {file = "contourpy-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfe924e5a63861c82332a12adeeab955dc8c8009ddbbd80cc2fcca049ff89a49"}, + {file = "contourpy-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bed3a2a823a041e8d249b1a7ec132933e1505299329b5cfe1b2b5ec689ec7675"}, + {file = "contourpy-1.0.5-cp38-cp38-win32.whl", hash = "sha256:0389349875424aa8c5e61f757e894687916bc4e9616cc6afcbd8051aa2428952"}, + {file = "contourpy-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:2b5e334330d82866923015b455260173cb3b9e3b4e297052d758abd262031289"}, + {file = "contourpy-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:def9a01b73c9e27d70ea03b381fb3e7aadfac1f398dbd63751313c3a46747ef5"}, + {file = "contourpy-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:59c827e536bb5e3ef58e06da0faba61fd89a14f30b68bcfeca41f43ca83a1942"}, + {file = "contourpy-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f05d311c937da03b0cd26ac3e14cb991f6ff8fc94f98b3df9713537817539795"}, + {file = "contourpy-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:970a4be7ec84ccda7c27cb4ae74930bbbd477bc8d849ed55ea798084dd5fca8c"}, + {file = "contourpy-1.0.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f7672148f8fca48e4efc16aba24a7455b40c22d4f8abe42475dec6a12b0bb9a"}, + {file = "contourpy-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eba62b7c21a33e72dd8adab2b92dd5610d8527f0b2ac28a8e0770e71b21a13f9"}, + {file = "contourpy-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:dd084459ecdb224e617e4ab3f1d5ebe4d1c48facb41f24952b76aa6ba9712bb0"}, + {file = "contourpy-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c5158616ab39d34b76c50f40c81552ee180598f7825dc7a66fd187d29958820f"}, + {file = "contourpy-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f856652f9b533c6cd2b9ad6836a7fc0e43917d7ff15be46c5baf1350f8cdc5d9"}, + {file = "contourpy-1.0.5-cp39-cp39-win32.whl", hash = "sha256:f1cc623fd6855b25da52b3275e0c9e51711b86a9dccc75f8c9ab4432fd8e42c7"}, + {file = "contourpy-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:e67dcaa34dcd908fcccbf49194211d847c731b6ebaac661c1c889f1bf6af1e44"}, + {file = "contourpy-1.0.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfd634cb9685161b2a51f73a7fc4736fd0d67a56632d52319317afaa27f08243"}, + {file = "contourpy-1.0.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79908b9d02b1d6c1c71ff3b7ad127f3f82e14a8e091ab44b3c7e34b649fea733"}, + {file = "contourpy-1.0.5-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4963cf08f4320d98ae72ec7694291b8ab85cb7da3b0cd824bc32701bc992edf"}, + {file = "contourpy-1.0.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cfc067ddde78b76dcbc9684d82688b7d3c5158fa2254a085f9bcb9586c1e2d8"}, + {file = "contourpy-1.0.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9939796abcadb2810a63dfb26ff8ca4595fe7dd70a3ceae7f607a2639b714307"}, + {file = "contourpy-1.0.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d8150579bf30cdf896906baf256aa200cd50dbe6e565c17d6fd3d678e21ff5de"}, + {file = "contourpy-1.0.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed9c91bf4ce614efed5388c3f989a7cfe08728ab871d995a486ea74ff88993db"}, + {file = "contourpy-1.0.5-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b46a04588ceb7cf132568e0e564a854627ef87a1ed3bf536234540a79ced44b0"}, + {file = "contourpy-1.0.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b85553699862c09937a7a5ea14ee6229087971a7d51ae97d5f4b407f571a2c17"}, + {file = "contourpy-1.0.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:99a8071e351b50827ad976b92ed91845fb614ac67a3c41109b24f3d8bd3afada"}, + {file = "contourpy-1.0.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fb0458d74726937ead9e2effc91144aea5a58ecee9754242f8539a782bed685a"}, + {file = "contourpy-1.0.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f89f0608a5aa8142ed0e53957916623791a88c7f5e5f07ae530c328beeb888f"}, + {file = "contourpy-1.0.5-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce763369e646e59e4ca2c09735cd1bdd3048d909ad5f2bc116e83166a9352f3c"}, + {file = "contourpy-1.0.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c16fa267740d67883899e054cccb4279e002f3f4872873b752c1ba15045ff49"}, + {file = "contourpy-1.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a30e95274f5c0e007ccc759ec258aa5708c534ec058f153ee25ac700a2f1438b"}, + {file = "contourpy-1.0.5.tar.gz", hash = "sha256:896631cd40222aef3697e4e51177d14c3709fda49d30983269d584f034acc8a4"}, +] +control = [ + {file = "control-0.9.2.tar.gz", hash = "sha256:0891d2d32d6006ac1faa4e238ed8223ca342a4721d202dfeccae24fb02563183"}, +] +coverage = [ + {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, + {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, + {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, + {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, + {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, + {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, + {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, + {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, + {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, + {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, + {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, + {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, + {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, + {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, + {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, +] +crashtest = [ + {file = "crashtest-0.3.1-py3-none-any.whl", hash = "sha256:300f4b0825f57688b47b6d70c6a31de33512eb2fa1ac614f780939aa0cf91680"}, + {file = "crashtest-0.3.1.tar.gz", hash = "sha256:42ca7b6ce88b6c7433e2ce47ea884e91ec93104a4b754998be498a8e6c3d37dd"}, +] +crcmod = [ + {file = "crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e"}, +] +cryptography = [ + {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:549153378611c0cca1042f20fd9c5030d37a72f634c9326e225c9f666d472884"}, + {file = "cryptography-37.0.4-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a958c52505c8adf0d3822703078580d2c0456dd1d27fabfb6f76fe63d2971cd6"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f721d1885ecae9078c3f6bbe8a88bc0786b6e749bf32ccec1ef2b18929a05046"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3d41b965b3380f10e4611dbae366f6dc3cefc7c9ac4e8842a806b9672ae9add5"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80f49023dd13ba35f7c34072fa17f604d2f19bf0989f292cedf7ab5770b87a0b"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2dcb0b3b63afb6df7fd94ec6fbddac81b5492513f7b0436210d390c14d46ee8"}, + {file = "cryptography-37.0.4-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:b7f8dd0d4c1f21759695c05a5ec8536c12f31611541f8904083f3dc582604280"}, + {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:30788e070800fec9bbcf9faa71ea6d8068f5136f60029759fd8c3efec3c9dcb3"}, + {file = "cryptography-37.0.4-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:190f82f3e87033821828f60787cfa42bff98404483577b591429ed99bed39d59"}, + {file = "cryptography-37.0.4-cp36-abi3-win32.whl", hash = "sha256:b62439d7cd1222f3da897e9a9fe53bbf5c104fff4d60893ad1355d4c14a24157"}, + {file = "cryptography-37.0.4-cp36-abi3-win_amd64.whl", hash = "sha256:f7a6de3e98771e183645181b3627e2563dcde3ce94a9e42a3f427d2255190327"}, + {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc95ed67b6741b2607298f9ea4932ff157e570ef456ef7ff0ef4884a134cc4b"}, + {file = "cryptography-37.0.4-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f8c0a6e9e1dd3eb0414ba320f85da6b0dcbd543126e30fcc546e7372a7fbf3b9"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:e007f052ed10cc316df59bc90fbb7ff7950d7e2919c9757fd42a2b8ecf8a5f67"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bc997818309f56c0038a33b8da5c0bfbb3f1f067f315f9abd6fc07ad359398d"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d204833f3c8a33bbe11eda63a54b1aad7aa7456ed769a982f21ec599ba5fa282"}, + {file = "cryptography-37.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:75976c217f10d48a8b5a8de3d70c454c249e4b91851f6838a4e48b8f41eb71aa"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7099a8d55cd49b737ffc99c17de504f2257e3787e02abe6d1a6d136574873441"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2be53f9f5505673eeda5f2736bea736c40f051a739bfae2f92d18aed1eb54596"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:91ce48d35f4e3d3f1d83e29ef4a9267246e6a3be51864a5b7d2247d5086fa99a"}, + {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"}, + {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"}, +] +cupy-cuda113 = [ + {file = "cupy_cuda113-10.6.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:27e5efe2c3afa80ff48654cb27f9e0eddb36f8b26ef0d32d3ba0a233e1359b51"}, + {file = "cupy_cuda113-10.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8b96076d1ddd33fdb2c908ed0f8109caf69d37d36f839a8a8cdae1312508336f"}, + {file = "cupy_cuda113-10.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22363c2863727cae5154aa4bab9e8a648d7fe66c9e2195d81dd4e8693c2e61ce"}, + {file = "cupy_cuda113-10.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8cc69b9d5735372477a7af3822c8f8e996ffe6de05cfc917500af9dc0117ca3e"}, + {file = "cupy_cuda113-10.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:10dc6899577e445426d81f0960ba9059d9aaa750426997c61fad882d6345264c"}, + {file = "cupy_cuda113-10.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:c6893ac9040a11610e63973063dfd715dbda8bd07ef99951bab7a09c7f335e1e"}, + {file = "cupy_cuda113-10.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4bf4bc06d991c06b95f6fe558d117cafd93bd4eeaf80606f18dd31d20d2eff25"}, + {file = "cupy_cuda113-10.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:3745fc42dca86ba8a1109ddc7964aed8e1efc0ce8085cb2f140dcd6429f26354"}, +] +cycler = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] +cython = [ + {file = "Cython-0.29.32-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:39afb4679b8c6bf7ccb15b24025568f4f9b4d7f9bf3cbd981021f542acecd75b"}, + {file = "Cython-0.29.32-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbee03b8d42dca924e6aa057b836a064c769ddfd2a4c2919e65da2c8a362d528"}, + {file = "Cython-0.29.32-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ba622326f2862f9c1f99ca8d47ade49871241920a352c917e16861e25b0e5c3"}, + {file = "Cython-0.29.32-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e6ffa08aa1c111a1ebcbd1cf4afaaec120bc0bbdec3f2545f8bb7d3e8e77a1cd"}, + {file = "Cython-0.29.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:97335b2cd4acebf30d14e2855d882de83ad838491a09be2011745579ac975833"}, + {file = "Cython-0.29.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:06be83490c906b6429b4389e13487a26254ccaad2eef6f3d4ee21d8d3a4aaa2b"}, + {file = "Cython-0.29.32-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:eefd2b9a5f38ded8d859fe96cc28d7d06e098dc3f677e7adbafda4dcdd4a461c"}, + {file = "Cython-0.29.32-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5514f3b4122cb22317122a48e175a7194e18e1803ca555c4c959d7dfe68eaf98"}, + {file = "Cython-0.29.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:656dc5ff1d269de4d11ee8542f2ffd15ab466c447c1f10e5b8aba6f561967276"}, + {file = "Cython-0.29.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:cdf10af3e2e3279dc09fdc5f95deaa624850a53913f30350ceee824dc14fc1a6"}, + {file = "Cython-0.29.32-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:3875c2b2ea752816a4d7ae59d45bb546e7c4c79093c83e3ba7f4d9051dd02928"}, + {file = "Cython-0.29.32-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:79e3bab19cf1b021b613567c22eb18b76c0c547b9bc3903881a07bfd9e7e64cf"}, + {file = "Cython-0.29.32-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0595aee62809ba353cebc5c7978e0e443760c3e882e2c7672c73ffe46383673"}, + {file = "Cython-0.29.32-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0ea8267fc373a2c5064ad77d8ff7bf0ea8b88f7407098ff51829381f8ec1d5d9"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:c8e8025f496b5acb6ba95da2fb3e9dacffc97d9a92711aacfdd42f9c5927e094"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:afbce249133a830f121b917f8c9404a44f2950e0e4f5d1e68f043da4c2e9f457"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:513e9707407608ac0d306c8b09d55a28be23ea4152cbd356ceaec0f32ef08d65"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e83228e0994497900af954adcac27f64c9a57cd70a9ec768ab0cb2c01fd15cf1"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ea1dcc07bfb37367b639415333cfbfe4a93c3be340edf1db10964bc27d42ed64"}, + {file = "Cython-0.29.32-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8669cadeb26d9a58a5e6b8ce34d2c8986cc3b5c0bfa77eda6ceb471596cb2ec3"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:ed087eeb88a8cf96c60fb76c5c3b5fb87188adee5e179f89ec9ad9a43c0c54b3"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3f85eb2343d20d91a4ea9cf14e5748092b376a64b7e07fc224e85b2753e9070b"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:63b79d9e1f7c4d1f498ab1322156a0d7dc1b6004bf981a8abda3f66800e140cd"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e1958e0227a4a6a2c06fd6e35b7469de50adf174102454db397cec6e1403cce3"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:856d2fec682b3f31583719cb6925c6cdbb9aa30f03122bcc45c65c8b6f515754"}, + {file = "Cython-0.29.32-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:479690d2892ca56d34812fe6ab8f58e4b2e0129140f3d94518f15993c40553da"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:67fdd2f652f8d4840042e2d2d91e15636ba2bcdcd92e7e5ffbc68e6ef633a754"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4a4b03ab483271f69221c3210f7cde0dcc456749ecf8243b95bc7a701e5677e0"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:40eff7aa26e91cf108fd740ffd4daf49f39b2fdffadabc7292b4b7dc5df879f0"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0bbc27abdf6aebfa1bce34cd92bd403070356f28b0ecb3198ff8a182791d58b9"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cddc47ec746a08603037731f5d10aebf770ced08666100bd2cdcaf06a85d4d1b"}, + {file = "Cython-0.29.32-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca3065a1279456e81c615211d025ea11bfe4e19f0c5650b859868ca04b3fcbd"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d968ffc403d92addf20b68924d95428d523436adfd25cf505d427ed7ba3bee8b"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f3fd44cc362eee8ae569025f070d56208908916794b6ab21e139cea56470a2b3"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:b6da3063c5c476f5311fd76854abae6c315f1513ef7d7904deed2e774623bbb9"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:061e25151c38f2361bc790d3bcf7f9d9828a0b6a4d5afa56fbed3bd33fb2373a"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f9944013588a3543fca795fffb0a070a31a243aa4f2d212f118aa95e69485831"}, + {file = "Cython-0.29.32-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:07d173d3289415bb496e72cb0ddd609961be08fe2968c39094d5712ffb78672b"}, + {file = "Cython-0.29.32-py2.py3-none-any.whl", hash = "sha256:eeb475eb6f0ccf6c039035eb4f0f928eb53ead88777e0a760eccb140ad90930b"}, + {file = "Cython-0.29.32.tar.gz", hash = "sha256:8733cf4758b79304f2a4e39ebfac5e92341bce47bcceb26c1254398b2f8c1af7"}, +] +datadog = [ + {file = "datadog-0.44.0-py2.py3-none-any.whl", hash = "sha256:57c4878d3a8351f652792cdba78050274789dcc44313adec096e87f9d3ca5992"}, + {file = "datadog-0.44.0.tar.gz", hash = "sha256:071170f0c7ef22511dbf7f9bd76c4be500ee2d3d52072900a5c87b5495d2c733"}, +] +debugpy = [ + {file = "debugpy-1.6.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:c4b2bd5c245eeb49824bf7e539f95fb17f9a756186e51c3e513e32999d8846f3"}, + {file = "debugpy-1.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b8deaeb779699350deeed835322730a3efec170b88927debc9ba07a1a38e2585"}, + {file = "debugpy-1.6.3-cp310-cp310-win32.whl", hash = "sha256:fc233a0160f3b117b20216f1169e7211b83235e3cd6749bcdd8dbb72177030c7"}, + {file = "debugpy-1.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:dda8652520eae3945833e061cbe2993ad94a0b545aebd62e4e6b80ee616c76b2"}, + {file = "debugpy-1.6.3-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5c814596a170a0a58fa6fad74947e30bfd7e192a5d2d7bd6a12156c2899e13a"}, + {file = "debugpy-1.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c4cd6f37e3c168080d61d698390dfe2cd9e74ebf80b448069822a15dadcda57d"}, + {file = "debugpy-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:3c9f985944a30cfc9ae4306ac6a27b9c31dba72ca943214dad4a0ab3840f6161"}, + {file = "debugpy-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5ad571a36cec137ae6ed951d0ff75b5e092e9af6683da084753231150cbc5b25"}, + {file = "debugpy-1.6.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:adcfea5ea06d55d505375995e150c06445e2b20cd12885bcae566148c076636b"}, + {file = "debugpy-1.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:daadab4403427abd090eccb38d8901afd8b393e01fd243048fab3f1d7132abb4"}, + {file = "debugpy-1.6.3-cp38-cp38-win32.whl", hash = "sha256:6efc30325b68e451118b795eff6fe8488253ca3958251d5158106d9c87581bc6"}, + {file = "debugpy-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:86d784b72c5411c833af1cd45b83d80c252b77c3bfdb43db17c441d772f4c734"}, + {file = "debugpy-1.6.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4e255982552b0edfe3a6264438dbd62d404baa6556a81a88f9420d3ed79b06ae"}, + {file = "debugpy-1.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cca23cb6161ac89698d629d892520327dd1be9321c0960e610bbcb807232b45d"}, + {file = "debugpy-1.6.3-cp39-cp39-win32.whl", hash = "sha256:7c302095a81be0d5c19f6529b600bac971440db3e226dce85347cc27e6a61908"}, + {file = "debugpy-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:34d2cdd3a7c87302ba5322b86e79c32c2115be396f3f09ca13306d8a04fe0f16"}, + {file = "debugpy-1.6.3-py2.py3-none-any.whl", hash = "sha256:84c39940a0cac410bf6aa4db00ba174f973eef521fbe9dd058e26bcabad89c4f"}, + {file = "debugpy-1.6.3.zip", hash = "sha256:e8922090514a890eec99cfb991bab872dd2e353ebb793164d5f01c362b9a40bf"}, +] +decorator = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] +defusedxml = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, +] +dictdiffer = [ + {file = "dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595"}, + {file = "dictdiffer-0.9.0.tar.gz", hash = "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578"}, +] +dill = [ + {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"}, + {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"}, +] +distlib = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] +docutils = [ + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, +] +dotmap = [ + {file = "dotmap-1.3.30-py3-none-any.whl", hash = "sha256:bd9fa15286ea2ad899a4d1dc2445ed85a1ae884a42effb87c89a6ecce71243c6"}, + {file = "dotmap-1.3.30.tar.gz", hash = "sha256:5821a7933f075fb47563417c0e92e0b7c031158b4c9a6a7e56163479b658b368"}, +] +dulwich = [ + {file = "dulwich-0.20.46-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:6676196e9cf377cde62aa2f5d741e93207437343e0c62368bd0d784c322a3c49"}, + {file = "dulwich-0.20.46-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a1ca555a3eafe7388d6cb81bb08f34608a1592500f0bd4c26734c91d208a546"}, + {file = "dulwich-0.20.46-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:769442c9657b10fc35ac625beeaf440540c9288c96fcfaba3e58adf745c5cafd"}, + {file = "dulwich-0.20.46-cp310-cp310-win32.whl", hash = "sha256:de22a54f68c6c4e97f9b924abd46da4618536d7934b9849066be9fc5cd31205d"}, + {file = "dulwich-0.20.46-cp310-cp310-win_amd64.whl", hash = "sha256:42fa5a68908556eb6c40f231a67caf6a4660588aad707a9d6b334fa1d8f04bf7"}, + {file = "dulwich-0.20.46-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:3e16376031466848e44aabf3489fafb054482143744b21167dbd168731041c74"}, + {file = "dulwich-0.20.46-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:153c7512587384a290c60fef330f1ab397a59559e19e8b02a0169ff21b4c69fb"}, + {file = "dulwich-0.20.46-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b68bd815cd2769c75e5a78708eb0440612df19b370a977aa9e01a056baa9ed"}, + {file = "dulwich-0.20.46-cp311-cp311-win32.whl", hash = "sha256:b1339bca70764eb8e780d80c72e7c1cb4651201dc9e43ec5d616bf51eb3bb3a6"}, + {file = "dulwich-0.20.46-cp311-cp311-win_amd64.whl", hash = "sha256:1162fdafb2abdfe66649617061f3853cb26384fade1f6884f6fe6e9c570a7552"}, + {file = "dulwich-0.20.46-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6826512f778eaa47e2e8c0a46cdc555958f9f5286771490b8642b4b508ea5d25"}, + {file = "dulwich-0.20.46-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:100d39bc18196a07c521fd5f60f78f397493303daa0b8690216864bbc621cd5d"}, + {file = "dulwich-0.20.46-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4cd2cd7baa81246bdc8c5272d4e9224e2255da7a0618a220aab5e07b9888e9b"}, + {file = "dulwich-0.20.46-cp36-cp36m-win32.whl", hash = "sha256:6eed5a3194d64112605fc0f638f4fa91771495e8674fa3e6d6b33bf150d297d5"}, + {file = "dulwich-0.20.46-cp36-cp36m-win_amd64.whl", hash = "sha256:9ca4d73987f5b0e2e843497876f9bb39a47384a2e50597a85542285f5c890293"}, + {file = "dulwich-0.20.46-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:b9f49de83911eed7adbe83136229837ef9d102e42dbe6aacb1a18be45c997ace"}, + {file = "dulwich-0.20.46-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38be7d3a78d608ecab3348f7920d6b9002e7972dd245206dc8075cfdb91621d"}, + {file = "dulwich-0.20.46-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b7a7feb966a4669c254b18385fe0b3c639f3b1f5ddef0d9e083364cc762847"}, + {file = "dulwich-0.20.46-cp37-cp37m-win32.whl", hash = "sha256:f9552ac246bceab1c5cdd1ec3cfe9446fe76b9853eaf59d3244df03eb27fd3fe"}, + {file = "dulwich-0.20.46-cp37-cp37m-win_amd64.whl", hash = "sha256:90a075aeb0fdbad7e18b9db3af161e3d635e2b7697b7a4b467e6844a13b0b210"}, + {file = "dulwich-0.20.46-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:8d6fee82cedb2362942d9ef94061901f7e07d7d8674e4c7b6fceeef7822ae275"}, + {file = "dulwich-0.20.46-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:669c6b3d82996518a7fec4604771bd285e23f0860f41f565fef5987265d431d9"}, + {file = "dulwich-0.20.46-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd3eac228117487a959ac8f49ea2787eac34acc69999fe7adae70b23e3c3571c"}, + {file = "dulwich-0.20.46-cp38-cp38-win32.whl", hash = "sha256:92024f572d32680e021219f77015c8b443c38022e502b7f51ad7cf51a6285a36"}, + {file = "dulwich-0.20.46-cp38-cp38-win_amd64.whl", hash = "sha256:d928de1eba0326a2a8a52ed94c9bf7c315ff4db606a1aa3ae688d39574f93267"}, + {file = "dulwich-0.20.46-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:a5d1b7a3a7d84a5dedbb90092e00097357106b9642ac08a96c2ae89ccd8afd9a"}, + {file = "dulwich-0.20.46-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b739d759c10e2af7c964dcc97fd4e5dc49e8567d080eed8906fc422c79b7fdcf"}, + {file = "dulwich-0.20.46-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fc7a4f633f5468453d5dd84a753cd99d4433f0397437229a0a8b10347935591"}, + {file = "dulwich-0.20.46-cp39-cp39-win32.whl", hash = "sha256:525115c4d1fbf60a5fe98f340b4ca597ba47b2c75d9c5ec750dd0e9115ef8ec6"}, + {file = "dulwich-0.20.46-cp39-cp39-win_amd64.whl", hash = "sha256:73e2585a9fcf1f8cdad8597a0c384c0b365b2e8346463130c96d9ea1478587ae"}, + {file = "dulwich-0.20.46.tar.gz", hash = "sha256:4f0e88ffff5db1523d93d92f1525fe5fa161318ffbaad502c1b9b3be7a067172"}, +] +efficientnet-pytorch = [ + {file = "efficientnet_pytorch-0.6.3.tar.gz", hash = "sha256:6667459336893e9bf6367de3788ba449fed97f65da3b6782bf2204b6273a319f"}, +] +elastic-transport = [ + {file = "elastic-transport-8.4.0.tar.gz", hash = "sha256:b9ad708ceb7fcdbc6b30a96f886609a109f042c0b9d9f2e44403b3133ba7ff10"}, + {file = "elastic_transport-8.4.0-py3-none-any.whl", hash = "sha256:19db271ab79c9f70f8c43f8f5b5111408781a6176b54ab2e54d713b6d9ceb815"}, +] +elasticsearch = [ + {file = "elasticsearch-8.4.3-py3-none-any.whl", hash = "sha256:14c68a96b7bbbf150dd9fca5ff65da9c50e791c0fdba474a328e43828fdd7f42"}, + {file = "elasticsearch-8.4.3.tar.gz", hash = "sha256:d34d43a6c349d15c9d91840f791eeba80fc50ee070caf6695130f56b7f41a02d"}, +] +entrypoints = [ + {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, + {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, +] +execnet = [ + {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, + {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, +] +executing = [ + {file = "executing-1.1.1-py2.py3-none-any.whl", hash = "sha256:236ea5f059a38781714a8bfba46a70fad3479c2f552abee3bbafadc57ed111b8"}, + {file = "executing-1.1.1.tar.gz", hash = "sha256:b0d7f8dcc2bac47ce6e39374397e7acecea6fdc380a6d5323e26185d70f38ea8"}, +] +fastcluster = [ + {file = "fastcluster-1.2.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d0e8faef0437a25fd083df70fb86cc65ce3c9c9780d4ae377cbe6521e7746ce0"}, + {file = "fastcluster-1.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8be01f97bc2bf11a9188537864f8e520e1103cdc6007aa2c5d7979b1363b121"}, + {file = "fastcluster-1.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:855ab2b7e6fa9b05f19c4f3023dedfb1a35a88d831933d65d0d9e10a070a9e85"}, + {file = "fastcluster-1.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72503e727887a61a15f9aaa13178798d3994dfec58aa7a943e42dcfda07c0149"}, + {file = "fastcluster-1.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fcb0973ca0e6978e3242046338c350cbed1493108929231fae9bd35ad05a6d6"}, + {file = "fastcluster-1.2.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9020899b67fe492d0ed87a3e993ec9962c5a0b51ea2df71d86b1766f065f1cef"}, + {file = "fastcluster-1.2.6-cp310-cp310-win32.whl", hash = "sha256:6cf156d4203708348522393c523c2e61c81f5a6a500e0411dcba2b064551ea2f"}, + {file = "fastcluster-1.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:1801c9daa9aa5bbbb0830efe8bd3034b4b7a417e4b8dd353683999be29797df2"}, + {file = "fastcluster-1.2.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cf5acfe1156849279ebd44a8d1fbcbe8b8e21334f7538eda782ae31e7dade9e2"}, + {file = "fastcluster-1.2.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb27c13225f5f77f3c5986a27ca27277cce7db12844330cf535019cd38021257"}, + {file = "fastcluster-1.2.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fe543b6d45da27e84e5af6248722475b88943d8ef40d835cbabbb0ba5ee786b"}, + {file = "fastcluster-1.2.6-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c12224da0b1f2f9d2b3d715dc82ecb1a3a33b990606f97da075cc46bc6d9576f"}, + {file = "fastcluster-1.2.6-cp36-cp36m-win32.whl", hash = "sha256:86a1ad972e83ba48144884fa849f87626346308b650002157123aee67d3b16fe"}, + {file = "fastcluster-1.2.6-cp36-cp36m-win_amd64.whl", hash = "sha256:8d3c9eab8e69cb36dcdd64c8b3200e008aedf88e34d39e01ae6af98a9605ad18"}, + {file = "fastcluster-1.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c61be0bad81a21ee3e5bef91469fdd11968f33d41d142c656accba9b2992babe"}, + {file = "fastcluster-1.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06df1d97edca68b2ffa43d81c3b5f4e4147bc12ab241c6585fadcdeb0bfa23ca"}, + {file = "fastcluster-1.2.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab9337b0a6a9b07b6f86fc724972d1ad729c890e2f539c1b33271c2f1f00af8b"}, + {file = "fastcluster-1.2.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4093d5454bcbe48b30e32da5db43056a08889480a96e4555f28c1f7004fc5323"}, + {file = "fastcluster-1.2.6-cp37-cp37m-win32.whl", hash = "sha256:58958a0333e3dfbad198394e9b7dd6254de0a3e622019b057288405b2a4a6bba"}, + {file = "fastcluster-1.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:03f8efe6435a7b947fa4a420676942d0267dac0d323ec5ead50f1856cc7cf96f"}, + {file = "fastcluster-1.2.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a5ceb39379327316d34613f7c16c06d7a3816aa38f4437b5e8433aa1bf149e2c"}, + {file = "fastcluster-1.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0bb54283b4d5ec96f167c7fd31921f169226c1261637434fdae7a69ee3c69573"}, + {file = "fastcluster-1.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6e51db0067e65687a5c46f00a11843d0bb15ca759e8a1767eebac8c4f6e3f4df"}, + {file = "fastcluster-1.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11748a4e245c745030e9ddd8c2c37e378f8ad8bd8e869d954c84ff674495499f"}, + {file = "fastcluster-1.2.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7254f81dc71cd29ef6f2d9747cf97ff907b569c9ef9d9760352391be5b57118c"}, + {file = "fastcluster-1.2.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa4a4c01c5fbec3623e92bc33a9f712ca416ce93255c402f5c904ac4b890ac3c"}, + {file = "fastcluster-1.2.6-cp38-cp38-win32.whl", hash = "sha256:ffdb00782cd63bbf2c45bb048897531e868326dff5081ab9b752d294b0426c1d"}, + {file = "fastcluster-1.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:a952a84453123db0c2336b9a9c86162e99ad0b897bae8213107c055a64effd41"}, + {file = "fastcluster-1.2.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a085e7e13f1afc517358981b2b7ed774dc9abf95f2be0da9a495d9e6b58c4409"}, + {file = "fastcluster-1.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a7c7f51a6d2f5ab58b1d85e9d0af2af9600ec13bb43bc6aafc9085d2c4ccd93"}, + {file = "fastcluster-1.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8bac5cf64691060cf86b0752dd385ef1eccff6d24bdb8b60691cf8cbf0e4f9ef"}, + {file = "fastcluster-1.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:060c1cb3c84942d8d3618385e2c25998ba690c46ec8c73d64477f808abfac3f2"}, + {file = "fastcluster-1.2.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03a228e018457842eb81de85be7af0b5fe8065d666dd093193e3bdcf1f13d2e"}, + {file = "fastcluster-1.2.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6f8da329c0032f2acaf4beaef958a2db0dae43d3f946f592dad5c29aa82c832"}, + {file = "fastcluster-1.2.6-cp39-cp39-win32.whl", hash = "sha256:eb3f98791427d5d5d02d023b66bcef61e48954edfadae6527ef72d70cf32ec86"}, + {file = "fastcluster-1.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:4b9cfd426966b8037bec2fc03a0d7a9c87313482c699b36ffa1432b49f84ed2e"}, + {file = "fastcluster-1.2.6.tar.gz", hash = "sha256:aab886efa7b6bba7ac124f4498153d053e5a08b822d2254926b7206cdf5a8aa6"}, +] +fastjsonschema = [ + {file = "fastjsonschema-2.16.2-py3-none-any.whl", hash = "sha256:21f918e8d9a1a4ba9c22e09574ba72267a6762d47822db9add95f6454e51cc1c"}, + {file = "fastjsonschema-2.16.2.tar.gz", hash = "sha256:01e366f25d9047816fe3d288cbfc3e10541daf0af2044763f3d0ade42476da18"}, +] +fastrlock = [ + {file = "fastrlock-0.8-cp27-cp27m-win32.whl", hash = "sha256:4d414a5e97a545fee64437586c70bd295d22ac49614eeb76fb67980e32a0d1ae"}, + {file = "fastrlock-0.8-cp27-cp27m-win_amd64.whl", hash = "sha256:b991766baec0113829c5a10bec4c5ec987cab31dfcb1fabf53e370b83b939ef9"}, + {file = "fastrlock-0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5356a15375fab5a8090f255b54122eead504ebcec8a67ac369489e3e315dfd21"}, + {file = "fastrlock-0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8369ce6d228fc3efbfcff5499468200bd12c35efdbc787eeaf8064153bcf0d72"}, + {file = "fastrlock-0.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:09314c5c0f63fe252a3ee038af855d7fb5668d0ccbae94846a35b32487c6256c"}, + {file = "fastrlock-0.8-cp35-cp35m-win32.whl", hash = "sha256:b724a7f5c1d5f9cdc30a13022e6e8cf319812c40dad0fd722b5ea18d2cfc4c4d"}, + {file = "fastrlock-0.8-cp35-cp35m-win_amd64.whl", hash = "sha256:c7ec22a5726467af53950a8baba92327620c0f73c34fab930ce29b94c8645c7e"}, + {file = "fastrlock-0.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcd7a05ba34702d0f0e9751d35afb06be21034fcf00197567ff0dcdf48cde8e7"}, + {file = "fastrlock-0.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:997bc6c4fafda396449e2410a5d32b69d231fdccc5af6de6cefe9d67e5f7157e"}, + {file = "fastrlock-0.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4ba3d3dc0dbb1cff2eee033a1f6369c24a86e8c20b427edfceff3f38b48b391c"}, + {file = "fastrlock-0.8-cp36-cp36m-win32.whl", hash = "sha256:f365fc1de226ce96fedbb475c4523b304ce00f9a59beea620dba34e21239f5f3"}, + {file = "fastrlock-0.8-cp36-cp36m-win_amd64.whl", hash = "sha256:7c9c66ab93877272169b017dc24f63c9c94b3f9d55b0b0b8c3f6d9644280120c"}, + {file = "fastrlock-0.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5d5fd2a76aa9cd451a8820e2427e512620062ffa62ea5732da0ab8888b6be6e"}, + {file = "fastrlock-0.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:340ae0734305d780aaad0893dba8185f4dbb0575d5fd696b5720eaf800526bbc"}, + {file = "fastrlock-0.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:719743b5b3c2b214fdf63096ac6a68615b4d9b8cb210e9e6ddf0293b38da2c9a"}, + {file = "fastrlock-0.8-cp37-cp37m-win32.whl", hash = "sha256:1cfb5ac6336ff327359a31b690898adf9a813fd44a76196115a3f0afb2367c81"}, + {file = "fastrlock-0.8-cp37-cp37m-win_amd64.whl", hash = "sha256:5aa6b442b12fa1f9041248506c8ea5ae909a92aedd5a139647dce2ee87e5b944"}, + {file = "fastrlock-0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af9df4c17c3142c9774cd1b9edea586f709c6421f02bcf7614507937b921ea7f"}, + {file = "fastrlock-0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:951a5c4dc6fbe4481082752ce9f21aabcaa1cf6185f683d7b5cbae254f10bb46"}, + {file = "fastrlock-0.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5c75985ba70fb4e8af595a0f67f58b96e0dbc53562768208890b4b2ac25b4b52"}, + {file = "fastrlock-0.8-cp38-cp38-win32.whl", hash = "sha256:0b459511349dc96c8961f1d43635bb94cfc2404a8899792a1f9aaa9998fa0eca"}, + {file = "fastrlock-0.8-cp38-cp38-win_amd64.whl", hash = "sha256:7b612474ddacf808c663aa8020db0a78f54a665ccabd9dbe505d3d4c4b3f6044"}, + {file = "fastrlock-0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe85f98fa66de41f929b8e01e4a9c5a7d20e660f605054b847c4ac54fadc8f79"}, + {file = "fastrlock-0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d2029fb44eac8ab5f7aafb3fcde9419cbdaa07a08f72dac8cd7790dc0f73e596"}, + {file = "fastrlock-0.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bba2a866c9f6eb1923ead5e70e1da02b3e57c531830eb4fcbd2d8e9530a2d7e"}, + {file = "fastrlock-0.8-cp39-cp39-win32.whl", hash = "sha256:85c36ac55dc917c7e1f4fb03a841fe84b3fb2669dd0306bb94bf62c5749b1a7f"}, + {file = "fastrlock-0.8-cp39-cp39-win_amd64.whl", hash = "sha256:4bb33625117bc9f1a66a5049a5d03ac4b38a44cb8eefdff1a394f7a435da54c9"}, + {file = "fastrlock-0.8.tar.gz", hash = "sha256:9cc100ed0924b32173d7de705a82fdf1257cdf60af1952a13f64759307b40931"}, +] +filelock = [ + {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, + {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, +] +flake8 = [ + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, +] +flask = [ + {file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"}, + {file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"}, +] +flask-cors = [ + {file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"}, + {file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"}, +] +flask-socketio = [ + {file = "Flask-SocketIO-5.3.1.tar.gz", hash = "sha256:fd0ed0fc1341671d92d5f5b2f5503916deb7aa7e2940e6636cfa2c087c828bf9"}, + {file = "Flask_SocketIO-5.3.1-py3-none-any.whl", hash = "sha256:ff0c721f20bff1e2cfba77948727a8db48f187e89a72fe50c34478ce6efb3353"}, +] +flatbuffers = [ + {file = "flatbuffers-22.9.24-py2.py3-none-any.whl", hash = "sha256:fc30f024e2eee55922d610f4d68626002fcd3c8f87d8058ec5ae9edd86993bcb"}, +] +fonttools = [ + {file = "fonttools-4.37.4-py3-none-any.whl", hash = "sha256:afae1b39555f9c3f0ad1f0f1daf678e5ad157e38c8842ecb567951bf1a9b9fd7"}, + {file = "fonttools-4.37.4.zip", hash = "sha256:86918c150c6412798e15a0de6c3e0d061ddefddd00f97b4f7b43dfa867ad315e"}, +] +frozenlist = [ + {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"}, + {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"}, + {file = "frozenlist-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:219a9676e2eae91cb5cc695a78b4cb43d8123e4160441d2b6ce8d2c70c60e2f3"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d64cdd973aede3dd71a9364742c542587db214e63b7529fbb487ed67cddd9"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2af6f7a4e93f5d08ee3f9152bce41a6015b5cf87546cb63872cc19b45476e98a"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a718b427ff781c4f4e975525edb092ee2cdef6a9e7bc49e15063b088961806f8"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c56c299602c70bc1bb5d1e75f7d8c007ca40c9d7aebaf6e4ba52925d88ef826d"}, + {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717470bfafbb9d9be624da7780c4296aa7935294bd43a075139c3d55659038ca"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:31b44f1feb3630146cffe56344704b730c33e042ffc78d21f2125a6a91168131"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3b31180b82c519b8926e629bf9f19952c743e089c41380ddca5db556817b221"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d82bed73544e91fb081ab93e3725e45dd8515c675c0e9926b4e1f420a93a6ab9"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49459f193324fbd6413e8e03bd65789e5198a9fa3095e03f3620dee2f2dabff2"}, + {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:94e680aeedc7fd3b892b6fa8395b7b7cc4b344046c065ed4e7a1e390084e8cb5"}, + {file = "frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"}, + {file = "frozenlist-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:eee0c5ecb58296580fc495ac99b003f64f82a74f9576a244d04978a7e97166db"}, + {file = "frozenlist-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bc75692fb3770cf2b5856a6c2c9de967ca744863c5e89595df64e252e4b3944"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086ca1ac0a40e722d6833d4ce74f5bf1aba2c77cbfdc0cd83722ffea6da52a04"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b51eb355e7f813bcda00276b0114c4172872dc5fb30e3fea059b9367c18fbcb"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74140933d45271c1a1283f708c35187f94e1256079b3c43f0c2267f9db5845ff"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4c5120ddf7d4dd1eaf079af3af7102b56d919fa13ad55600a4e0ebe532779b"}, + {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d9e00f3ac7c18e685320601f91468ec06c58acc185d18bb8e511f196c8d4b2"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e19add867cebfb249b4e7beac382d33215d6d54476bb6be46b01f8cafb4878b"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a027f8f723d07c3f21963caa7d585dcc9b089335565dabe9c814b5f70c52705a"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:61d7857950a3139bce035ad0b0945f839532987dfb4c06cfe160254f4d19df03"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"}, + {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bbb1a71b1784e68870800b1bc9f3313918edc63dbb8f29fbd2e767ce5821696c"}, + {file = "frozenlist-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ab6fa8c7871877810e1b4e9392c187a60611fbf0226a9e0b11b7b92f5ac72792"}, + {file = "frozenlist-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89139662cc4e65a4813f4babb9ca9544e42bddb823d2ec434e18dad582543bc"}, + {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4c0c99e31491a1d92cde8648f2e7ccad0e9abb181f6ac3ddb9fc48b63301808e"}, + {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e8cb51fba9f1f33887e22488bad1e28dd8325b72425f04517a4d285a04c519"}, + {file = "frozenlist-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc2f3e368ee5242a2cbe28323a866656006382872c40869b49b265add546703f"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58fb94a01414cddcdc6839807db77ae8057d02ddafc94a42faee6004e46c9ba8"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:022178b277cb9277d7d3b3f2762d294f15e85cd2534047e68a118c2bb0058f3e"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:572ce381e9fe027ad5e055f143763637dcbac2542cfe27f1d688846baeef5170"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19127f8dcbc157ccb14c30e6f00392f372ddb64a6ffa7106b26ff2196477ee9f"}, + {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42719a8bd3792744c9b523674b752091a7962d0d2d117f0b417a3eba97d1164b"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2743bb63095ef306041c8f8ea22bd6e4d91adabf41887b1ad7886c4c1eb43d5f"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fa47319a10e0a076709644a0efbcaab9e91902c8bd8ef74c6adb19d320f69b83"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52137f0aea43e1993264a5180c467a08a3e372ca9d378244c2d86133f948b26b"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:f5abc8b4d0c5b556ed8cd41490b606fe99293175a82b98e652c3f2711b452988"}, + {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e1cf7bc8cbbe6ce3881863671bac258b7d6bfc3706c600008925fb799a256e2"}, + {file = "frozenlist-1.3.1-cp38-cp38-win32.whl", hash = "sha256:0dde791b9b97f189874d654c55c24bf7b6782343e14909c84beebd28b7217845"}, + {file = "frozenlist-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:9494122bf39da6422b0972c4579e248867b6b1b50c9b05df7e04a3f30b9a413d"}, + {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31bf9539284f39ff9398deabf5561c2b0da5bb475590b4e13dd8b268d7a3c5c1"}, + {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0c8c803f2f8db7217898d11657cb6042b9b0553a997c4a0601f48a691480fab"}, + {file = "frozenlist-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da5ba7b59d954f1f214d352308d1d86994d713b13edd4b24a556bcc43d2ddbc3"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e6b2b456f21fc93ce1aff2b9728049f1464428ee2c9752a4b4f61e98c4db96"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526d5f20e954d103b1d47232e3839f3453c02077b74203e43407b962ab131e7b"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b499c6abe62a7a8d023e2c4b2834fce78a6115856ae95522f2f974139814538c"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab386503f53bbbc64d1ad4b6865bf001414930841a870fc97f1546d4d133f141"}, + {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f63c308f82a7954bf8263a6e6de0adc67c48a8b484fab18ff87f349af356efd"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:12607804084d2244a7bd4685c9d0dca5df17a6a926d4f1967aa7978b1028f89f"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:da1cdfa96425cbe51f8afa43e392366ed0b36ce398f08b60de6b97e3ed4affef"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f810e764617b0748b49a731ffaa525d9bb36ff38332411704c2400125af859a6"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:35c3d79b81908579beb1fb4e7fcd802b7b4921f1b66055af2578ff7734711cfa"}, + {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c92deb5d9acce226a501b77307b3b60b264ca21862bd7d3e0c1f3594022f01bc"}, + {file = "frozenlist-1.3.1-cp39-cp39-win32.whl", hash = "sha256:5e77a8bd41e54b05e4fb2708dc6ce28ee70325f8c6f50f3df86a44ecb1d7a19b"}, + {file = "frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"}, + {file = "frozenlist-1.3.1.tar.gz", hash = "sha256:3a735e4211a04ccfa3f4833547acdf5d2f863bfeb01cfd3edaffbc251f15cec8"}, +] +ft4222 = [ + {file = "ft4222-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:64c80402e19ada10f142cf9d5f5b343a121689b94dfc31fafc7864db13ac7f79"}, + {file = "ft4222-1.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5c713b6527513a77e674a6db60d97f67b18ce9f85727168ecbeef82557f2b2d1"}, + {file = "ft4222-1.6.0-cp310-cp310-win32.whl", hash = "sha256:324d6330d501bf6f7746aa1b81f9540a2b385e9318bd4e6e4f744d7107f90c67"}, + {file = "ft4222-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:1279115892441e4a2ab468429e5003c72f47423daa4d7179c0da4af3522c056a"}, + {file = "ft4222-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:719ec8f9c05636d8306a64f8f6f86dd9ec27d80afb3fc07e7d0b01c9b3d83d1e"}, + {file = "ft4222-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:886f3b53bad1dc238a3d6e5105b6d7442244ea854afea38daf84529491ad6e3d"}, + {file = "ft4222-1.6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:c28fb526ec98afefebb24f0e333bfef0def3ca46f8b4f84712c5e6e3c7e0fe9c"}, + {file = "ft4222-1.6.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f4b3ced3e5603f6bb22fcfcf9567a95ec47a93dd453a911e438c02d665bf657c"}, + {file = "ft4222-1.6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:376ddba0e44a24237d926bc28a519ef7877174726629c3335529f548a829e857"}, + {file = "ft4222-1.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3dff18e3d95027fb7407748d9a92eece9a2e88c3f7521be59fc848fe32a3780f"}, + {file = "ft4222-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:c0673a1420bd10b3dd782d307c60516bcd4ff24f7c27661b319c781e8a0618df"}, + {file = "ft4222-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:de38894f69cd0253a4b683612006912c5d98fae94f07f910650ab5027dc3df8e"}, + {file = "ft4222-1.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e3aae2cbd0a15f7dd9506971f32ab67dcf192c24b012258ccf2e0daeb099d8e5"}, + {file = "ft4222-1.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f4d6d21e8e00b9c5aabaff48489973cf45452cb88a9d6946eaa6aea1d48c0794"}, + {file = "ft4222-1.6.0-cp38-cp38-win32.whl", hash = "sha256:eeb1f8cf04262e2bcdaf159a767148a61ef91aa8b86950ae883bb8ba8f0e82da"}, + {file = "ft4222-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:06419df94566e5e62358f7d68055fd4155b916646ead2c479e75b964548714e3"}, + {file = "ft4222-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7a91689f9e44c6a8afedb6e5a11ba70d0c661e879607fd8635c76ebaa503cd90"}, + {file = "ft4222-1.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:31976a15a7cd649814887e3887480f3f625e82e7e2d354f33d582a0faf4c7689"}, + {file = "ft4222-1.6.0-cp39-cp39-win32.whl", hash = "sha256:b4c8309bbc2d0cf2704dd8737bcf2a6ae27284f7cf45746e79d3dbd4810e0cb3"}, + {file = "ft4222-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:395596fd03120015b7a049928ba31983f7e71596bcdb85bd78eff4293e955266"}, + {file = "ft4222-1.6.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:937124275e50adc87213fa3bda52e3ac08348454eee21b23e23ce4afd656035b"}, + {file = "ft4222-1.6.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:eb9752990913ee327ebf1279f4a4847b54cacbf95aa920d24f07cb687a77572b"}, + {file = "ft4222-1.6.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:37696c46340064e7518e4d77c8f8b044d72af26850f2e3370369201dd44b08b9"}, + {file = "ft4222-1.6.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ea7fdf9f5757e981445bbf80669f4f059912963f5718d16736c0f2b341a05610"}, + {file = "ft4222-1.6.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:f242776c497d49f0533c643138375a59fe1745c159e43ec55845fe59c1f17020"}, + {file = "ft4222-1.6.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5ba637e9c43c7aaa82915b06c4098ac885f2ae45152b1f01584307b8e6e5b005"}, + {file = "ft4222-1.6.0.tar.gz", hash = "sha256:537de8f49c21fe49f4be16e0a359315e72322a6a513b153effc95c8105c6af06"}, +] +future = [ + {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, +] +future-fstrings = [ + {file = "future_fstrings-1.2.0-py2.py3-none-any.whl", hash = "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63"}, + {file = "future_fstrings-1.2.0.tar.gz", hash = "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089"}, +] +geoalchemy2 = [ + {file = "GeoAlchemy2-0.12.5-py2.py3-none-any.whl", hash = "sha256:3a59eb651df95b3dfee8e1d82f4d18c80b75f712860a0a3080defc6b0435070d"}, + {file = "GeoAlchemy2-0.12.5.tar.gz", hash = "sha256:31c2502dce317b57b335e4eb87562d501fa39e46c728be514d9b86091e08dd67"}, +] +gevent = [ + {file = "gevent-22.10.1-cp27-cp27m-win32.whl", hash = "sha256:702a51b8f21bad1976b0893f90ade466e8c27039b846b611ad2beb8c6e6ac701"}, + {file = "gevent-22.10.1-cp27-cp27m-win_amd64.whl", hash = "sha256:af7baec79a5f8ad1cc132d3b14edd12661c628d8094e501b089b1fe2d3df7f6e"}, + {file = "gevent-22.10.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf6dd33052919de8fb56e0bea0e6a7c7d6545281fe280ea78e311621c7adb50e"}, + {file = "gevent-22.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f16c6937d47593f051fc3ac7996c819919082a1e7e0dec927cdae8771d26ed45"}, + {file = "gevent-22.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21dbeb6d3b47093f40ca97aab493b2fb64b6f22112f88f56d79cf6f52a8c1c16"}, + {file = "gevent-22.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:acb21bee2e66da45b8916073c8ae54c44629beb94d49120c188d27aff4ebf8dd"}, + {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, + {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, + {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, + {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, + {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a920a812b6c0c36d4613a15c254ca1ce415ee75ade0df3b8941ab61ae7ce3f"}, + {file = "gevent-22.10.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:33c4cd095f99768ecc4b3bb75a12f52ea9df5c40a58671c667f86ea087a075e1"}, + {file = "gevent-22.10.1-cp36-cp36m-win32.whl", hash = "sha256:db592cfe5106730667ac36f43554e7a869d757e411f8a08116c3739cee507145"}, + {file = "gevent-22.10.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a12443b7326e40d00fb445d37bae154fd1f4693055330c6b4e68670ca3b6e6bf"}, + {file = "gevent-22.10.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5d64b208bec99adc7e0b6e08a3e2c296065c665ca725ca8da434c4ffc5aa302e"}, + {file = "gevent-22.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ac816f5e8e318c5fa27091ee43fcf4caaa6ae73a487e875a1a296a04c3da5af"}, + {file = "gevent-22.10.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0d9d6f869ba7c49d7f9b7d244dd20daec5cc87cd3e2e90209d6ed8172e0cad"}, + {file = "gevent-22.10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3c1cfd9f9fb6a2a5a9a04132d315db7fb819db019dea260695fe6e4012416f96"}, + {file = "gevent-22.10.1-cp37-cp37m-win32.whl", hash = "sha256:4b0d29fc18ee338a85396facfc508e5f26e2e0e90f4c2889f8a9e74d341ad467"}, + {file = "gevent-22.10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:36e47ca663081a71fca137b7c852e99e7ee3761082070c13aa2ae3b5b6234af6"}, + {file = "gevent-22.10.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a838437b7b629328ad457cd36df454500afe7f3df4b971a6ff85851dfcf8c844"}, + {file = "gevent-22.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c06c0f3f4f1b147f51a934fbf541880cee769492b98c4ebd3e930b5ff862646"}, + {file = "gevent-22.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d701208d4d65dbdf9feb02561a75ecc5bd28300e47b59f74033a07b593887806"}, + {file = "gevent-22.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e8c4ccc544f6e6c26ab10d0d6a7be86bd522222ce40f00bfafa01289f04bffc"}, + {file = "gevent-22.10.1-cp38-cp38-win32.whl", hash = "sha256:4be5859af086de1ed85702c0a84479387087ddf49e38332c41861b0a10e96d8f"}, + {file = "gevent-22.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:be43278781d39b4081f7f4d3e8ebb1dac188c9fe98f25da817325cb12c01887a"}, + {file = "gevent-22.10.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cafb8f5399224990a5329bca3606bf399ee3604ae711b2d9238129b44551ad5"}, + {file = "gevent-22.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e1c609f9e4171588006bea7ff41bb830ff27c27d071bbd311f91860fb5ef4cc"}, + {file = "gevent-22.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2dcfd8ef9dcca78c51dd266d0f4b48d9b7ea2592ae881bf66d8dbe59bb16631a"}, + {file = "gevent-22.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eefcb21fda3055f2e7eaad2e8098885a7bbddd83b174b012e2142db6b2b4c09d"}, + {file = "gevent-22.10.1-cp39-cp39-win32.whl", hash = "sha256:3f7d11136b3ae6312effbc2ac0ed902ae718d86e7acb9a51cf927262cfb2931e"}, + {file = "gevent-22.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:1ec5f77f629d997668983be53bad2a90d1b858a00e43b9e75e1c9a118c3a840b"}, + {file = "gevent-22.10.1-pp27-pypy_73-win_amd64.whl", hash = "sha256:d8df3f628c8a9fb339b87a849dc2076e56d124e2169261fa58b4a01db3a335b6"}, + {file = "gevent-22.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0569e133bb620de1001ac807ad9a8abaadedd25349c6d695f80c9048a3f59d42"}, + {file = "gevent-22.10.1.tar.gz", hash = "sha256:df3042349c9a4460eeaec8d0e56d737cb183eed055e75a6af9dbda94aaddaf4d"}, +] +greenlet = [ + {file = "greenlet-1.1.3.post0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-win32.whl", hash = "sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05"}, + {file = "greenlet-1.1.3.post0-cp27-cp27m-win_amd64.whl", hash = "sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519"}, + {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392"}, + {file = "greenlet-1.1.3.post0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5"}, + {file = "greenlet-1.1.3.post0-cp310-cp310-win_amd64.whl", hash = "sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f"}, + {file = "greenlet-1.1.3.post0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-win32.whl", hash = "sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f"}, + {file = "greenlet-1.1.3.post0-cp35-cp35m-win_amd64.whl", hash = "sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-win32.whl", hash = "sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04"}, + {file = "greenlet-1.1.3.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-win32.whl", hash = "sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427"}, + {file = "greenlet-1.1.3.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-win32.whl", hash = "sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a"}, + {file = "greenlet-1.1.3.post0-cp38-cp38-win_amd64.whl", hash = "sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"}, + {file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"}, + {file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"}, +] +gunicorn = [ + {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, + {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, +] +h3 = [ + {file = "h3-3.7.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e61d3c6b1b66072f5b74d46dbee7df29daac6ce9738b9a6223a67dc577114515"}, + {file = "h3-3.7.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:960cd005b8817314d95fbaff3e848a72385df4e3c6c9703ff99b08581c8def69"}, + {file = "h3-3.7.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:68227df989274b0da54de9101a50741c70c48197ba3beacfb97c88170445c18e"}, + {file = "h3-3.7.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bf4d75fe42a260ac23bf4cb9f9de6e6f2aa37279b2719387711f3e0727c4653"}, + {file = "h3-3.7.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c644ab3f221c7faaab2d1ccd11bc3b1106f172e9bb1c85a863b0a097f6b71cce"}, + {file = "h3-3.7.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5366d24c2c01ef3bae68547c15f1965fac6053b2596c0073766bf7544ecaf0"}, + {file = "h3-3.7.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83c2b0cd8259541f95b0493a620fb781b6a18c7c1e8fac1bda4fb234ae23ab43"}, + {file = "h3-3.7.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1108a9acb755310dce50a6e3c58ae1a2460ef60901d40e1155d633c7392f858"}, + {file = "h3-3.7.4-cp310-cp310-win_amd64.whl", hash = "sha256:ce86c6dce2c923bfb16e26586bc5f0443a8be61d4f43227be8587ccb95588a46"}, + {file = "h3-3.7.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ad21cfa8d97a62984ce30692a7ddf71a32a0c744cc247c43cbdbac1536aec4de"}, + {file = "h3-3.7.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be63482de86bbb91db7f3f3b7dd452b9e08a11dacbda2088386831fb0e7de59c"}, + {file = "h3-3.7.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a96ea1844182bd0511cdcdc89e38e3026d9a3d4139fd0c5e899709edd798ffa"}, + {file = "h3-3.7.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2faf304020493c5ffede34264bd28ed529b8b7238103e0904c0f3e9ca880bcfd"}, + {file = "h3-3.7.4-cp36-cp36m-win_amd64.whl", hash = "sha256:3b1642085939c597a9c723ae3b187f80527ffc79cad0ded0e55be9c9bac69c6c"}, + {file = "h3-3.7.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8d03622433da1a2761574311af378ff1ff841f5956db25927837c6aee9d1c13c"}, + {file = "h3-3.7.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08a09f7a43ed142573c602ef487a058da54ab4d86c173082b29a5057805fe2d3"}, + {file = "h3-3.7.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4469fdf90034b1a67e155cac4f46b077fdc404b6182ab33abcb7081c9bfbf411"}, + {file = "h3-3.7.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:33b147ecc0e19ab1f27303d0e3ae28e5a457f3347ce18ca9a58b694a8b0cdd0a"}, + {file = "h3-3.7.4-cp37-cp37m-win_amd64.whl", hash = "sha256:c95c0818c163b69989c9e876dd82005e60edfbaabfd45429abebfc26f9a357e8"}, + {file = "h3-3.7.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7b0ddfdd02920996d7c6672c91e83efb5432c67ff83f89a03f774e84bcfe19f8"}, + {file = "h3-3.7.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46a1284521d86cab414981056390be944dca780fe74c6c9e463a16d1c8d24871"}, + {file = "h3-3.7.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:585f375ba2a95ceb16b115a378e9118159c912c26703cf1627f57a004818c3b3"}, + {file = "h3-3.7.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdd68e684f0c6e18604d46ee04dbcfe5c79de62238b2c29f1db0f3a5d8dfa47b"}, + {file = "h3-3.7.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a59d7d10597a2da9e9729637a625ae8dff2ed4e7c6c0b4952f0a5b2db6ef7152"}, + {file = "h3-3.7.4-cp38-cp38-win_amd64.whl", hash = "sha256:38a084d74b234d48aafc01e4329cd9a92966e3f45b8cf21224118643b6eaa1c0"}, + {file = "h3-3.7.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a33fae02a54c63acb3c30fe49388715d658d76d42858a6ad4563e7e6859a9e57"}, + {file = "h3-3.7.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b0277d82578b3ed3220167ef5c5acd8b4e0ef2fcd6c2fd69dbf29e0c4e03765"}, + {file = "h3-3.7.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8155b2de1938eb56128fe4fd96e4f6d2022d4c34d8137bc95d73cbf329f8f89e"}, + {file = "h3-3.7.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1387166f453816f91d624c6ce70876a3c20356cd28a3a759920dee23c78684cf"}, + {file = "h3-3.7.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:62057c1c3d1c7fe492841e42fa360825d66fafd55ac37dc4e90b2292af21cb47"}, + {file = "h3-3.7.4-cp39-cp39-win_amd64.whl", hash = "sha256:25f0c22f4802ab71c45b86d206bd30fa0a6c7fbc3b630398b60c22907e9742e6"}, + {file = "h3-3.7.4.tar.gz", hash = "sha256:f8edf5a546b31afdcd801b60448ea890ce1ff418fb784335e1329519f13aa85e"}, +] +hatanaka = [ + {file = "hatanaka-2.4.0-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:ef594d63473782fac46df5b0c92a59211a3efea1d47c1a964244a0abffc9f3f6"}, + {file = "hatanaka-2.4.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8fda4aa56f27313de75a806a2f5aa83ed5bb2dc7561bebab856a774d06cf1ee7"}, + {file = "hatanaka-2.4.0-py3-none-win_amd64.whl", hash = "sha256:5a0624f6812b13abb4c996398a60338566885c1786841c4c04de9b1b91da28d2"}, + {file = "hatanaka-2.4.0.tar.gz", hash = "sha256:c22970b99169bddaf22e5239672e856a6bc9602c435f8793d26ad49619a70a99"}, +] +hexdump = [ + {file = "hexdump-3.3.zip", hash = "sha256:d781a43b0c16ace3f9366aade73e8ad3a7bd5137d58f0b45ab2d3f54876f20db"}, +] +html5lib = [ + {file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"}, + {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, +] +humanfriendly = [ + {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"}, + {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"}, +] +hypothesis = [ + {file = "hypothesis-6.46.7-py3-none-any.whl", hash = "sha256:2696cdb9005946bf1d2b215cc91d3fc01625e3342eb8743ddd04b667b2f1882b"}, + {file = "hypothesis-6.46.7.tar.gz", hash = "sha256:967009fa561b3a3f8363a73d71923357271c37dc7fa27b30c2d21a1b6092b240"}, +] +identify = [ + {file = "identify-2.5.6-py2.py3-none-any.whl", hash = "sha256:b276db7ec52d7e89f5bc4653380e33054ddc803d25875952ad90b0f012cbcdaa"}, + {file = "identify-2.5.6.tar.gz", hash = "sha256:6c32dbd747aa4ceee1df33f25fed0b0f6e0d65721b15bd151307ff7056d50245"}, +] +idna = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] +imageio = [ + {file = "imageio-2.22.2-py3-none-any.whl", hash = "sha256:9bdafe9c5a3d336a187f3f554f3e30bcdbf8a1d7d46f0e4d94e4a535adfb64c7"}, + {file = "imageio-2.22.2.tar.gz", hash = "sha256:db7010cd10712518819a4187baf61b05988361ea20c23e829918727b27acb977"}, +] +imagesize = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] +importlib-metadata = [ + {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, + {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, +] +importlib-resources = [ + {file = "importlib_resources-5.10.0-py3-none-any.whl", hash = "sha256:ee17ec648f85480d523596ce49eae8ead87d5631ae1551f913c0100b5edd3437"}, + {file = "importlib_resources-5.10.0.tar.gz", hash = "sha256:c01b1b94210d9849f286b86bb51bcea7cd56dde0600d8db721d7b81330711668"}, +] +influxdb-client = [ + {file = "influxdb_client-1.33.0-py3-none-any.whl", hash = "sha256:38a8bedce673ffd2211f60012b5848cb2418977c19f83a43454882b665acbc69"}, + {file = "influxdb_client-1.33.0.tar.gz", hash = "sha256:45f6a1763804a19b972890daf4c5f0bd2d3ae2f202b86451c579e09dcadd30e6"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +inputs = [ + {file = "inputs-0.5-py2.py3-none-any.whl", hash = "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec"}, + {file = "inputs-0.5.tar.gz", hash = "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4"}, +] +ipykernel = [ + {file = "ipykernel-6.16.1-py3-none-any.whl", hash = "sha256:32eb7bdc5af57185e9a42b0dcef66413ef91a0490b378eae46cbdf0d4e0b5912"}, + {file = "ipykernel-6.16.1.tar.gz", hash = "sha256:3a27a550c1d682e7825f0f7732b0142b79ef1b21cd2e713cacac0c9847535f13"}, +] +ipython = [ + {file = "ipython-8.5.0-py3-none-any.whl", hash = "sha256:6f090e29ab8ef8643e521763a4f1f39dc3914db643122b1e9d3328ff2e43ada2"}, + {file = "ipython-8.5.0.tar.gz", hash = "sha256:097bdf5cd87576fd066179c9f7f208004f7a6864ee1b20f37d346c0bcb099f84"}, +] +ipython-genutils = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] +ipywidgets = [ + {file = "ipywidgets-8.0.2-py3-none-any.whl", hash = "sha256:1dc3dd4ee19ded045ea7c86eb273033d238d8e43f9e7872c52d092683f263891"}, + {file = "ipywidgets-8.0.2.tar.gz", hash = "sha256:08cb75c6e0a96836147cbfdc55580ae04d13e05d26ffbc377b4e1c68baa28b1f"}, +] +isodate = [ + {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, + {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, +] +isort = [ + {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, + {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, +] +itsdangerous = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] +jaraco-classes = [ + {file = "jaraco.classes-3.2.3-py3-none-any.whl", hash = "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158"}, + {file = "jaraco.classes-3.2.3.tar.gz", hash = "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"}, +] +jedi = [ + {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, + {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, +] +jeepney = [ + {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, + {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, +] +jinja2 = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] +jmespath = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] +joblib = [ + {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"}, + {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"}, +] +json-logging-py = [ + {file = "json-logging-py-0.2.tar.gz", hash = "sha256:118b1fe1f4eacaea6370e5b9710d0f6d0c0a4599aef9d5b9875a6a579974fc9a"}, +] +json-rpc = [ + {file = "json-rpc-1.13.0.tar.gz", hash = "sha256:def0dbcf5b7084fc31d677f2f5990d988d06497f2f47f13024274cfb2d5d7589"}, + {file = "json_rpc-1.13.0-py2.py3-none-any.whl", hash = "sha256:84b45058e5ba95f49c7b6afcf7e03ab86bee89bf2c01f3ad8dd41fe114fc1f84"}, +] +json5 = [ + {file = "json5-0.9.10-py2.py3-none-any.whl", hash = "sha256:993189671e7412e9cdd8be8dc61cf402e8e579b35f1d1bb20ae6b09baa78bbce"}, + {file = "json5-0.9.10.tar.gz", hash = "sha256:ad9f048c5b5a4c3802524474ce40a622fae789860a86f10cc4f7e5f9cf9b46ab"}, +] +jsonschema = [ + {file = "jsonschema-4.16.0-py3-none-any.whl", hash = "sha256:9e74b8f9738d6a946d70705dc692b74b5429cd0960d58e79ffecfc43b2221eb9"}, + {file = "jsonschema-4.16.0.tar.gz", hash = "sha256:165059f076eff6971bae5b742fc029a7b4ef3f9bcf04c14e4776a7605de14b23"}, +] +jupyter = [ + {file = "jupyter-1.0.0-py2.py3-none-any.whl", hash = "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78"}, + {file = "jupyter-1.0.0.tar.gz", hash = "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"}, + {file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"}, +] +jupyter-client = [ + {file = "jupyter_client-7.4.3-py3-none-any.whl", hash = "sha256:8845e3f5a339734b1ecc21d2100638aa1c7a145e356a31845f155cda5b624b1c"}, + {file = "jupyter_client-7.4.3.tar.gz", hash = "sha256:4fa2514cdb54dd9fbdcf7d7e4c5c3c8a973028168a8b4fc097b6aef625be13b0"}, +] +jupyter-console = [ + {file = "jupyter_console-6.4.4-py3-none-any.whl", hash = "sha256:756df7f4f60c986e7bc0172e4493d3830a7e6e75c08750bbe59c0a5403ad6dee"}, + {file = "jupyter_console-6.4.4.tar.gz", hash = "sha256:172f5335e31d600df61613a97b7f0352f2c8250bbd1092ef2d658f77249f89fb"}, +] +jupyter-core = [ + {file = "jupyter_core-4.11.2-py3-none-any.whl", hash = "sha256:3815e80ec5272c0c19aad087a0d2775df2852cfca8f5a17069e99c9350cecff8"}, + {file = "jupyter_core-4.11.2.tar.gz", hash = "sha256:c2909b9bc7dca75560a6c5ae78c34fd305ede31cd864da3c0d0bb2ed89aa9337"}, +] +jupyter-server = [ + {file = "jupyter_server-1.21.0-py3-none-any.whl", hash = "sha256:992531008544d77e05a16251cdfbd0bdff1b1efa14760c79b9cc776ac9214cf1"}, + {file = "jupyter_server-1.21.0.tar.gz", hash = "sha256:d0adca19913a3763359be7f0b8c2ea8bfde356f4b8edd8e3149d7d0fbfaa248b"}, +] +jupyterlab = [ + {file = "jupyterlab-3.4.8-py3-none-any.whl", hash = "sha256:4626a0434c76a3a22f11c4efaa1d031d2586367f72cfdbdbff6b08b6ef0060f7"}, + {file = "jupyterlab-3.4.8.tar.gz", hash = "sha256:1fafb8b657005d91603f3c3adfd6d9e8eaf33fdc601537fef09283332efe67cb"}, +] +jupyterlab-pygments = [ + {file = "jupyterlab_pygments-0.2.2-py2.py3-none-any.whl", hash = "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f"}, + {file = "jupyterlab_pygments-0.2.2.tar.gz", hash = "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d"}, +] +jupyterlab-server = [ + {file = "jupyterlab_server-2.16.1-py3-none-any.whl", hash = "sha256:b572cd3e59b0722120f41d47f2363a0072765227184aea418b7cc276db4d75fd"}, + {file = "jupyterlab_server-2.16.1.tar.gz", hash = "sha256:fe0de558ff3bb447a32e24099aa7e17444fdbc8c08f6dbc0171cb1a0ae382d3f"}, +] +jupyterlab-vim = [ + {file = "jupyterlab_vim-0.15.1-py3-none-any.whl", hash = "sha256:e3ea4a0f140bb2956fa7c3b75442121cce264930fb94f06e5b0f75ccae2bde2e"}, + {file = "jupyterlab_vim-0.15.1.tar.gz", hash = "sha256:c4282beb4a67d21f7126e32cda19f99ed324a1d3fc494560e393fe53f7519a74"}, +] +jupyterlab-widgets = [ + {file = "jupyterlab_widgets-3.0.3-py3-none-any.whl", hash = "sha256:6aa1bc0045470d54d76b9c0b7609a8f8f0087573bae25700a370c11f82cb38c8"}, + {file = "jupyterlab_widgets-3.0.3.tar.gz", hash = "sha256:c767181399b4ca8b647befe2d913b1260f51bf9d8ef9b7a14632d4c1a7b536bd"}, +] +keyring = [ + {file = "keyring-23.9.3-py3-none-any.whl", hash = "sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0"}, + {file = "keyring-23.9.3.tar.gz", hash = "sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5"}, +] +kiwisolver = [ + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, + {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, +] +knack = [ + {file = "knack-0.10.0-py3-none-any.whl", hash = "sha256:9e989286622d4a028ba738111f9fac475bae93146d375522141908ce43077cda"}, + {file = "knack-0.10.0.tar.gz", hash = "sha256:13190fa95d4c21bce04b4bee22d6a4e3fb19a93b6999b1d104bd02c476706c28"}, +] +lazy-object-proxy = [ + {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, + {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, + {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, + {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, + {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, + {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, + {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, +] +libusb1 = [ + {file = "libusb1-3.0.0-py3-none-any.whl", hash = "sha256:0e652b04cbe85ec8e74f9ee82b49f861fb14b5320ae51399387ad2601ccc0500"}, + {file = "libusb1-3.0.0-py3-none-win32.whl", hash = "sha256:083f75e5d15cb5e2159e64c308c5317284eae926a820d6dce53a9505d18be3b2"}, + {file = "libusb1-3.0.0-py3-none-win_amd64.whl", hash = "sha256:6f6bb010632ada35c661d17a65e135077beef0fbb2434d5ffdb3a4a911fd9490"}, + {file = "libusb1-3.0.0.tar.gz", hash = "sha256:5792a9defee40f15d330a40d9b1800545c32e47ba7fc66b6f28f133c9fcc8538"}, +] +lockfile = [ + {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, + {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, +] +lru-dict = [ + {file = "lru-dict-1.1.8.tar.gz", hash = "sha256:878bc8ef4073e5cfb953dfc1cf4585db41e8b814c0106abde34d00ee0d0b3115"}, + {file = "lru_dict-1.1.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9d5815c0e85922cd0fb8344ca8b1c7cf020bf9fc45e670d34d51932c91fd7ec"}, + {file = "lru_dict-1.1.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f877f53249c3e49bbd7612f9083127290bede6c7d6501513567ab1bf9c581381"}, + {file = "lru_dict-1.1.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fef595c4f573141d54a38bda9221b9ee3cbe0acc73d67304a1a6d5972eb2a02"}, + {file = "lru_dict-1.1.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:db20597c4e67b4095b376ce2e83930c560f4ce481e8d05737885307ed02ba7c1"}, + {file = "lru_dict-1.1.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5b09dbe47bc4b4d45ffe56067aff190bc3c0049575da6e52127e114236e0a6a7"}, + {file = "lru_dict-1.1.8-cp310-cp310-win32.whl", hash = "sha256:3b1692755fef288b67af5cd8a973eb331d1f44cb02cbdc13660040809c2bfec6"}, + {file = "lru_dict-1.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:8f6561f9cd5a452cb84905c6a87aa944fdfdc0f41cc057d03b71f9b29b2cc4bd"}, + {file = "lru_dict-1.1.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ca8f89361e0e7aad0bf93ae03a31502e96280faeb7fb92267f4998fb230d36b2"}, + {file = "lru_dict-1.1.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c50ab9edaa5da5838426816a2b7bcde9d576b4fc50e6a8c062073dbc4969d78"}, + {file = "lru_dict-1.1.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fe16ade5fd0a57e9a335f69b8055aaa6fb278fbfa250458e4f6b8255115578f"}, + {file = "lru_dict-1.1.8-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:de972c7f4bc7b6002acff2a8de984c55fbd7f2289dba659cfd90f7a0f5d8f5d1"}, + {file = "lru_dict-1.1.8-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3d003a864899c29b0379e412709a6e516cbd6a72ee10b09d0b33226343617412"}, + {file = "lru_dict-1.1.8-cp36-cp36m-win32.whl", hash = "sha256:6e2a7aa9e36626fb48fdc341c7e3685a31a7b50ea4918677ea436271ad0d904d"}, + {file = "lru_dict-1.1.8-cp36-cp36m-win_amd64.whl", hash = "sha256:d2ed4151445c3f30423c2698f72197d64b27b1cd61d8d56702ffe235584e47c2"}, + {file = "lru_dict-1.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:075b9dd46d7022b675419bc6e3631748ae184bc8af195d20365a98b4f3bb2914"}, + {file = "lru_dict-1.1.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70364e3cbef536adab8762b4835e18f5ca8e3fddd8bd0ec9258c42bbebd0ee77"}, + {file = "lru_dict-1.1.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:720f5728e537f11a311e8b720793a224e985d20e6b7c3d34a891a391865af1a2"}, + {file = "lru_dict-1.1.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c2fe692332c2f1d81fd27457db4b35143801475bfc2e57173a2403588dd82a42"}, + {file = "lru_dict-1.1.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:86d32a4498b74a75340497890a260d37bf1560ad2683969393032977dd36b088"}, + {file = "lru_dict-1.1.8-cp37-cp37m-win32.whl", hash = "sha256:348167f110494cfafae70c066470a6f4e4d43523933edf16ccdb8947f3b5fae0"}, + {file = "lru_dict-1.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:9be6c4039ef328676b868acea619cd100e3de1a35b3be211cf0eaf9775563b65"}, + {file = "lru_dict-1.1.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a777d48319d293b1b6a933d606c0e4899690a139b4c81173451913bbcab6f44f"}, + {file = "lru_dict-1.1.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99f6cfb3e28490357a0805b409caf693e46c61f8dbb789c51355adb693c568d3"}, + {file = "lru_dict-1.1.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:163079dbda54c3e6422b23da39fb3ecc561035d65e8496ff1950cbdb376018e1"}, + {file = "lru_dict-1.1.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0972d669e9e207617e06416166718b073a49bf449abbd23940d9545c0847a4d9"}, + {file = "lru_dict-1.1.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:97c24ffc55de6013075979f440acd174e88819f30387074639fb7d7178ca253e"}, + {file = "lru_dict-1.1.8-cp38-cp38-win32.whl", hash = "sha256:0f83cd70a6d32f9018d471be609f3af73058f700691657db4a3d3dd78d3f96dd"}, + {file = "lru_dict-1.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:add762163f4af7f4173fafa4092eb7c7f023cf139ef6d2015cfea867e1440d82"}, + {file = "lru_dict-1.1.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ac524e4615f06dc72ffbfd83f26e073c9ec256de5413634fbd024c010a8bc"}, + {file = "lru_dict-1.1.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7284bdbc5579bbdc3fc8f869ed4c169f403835566ab0f84567cdbfdd05241847"}, + {file = "lru_dict-1.1.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca497cb25f19f24171f9172805f3ff135b911aeb91960bd4af8e230421ccb51"}, + {file = "lru_dict-1.1.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1df1da204a9f0b5eb8393a46070f1d984fa8559435ee790d7f8f5602038fc00"}, + {file = "lru_dict-1.1.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f4d0a6d733a23865019b1c97ed6fb1fdb739be923192abf4dbb644f697a26a69"}, + {file = "lru_dict-1.1.8-cp39-cp39-win32.whl", hash = "sha256:7be1b66926277993cecdc174c15a20c8ce785c1f8b39aa560714a513eef06473"}, + {file = "lru_dict-1.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:881104711900af45967c2e5ce3e62291dd57d5b2a224d58b7c9f60bf4ad41b8c"}, + {file = "lru_dict-1.1.8-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:beb089c46bd95243d1ac5b2bd13627317b08bf40dd8dc16d4b7ee7ecb3cf65ca"}, + {file = "lru_dict-1.1.8-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10fe823ff90b655f0b6ba124e2b576ecda8c61b8ead76b456db67831942d22f2"}, + {file = "lru_dict-1.1.8-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07163c9dcbb2eca377f366b1331f46302fd8b6b72ab4d603087feca00044bb0"}, + {file = "lru_dict-1.1.8-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93336911544ebc0e466272043adab9fb9f6e9dcba6024b639c32553a3790e089"}, + {file = "lru_dict-1.1.8-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:55aeda6b6789b2d030066b4f5f6fc3596560ba2a69028f35f3682a795701b5b1"}, + {file = "lru_dict-1.1.8-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:262a4e622010ceb960a6a5222ed011090e50954d45070fd369c0fa4d2ed7d9a9"}, + {file = "lru_dict-1.1.8-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6f64005ede008b7a866be8f3f6274dbf74e656e15e4004e9d99ad65efb01809"}, + {file = "lru_dict-1.1.8-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:9d70257246b8207e8ef3d8b18457089f5ff0dfb087bd36eb33bce6584f2e0b3a"}, + {file = "lru_dict-1.1.8-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f874e9c2209dada1a080545331aa1277ec060a13f61684a8642788bf44b2325f"}, + {file = "lru_dict-1.1.8-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a592363c93d6fc6472d5affe2819e1c7590746aecb464774a4f67e09fbefdfc"}, + {file = "lru_dict-1.1.8-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f340b61f3cdfee71f66da7dbfd9a5ea2db6974502ccff2065cdb76619840dca"}, + {file = "lru_dict-1.1.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9447214e4857e16d14158794ef01e4501d8fad07d298d03308d9f90512df02fa"}, +] +lxml = [ + {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, + {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, + {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, + {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, + {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, + {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, + {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, + {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, + {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, + {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, + {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, + {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, + {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, + {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, + {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, + {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, + {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, + {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, + {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, + {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, + {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, + {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, + {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, + {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, + {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, + {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, + {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, + {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, + {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, + {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, + {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, + {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, + {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, + {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, + {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, + {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, + {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, + {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, + {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, + {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, + {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, + {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, + {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, + {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, + {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, + {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, + {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, + {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, + {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, + {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, +] +mako = [ + {file = "Mako-1.2.3-py3-none-any.whl", hash = "sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f"}, + {file = "Mako-1.2.3.tar.gz", hash = "sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd"}, +] +markdown = [ + {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"}, + {file = "Markdown-3.4.1.tar.gz", hash = "sha256:3b809086bb6efad416156e00a0da66fe47618a5d6918dd688f53f40c8e4cfeff"}, +] +markdown-it-py = [ + {file = "markdown-it-py-2.1.0.tar.gz", hash = "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da"}, + {file = "markdown_it_py-2.1.0-py3-none-any.whl", hash = "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27"}, +] +markupsafe = [ + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, +] +matplotlib = [ + {file = "matplotlib-3.6.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:7730e60e751cfcfe7fcb223cf03c0b979e9a064c239783ad37929d340a364cef"}, + {file = "matplotlib-3.6.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9dd40505ccc526acaf9a5db1b3029e237c64b58f1249983b28a291c2d6a1d0fa"}, + {file = "matplotlib-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:85948b303534b69fd771126764cf883fde2af9b003eb5778cb60f3b46f93d3f6"}, + {file = "matplotlib-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71eced071825005011cdc64efbae2e2c76b8209c18aa487dedf69796fe4b1e40"}, + {file = "matplotlib-3.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220314c2d6b9ca11570d7cd4b841c9f3137546f188336003b9fb8def4dcb804d"}, + {file = "matplotlib-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cc5d726d4d42865f909c5208a7841109d76584950dd0587b01a77cc279d4ab7"}, + {file = "matplotlib-3.6.1-cp310-cp310-win32.whl", hash = "sha256:183bf3ac6a6023ee590aa4b677f391ceed65ec0d6b930901a8483c267bd12995"}, + {file = "matplotlib-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:a68b91ac7e6bb26100a540a033f54c95fe06d9c0aa51312c2a52d07d1bde78f4"}, + {file = "matplotlib-3.6.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:4648f0d79a87bf50ee740058305c91091ee5e1fbb71a7d2f5fe6707bfe328d1c"}, + {file = "matplotlib-3.6.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9403764017d20ff570f7ce973a8b9637f08a6109118f4e0ce6c7493d8849a0d3"}, + {file = "matplotlib-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4c8b5a243dd29d50289d694e931bd6cb6ae0b5bd654d12c647543d63862540c"}, + {file = "matplotlib-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1effccef0cea2d4da9feeed22079adf6786f92c800a7d0d2ef2104318a1c66c"}, + {file = "matplotlib-3.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dc25473319afabe49150267e54648ac559c33b0fc2a80c8caecfbbc2948a820"}, + {file = "matplotlib-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47cb088bbce82ae9fc2edf3c25e56a5c6142ce2553fea2b781679f960a70c207"}, + {file = "matplotlib-3.6.1-cp311-cp311-win32.whl", hash = "sha256:4d3b0e0a4611bd22065bbf47e9b2f689ac9e575bcb850a9f0ae2bbed75cab956"}, + {file = "matplotlib-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:e3c116e779fbbf421a9e4d3060db259a9bb486d98f4e3c5a0877c599bd173582"}, + {file = "matplotlib-3.6.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:565f514dec81a41cbed10eb6011501879695087fc2787fb89423a466508abbbd"}, + {file = "matplotlib-3.6.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:05e86446562063d6186ff6d700118c0dbd5dccc403a6187351ee526c48878f10"}, + {file = "matplotlib-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8245e85fd793f58edf29b8a9e3be47e8ecf76ea1a1e8240545f2746181ca5787"}, + {file = "matplotlib-3.6.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1e2c75d5d1ff6b7ef9870360bfa23bea076b8dc0945a60d19453d7619ed9ea8f"}, + {file = "matplotlib-3.6.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9756a8e69f6e1f76d47eb42132175b6814da1fbeae0545304c6d0fc2aae252a"}, + {file = "matplotlib-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f5788168da2661b42f7468063b725cc73fdbeeb80f2704cb2d8c415e9a57c50"}, + {file = "matplotlib-3.6.1-cp38-cp38-win32.whl", hash = "sha256:0bab7564aafd5902128d54b68dca04f5755413fb6b502100bb0235a545882c48"}, + {file = "matplotlib-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3c53486278a0629fd892783271dc994b962fba8dfe207445d039e14f1928ea46"}, + {file = "matplotlib-3.6.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:27337bcb38d5db7430c14f350924542d75416ec1546d5d9d9f39b362b71db3fb"}, + {file = "matplotlib-3.6.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fad858519bd6d52dbfeebdbe04d00dd8e932ed436f1c535e61bcc970a96c11e4"}, + {file = "matplotlib-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a3d903588b519b38ed085d0ae762a1dcd4b70164617292175cfd91b90d6c415"}, + {file = "matplotlib-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bdbd37d0a41e025879863fe9b17bab15c0421313bc33e77e5e1aa54215c9c5"}, + {file = "matplotlib-3.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e632f66218811d4cf8b7a2a649e25ec15406c3c498f72d19e2bcf8377f38445d"}, + {file = "matplotlib-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ddd58324dc9a77e2e56d7b7aea7dbd0575b6f7cd1333c3ca9d388ac70978344"}, + {file = "matplotlib-3.6.1-cp39-cp39-win32.whl", hash = "sha256:12ab21d0cad122f5b23688d453a0280676e7c42f634f0dbd093d15d42d142b1f"}, + {file = "matplotlib-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:563896ba269324872ace436a57775dcc8322678a9496b28a8c25cdafa5ec2b92"}, + {file = "matplotlib-3.6.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:52935b7d4ccbf0dbc9cf454dbb10ca99c11cbe8da9467596b96e5e21fd4dfc5c"}, + {file = "matplotlib-3.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87027ff7b2edeb14476900261ef04d4beae949e1dfa0a3eb3ad6a6efbf9d0e1d"}, + {file = "matplotlib-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4de03085afb3b80fab341afaf8e60dfe06ce439b6dfed55d657cf34a7bc3c40"}, + {file = "matplotlib-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b53387d4e59432ff221540a4ffb5ee9669c69417805e4faf0148a00d701c61f9"}, + {file = "matplotlib-3.6.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:02561141c434154f7bae8e5449909d152367cb40aa57bfb2a27f2748b9c5f95f"}, + {file = "matplotlib-3.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0161ebf87518ecfe0980c942d5f0d5df0e080c1746ebaab2027a969967014b7"}, + {file = "matplotlib-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2469f57e4c5cc0e85eddc7b30995ea9c404a78c0b1856da75d1a5887156ca350"}, + {file = "matplotlib-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5f97141e05baf160c3ec125f06ceb2a44c9bb62f42fcb8ee1c05313c73e99432"}, + {file = "matplotlib-3.6.1.tar.gz", hash = "sha256:e2d1b7225666f7e1bcc94c0bc9c587a82e3e8691da4757e357e5c2515222ee37"}, +] +matplotlib-inline = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +mdit-py-plugins = [ + {file = "mdit-py-plugins-0.3.1.tar.gz", hash = "sha256:3fc13298497d6e04fe96efdd41281bfe7622152f9caa1815ea99b5c893de9441"}, + {file = "mdit_py_plugins-0.3.1-py3-none-any.whl", hash = "sha256:606a7f29cf56dbdfaf914acb21709b8f8ee29d857e8f29dcc33d8cb84c57bfa1"}, +] +mdurl = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] +mistune = [ + {file = "mistune-2.0.4-py2.py3-none-any.whl", hash = "sha256:182cc5ee6f8ed1b807de6b7bb50155df7b66495412836b9a74c8fbdfc75fe36d"}, + {file = "mistune-2.0.4.tar.gz", hash = "sha256:9ee0a66053e2267aba772c71e06891fa8f1af6d4b01d5e84e267b4570d4d9808"}, +] +more-itertools = [ + {file = "more-itertools-9.0.0.tar.gz", hash = "sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab"}, + {file = "more_itertools-9.0.0-py3-none-any.whl", hash = "sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41"}, +] +mpld3 = [ + {file = "mpld3-0.5.8-py3-none-any.whl", hash = "sha256:41938e65de4ba41a1b53d92e7c8609e7172e09b33ef5db42bb6f73701106c8b7"}, + {file = "mpld3-0.5.8.tar.gz", hash = "sha256:1a167dbef836dd7c66d8aa71c06a32d50bffa18725f304d93cb74fdb3545043b"}, +] +mpmath = [ + {file = "mpmath-1.2.1-py3-none-any.whl", hash = "sha256:604bc21bd22d2322a177c73bdb573994ef76e62edd595d17e00aff24b0667e5c"}, + {file = "mpmath-1.2.1.tar.gz", hash = "sha256:79ffb45cf9f4b101a807595bcb3e72e0396202e0b1d25d689134b48c4216a81a"}, +] +msal = [ + {file = "msal-1.20.0b1-py2.py3-none-any.whl", hash = "sha256:07805ade58ce76bdaa4f6a3f7e61477901d5145abd7959a850eb6c49a2fbaea6"}, + {file = "msal-1.20.0b1.tar.gz", hash = "sha256:8c0d7238b7bc5abe86515568c4fd59e53c5ccca159ef02b369f867b951480c4d"}, +] +msal-extensions = [ + {file = "msal-extensions-1.0.0.tar.gz", hash = "sha256:c676aba56b0cce3783de1b5c5ecfe828db998167875126ca4b47dc6436451354"}, + {file = "msal_extensions-1.0.0-py2.py3-none-any.whl", hash = "sha256:91e3db9620b822d0ed2b4d1850056a0f133cba04455e62f11612e40f5502f2ee"}, +] +msgpack = [ + {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"}, + {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"}, + {file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"}, + {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"}, + {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"}, + {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"}, + {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"}, + {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"}, + {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"}, + {file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"}, + {file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"}, + {file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"}, + {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"}, + {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"}, + {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"}, + {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"}, + {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"}, + {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"}, + {file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"}, + {file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"}, + {file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"}, + {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"}, + {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"}, + {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"}, + {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"}, + {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"}, + {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"}, + {file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"}, + {file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"}, + {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"}, + {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"}, + {file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"}, + {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"}, + {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"}, + {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"}, + {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"}, + {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"}, + {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"}, + {file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"}, + {file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"}, + {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"}, + {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"}, + {file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"}, + {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"}, + {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"}, + {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"}, + {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"}, + {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"}, + {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"}, + {file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"}, + {file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"}, + {file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"}, +] +msgpack-numpy = [ + {file = "msgpack-numpy-0.4.8.tar.gz", hash = "sha256:c667d3180513422f9c7545be5eec5d296dcbb357e06f72ed39cc683797556e69"}, + {file = "msgpack_numpy-0.4.8-py2.py3-none-any.whl", hash = "sha256:773c19d4dfbae1b3c7b791083e2caf66983bb19b40901646f61d8731554ae3da"}, +] +msgpack-python = [ + {file = "msgpack-python-0.5.6.tar.gz", hash = "sha256:378cc8a6d3545b532dfd149da715abae4fda2a3adb6d74e525d0d5e51f46909b"}, +] +msrest = [ + {file = "msrest-0.7.1-py3-none-any.whl", hash = "sha256:21120a810e1233e5e6cc7fe40b474eeb4ec6f757a15d7cf86702c369f9567c32"}, + {file = "msrest-0.7.1.zip", hash = "sha256:6e7661f46f3afd88b75667b7187a92829924446c7ea1d169be8c4bb7eeb788b9"}, +] +msrestazure = [ + {file = "msrestazure-0.6.4-py2.py3-none-any.whl", hash = "sha256:3de50f56147ef529b31e099a982496690468ecef33f0544cb0fa0cfe1e1de5b9"}, + {file = "msrestazure-0.6.4.tar.gz", hash = "sha256:a06f0dabc9a6f5efe3b6add4bd8fb623aeadacf816b7a35b0f89107e0544d189"}, +] +multidict = [ + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, + {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, + {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, + {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, + {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, + {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, + {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, + {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, + {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, + {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, + {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, +] +munch = [ + {file = "munch-2.5.0-py2.py3-none-any.whl", hash = "sha256:6f44af89a2ce4ed04ff8de41f70b226b984db10a91dcc7b9ac2efc1c77022fdd"}, + {file = "munch-2.5.0.tar.gz", hash = "sha256:2d735f6f24d4dba3417fa448cae40c6e896ec1fdab6cdb5e6510999758a4dbd2"}, +] +mypy = [ + {file = "mypy-0.961-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0"}, + {file = "mypy-0.961-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15"}, + {file = "mypy-0.961-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3"}, + {file = "mypy-0.961-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e"}, + {file = "mypy-0.961-cp310-cp310-win_amd64.whl", hash = "sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24"}, + {file = "mypy-0.961-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723"}, + {file = "mypy-0.961-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b"}, + {file = "mypy-0.961-cp36-cp36m-win_amd64.whl", hash = "sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d"}, + {file = "mypy-0.961-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813"}, + {file = "mypy-0.961-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e"}, + {file = "mypy-0.961-cp37-cp37m-win_amd64.whl", hash = "sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a"}, + {file = "mypy-0.961-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6"}, + {file = "mypy-0.961-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6"}, + {file = "mypy-0.961-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d"}, + {file = "mypy-0.961-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b"}, + {file = "mypy-0.961-cp38-cp38-win_amd64.whl", hash = "sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569"}, + {file = "mypy-0.961-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932"}, + {file = "mypy-0.961-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5"}, + {file = "mypy-0.961-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648"}, + {file = "mypy-0.961-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950"}, + {file = "mypy-0.961-cp39-cp39-win_amd64.whl", hash = "sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56"}, + {file = "mypy-0.961-py3-none-any.whl", hash = "sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66"}, + {file = "mypy-0.961.tar.gz", hash = "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +myst-parser = [ + {file = "myst-parser-0.18.1.tar.gz", hash = "sha256:79317f4bb2c13053dd6e64f9da1ba1da6cd9c40c8a430c447a7b146a594c246d"}, + {file = "myst_parser-0.18.1-py3-none-any.whl", hash = "sha256:61b275b85d9f58aa327f370913ae1bec26ebad372cc99f3ab85c8ec3ee8d9fb8"}, +] +natsort = [ + {file = "natsort-8.2.0-py3-none-any.whl", hash = "sha256:04fe18fdd2b9e5957f19f687eb117f102ef8dde6b574764e536e91194bed4f5f"}, + {file = "natsort-8.2.0.tar.gz", hash = "sha256:57f85b72c688b09e053cdac302dd5b5b53df5f73ae20b4874fcbffd8bf783d11"}, +] +nbclassic = [ + {file = "nbclassic-0.4.7-py3-none-any.whl", hash = "sha256:d71d18aa6605eaf59e9b99b34c96360af45847f2a30ee2fefbe2f7bed4bc3df2"}, + {file = "nbclassic-0.4.7.tar.gz", hash = "sha256:1e0470583b55089c427940ed31b8a866ffef7ccab101494e409efe5ac7ba9897"}, +] +nbclient = [ + {file = "nbclient-0.7.0-py3-none-any.whl", hash = "sha256:434c91385cf3e53084185334d675a0d33c615108b391e260915d1aa8e86661b8"}, + {file = "nbclient-0.7.0.tar.gz", hash = "sha256:a1d844efd6da9bc39d2209bf996dbd8e07bf0f36b796edfabaa8f8a9ab77c3aa"}, +] +nbconvert = [ + {file = "nbconvert-7.2.2-py3-none-any.whl", hash = "sha256:fc7a3787c927cbd45a52e088e934fbbaab39afe61767522168a724b7483992be"}, + {file = "nbconvert-7.2.2.tar.gz", hash = "sha256:24acfaa466d2c9b7eb524800e4a45afbed862c5d058cfb30fc7aa24d448c95eb"}, +] +nbformat = [ + {file = "nbformat-5.7.0-py3-none-any.whl", hash = "sha256:1b05ec2c552c2f1adc745f4eddce1eac8ca9ffd59bb9fd859e827eaa031319f9"}, + {file = "nbformat-5.7.0.tar.gz", hash = "sha256:1d4760c15c1a04269ef5caf375be8b98dd2f696e5eb9e603ec2bf091f9b0d3f3"}, +] +ncompress = [ + {file = "ncompress-1.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0349d7de11edd70a7efea9ce9dc67f0e47b5774832dd063f7ae68a9e3e36ea31"}, + {file = "ncompress-1.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af0011bae90e44121f4e4edbff3dccdce7e4c5fc5e354db7eb48410d71f496df"}, + {file = "ncompress-1.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6f5bf381412e9d3847b76e8b6bd1f84dfadcd3d9c25903c8592facb437909a0"}, + {file = "ncompress-1.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e0ebd71990ef7909b6627b5341a2fe1977dcce61dd3760a29e19e3f9e4c6a275"}, + {file = "ncompress-1.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8b9acc46cf36bb998ed215d6e76a94e2bd1e827b9a4cb5362982b7004b5a7620"}, + {file = "ncompress-1.0.0-cp310-cp310-win32.whl", hash = "sha256:2a104803fbe3ab0a96edb14927fa22c8142be838aabe7e938b4a52a4e82db56e"}, + {file = "ncompress-1.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a2ae8a9170fa1f45df7efa292eb8c437b18c225b63d4adca4f50f9da0e8e0c7"}, + {file = "ncompress-1.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7608fbda43d04d9f476be2dbf4ef3c96e72d83b9557a48b07fbc9ff3ad29cdd2"}, + {file = "ncompress-1.0.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8322482e72ac2802d1dca1007ec06aa281a4d5cf1cf9f8c75bb51e917382b756"}, + {file = "ncompress-1.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3590e66313041721ae81e72ece06b7048c9293321bb30900358638673608e264"}, + {file = "ncompress-1.0.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:736dbae078107742cf6ac7ccc11ae9c5eab77ef2c02aab3ef64802877bb01cab"}, + {file = "ncompress-1.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5336a8831a7e587829ce54e9e27d1fb2e04ddbc7d2d983693e35a3a03ac3ce79"}, + {file = "ncompress-1.0.0-cp36-cp36m-win32.whl", hash = "sha256:9cd040ad73a3b0e917e01cdfba507e10e0bb56849daaac3ac3d86382d4d7ad82"}, + {file = "ncompress-1.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:8eb4a55cbeaeb238a3b412952077be6b3f37b3416cd0211cc22776391ff2fef7"}, + {file = "ncompress-1.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:916671d62167191af58d6b4a17b1c09c647e349dcff1fc0b7d764aa64c3773ee"}, + {file = "ncompress-1.0.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15f10fbfa11345ff0af090e3e6ae13a1fe2b52a2bb39d4f2373c2d6aeac75e5d"}, + {file = "ncompress-1.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe0a671a2f7dc1ee0438d278ef30ab425a969536100c4352b5cb6bc0b6210818"}, + {file = "ncompress-1.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d89acf209858e7940223cf35324e1b2effec119bb009a41f039e2ea4db22177"}, + {file = "ncompress-1.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:66d991155a1655ccd98e8433c4a7e811d63eb649adb55f47d8f9528a30cc4b7a"}, + {file = "ncompress-1.0.0-cp37-cp37m-win32.whl", hash = "sha256:34c6496168fd4dbc13f1fc0c0fcbadded1957639956f8cbc6894c39999817e36"}, + {file = "ncompress-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:94b3f4e851f5b37e1d4cf2d8da911fa10783a59cba3d7f1f2ae5bd2842558077"}, + {file = "ncompress-1.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aaa18a509d9fc173b4b47d53c834e43ced1eda63d2aa7d4613dc59b2f802a31a"}, + {file = "ncompress-1.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6540556d47670a8fb93878a44d0206bbdc87f32e4c5b57d6fe63691efafbb982"}, + {file = "ncompress-1.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da7c81313aed4b6c6e8020442ed8d03d04bff72947f9380ea1ce2c63ffb8ad1"}, + {file = "ncompress-1.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d45ec59a8a3ce00613df0c81e5567854574dbbbf01ecd1a5a0929cd8fb04844d"}, + {file = "ncompress-1.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:393cc3c126b9451fb32fe2bc07773264c90e73afbd37da0df472ac23bfd1a2d5"}, + {file = "ncompress-1.0.0-cp38-cp38-win32.whl", hash = "sha256:78674f246878938387b6f82b10d1aa2192e02544d214541943d12ef1a45e66c6"}, + {file = "ncompress-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:da216a53db7cd4c0247376f87367dd71df457443567e55310f6d3d23a9aff2f2"}, + {file = "ncompress-1.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34754041d9bac2d6908ae0d07ba541e4d6d606cca222ddd53f3a57e15f386b0a"}, + {file = "ncompress-1.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab9fc62baaa55faf8ed8ac67f2c64a7295fec91d7c1f306ac46aa894ca4edf91"}, + {file = "ncompress-1.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070044eab19586a45d1855c3e50e000ce86d6075b122a5ec8cffd480713dffac"}, + {file = "ncompress-1.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f9ba6ab2aadd6fd90365fdad5219e4dc7bc2459b94f1e900a733dddaf4e9b2e6"}, + {file = "ncompress-1.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b031e06b42037b181e3514261e1e85a9eae4af990c12b9348a9f22b8042201ff"}, + {file = "ncompress-1.0.0-cp39-cp39-win32.whl", hash = "sha256:13fa26ec8000d786a8079bb265508b5df4b445a4f460481a13549b4bd3c83824"}, + {file = "ncompress-1.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:d11df815d280985dfa660974df11dbe051a1a18dca2f91f9d30fbd6548237b8f"}, + {file = "ncompress-1.0.0.tar.gz", hash = "sha256:e7bbf10cca1376f4f17ae2c447e33a9d4067525abb0c71d488c9a5ced50552f1"}, +] +nest-asyncio = [ + {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, + {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, +] +networkx = [ + {file = "networkx-2.3.zip", hash = "sha256:8311ddef63cf5c5c5e7c1d0212dd141d9a1fe3f474915281b73597ed5f1d4e3d"}, +] +nodeenv = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] +nose = [ + {file = "nose-1.3.7-py2-none-any.whl", hash = "sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a"}, + {file = "nose-1.3.7-py3-none-any.whl", hash = "sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac"}, + {file = "nose-1.3.7.tar.gz", hash = "sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"}, +] +notebook = [ + {file = "notebook-6.4.12-py3-none-any.whl", hash = "sha256:8c07a3bb7640e371f8a609bdbb2366a1976c6a2589da8ef917f761a61e3ad8b1"}, + {file = "notebook-6.4.12.tar.gz", hash = "sha256:6268c9ec9048cff7a45405c990c29ac9ca40b0bc3ec29263d218c5e01f2b4e86"}, +] +notebook-shim = [ + {file = "notebook_shim-0.2.0-py3-none-any.whl", hash = "sha256:481711abddfb2e5305b83cf0efe18475824eb47d1ba9f87f66a8c574b8b5c9e4"}, + {file = "notebook_shim-0.2.0.tar.gz", hash = "sha256:fdb81febb05932c6d19e44e10382ce05469cac5e1b6e99b49be6159ddb5e4804"}, +] +numpy = [ + {file = "numpy-1.23.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:95d79ada05005f6f4f337d3bb9de8a7774f259341c70bc88047a1f7b96a4bcb2"}, + {file = "numpy-1.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:926db372bc4ac1edf81cfb6c59e2a881606b409ddc0d0920b988174b2e2a767f"}, + {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c237129f0e732885c9a6076a537e974160482eab8f10db6292e92154d4c67d71"}, + {file = "numpy-1.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8365b942f9c1a7d0f0dc974747d99dd0a0cdfc5949a33119caf05cb314682d3"}, + {file = "numpy-1.23.4-cp310-cp310-win32.whl", hash = "sha256:2341f4ab6dba0834b685cce16dad5f9b6606ea8a00e6da154f5dbded70fdc4dd"}, + {file = "numpy-1.23.4-cp310-cp310-win_amd64.whl", hash = "sha256:d331afac87c92373826af83d2b2b435f57b17a5c74e6268b79355b970626e329"}, + {file = "numpy-1.23.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:488a66cb667359534bc70028d653ba1cf307bae88eab5929cd707c761ff037db"}, + {file = "numpy-1.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce03305dd694c4873b9429274fd41fc7eb4e0e4dea07e0af97a933b079a5814f"}, + {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8981d9b5619569899666170c7c9748920f4a5005bf79c72c07d08c8a035757b0"}, + {file = "numpy-1.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a70a7d3ce4c0e9284e92285cba91a4a3f5214d87ee0e95928f3614a256a1488"}, + {file = "numpy-1.23.4-cp311-cp311-win32.whl", hash = "sha256:5e13030f8793e9ee42f9c7d5777465a560eb78fa7e11b1c053427f2ccab90c79"}, + {file = "numpy-1.23.4-cp311-cp311-win_amd64.whl", hash = "sha256:7607b598217745cc40f751da38ffd03512d33ec06f3523fb0b5f82e09f6f676d"}, + {file = "numpy-1.23.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7ab46e4e7ec63c8a5e6dbf5c1b9e1c92ba23a7ebecc86c336cb7bf3bd2fb10e5"}, + {file = "numpy-1.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8aae2fb3180940011b4862b2dd3756616841c53db9734b27bb93813cd79fce6"}, + {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c053d7557a8f022ec823196d242464b6955a7e7e5015b719e76003f63f82d0f"}, + {file = "numpy-1.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0882323e0ca4245eb0a3d0a74f88ce581cc33aedcfa396e415e5bba7bf05f68"}, + {file = "numpy-1.23.4-cp38-cp38-win32.whl", hash = "sha256:dada341ebb79619fe00a291185bba370c9803b1e1d7051610e01ed809ef3a4ba"}, + {file = "numpy-1.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:0fe563fc8ed9dc4474cbf70742673fc4391d70f4363f917599a7fa99f042d5a8"}, + {file = "numpy-1.23.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c67b833dbccefe97cdd3f52798d430b9d3430396af7cdb2a0c32954c3ef73894"}, + {file = "numpy-1.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f76025acc8e2114bb664294a07ede0727aa75d63a06d2fae96bf29a81747e4a7"}, + {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12ac457b63ec8ded85d85c1e17d85efd3c2b0967ca39560b307a35a6703a4735"}, + {file = "numpy-1.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95de7dc7dc47a312f6feddd3da2500826defdccbc41608d0031276a24181a2c0"}, + {file = "numpy-1.23.4-cp39-cp39-win32.whl", hash = "sha256:f2f390aa4da44454db40a1f0201401f9036e8d578a25f01a6e237cea238337ef"}, + {file = "numpy-1.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:f260da502d7441a45695199b4e7fd8ca87db659ba1c78f2bbf31f934fe76ae0e"}, + {file = "numpy-1.23.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61be02e3bf810b60ab74e81d6d0d36246dbfb644a462458bb53b595791251911"}, + {file = "numpy-1.23.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:296d17aed51161dbad3c67ed6d164e51fcd18dbcd5dd4f9d0a9c6055dce30810"}, + {file = "numpy-1.23.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4d52914c88b4930dafb6c48ba5115a96cbab40f45740239d9f4159c4ba779962"}, + {file = "numpy-1.23.4.tar.gz", hash = "sha256:ed2cc92af0efad20198638c69bb0fc2870a58dabfba6eb722c933b48556c686c"}, +] +nvidia-ml-py3 = [ + {file = "nvidia-ml-py3-7.352.0.tar.gz", hash = "sha256:390f02919ee9d73fe63a98c73101061a6b37fa694a793abf56673320f1f51277"}, +] +oauthlib = [ + {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, + {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, +] +onnx = [ + {file = "onnx-1.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bdbd2578424c70836f4d0f9dda16c21868ddb07cc8192f9e8a176908b43d694b"}, + {file = "onnx-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213e73610173f6b2e99f99a4b0636f80b379c417312079d603806e48ada4ca8b"}, + {file = "onnx-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fd2f4e23078df197bb76a59b9cd8f5a43a6ad2edc035edb3ecfb9042093e05a"}, + {file = "onnx-1.12.0-cp310-cp310-win32.whl", hash = "sha256:23781594bb8b7ee985de1005b3c601648d5b0568a81e01365c48f91d1f5648e4"}, + {file = "onnx-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:81a3555fd67be2518bf86096299b48fb9154652596219890abfe90bd43a9ec13"}, + {file = "onnx-1.12.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:5578b93dc6c918cec4dee7fb7d9dd3b09d338301ee64ca8b4f28bc217ed42dca"}, + {file = "onnx-1.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c11162ffc487167da140f1112f49c4f82d815824f06e58bc3095407699f05863"}, + {file = "onnx-1.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341c7016e23273e9ffa9b6e301eee95b8c37d0f04df7cedbdb169d2c39524c96"}, + {file = "onnx-1.12.0-cp37-cp37m-win32.whl", hash = "sha256:3c6e6bcffc3f5c1e148df3837dc667fa4c51999788c1b76b0b8fbba607e02da8"}, + {file = "onnx-1.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8a7aa61aea339bd28f310f4af4f52ce6c4b876386228760b16308efd58f95059"}, + {file = "onnx-1.12.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:56ceb7e094c43882b723cfaa107d85ad673cfdf91faeb28d7dcadacca4f43a07"}, + {file = "onnx-1.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3629e8258db15d4e2c9b7f1be91a3186719dd94661c218c6f5fde3cc7de3d4d"}, + {file = "onnx-1.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d9a7db54e75529160337232282a4816cc50667dc7dc34be178fd6f6b79d4705"}, + {file = "onnx-1.12.0-cp38-cp38-win32.whl", hash = "sha256:fea5156a03398fe0e23248042d8651c1eaac5f6637d4dd683b4c1f1320b9f7b4"}, + {file = "onnx-1.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:f66d2996e65f490a57b3ae952e4e9189b53cc9fe3f75e601d50d4db2dc1b1cd9"}, + {file = "onnx-1.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c39a7a0352c856f1df30dccf527eb6cb4909052e5eaf6fa2772a637324c526aa"}, + {file = "onnx-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab13feb4d94342aae6d357d480f2e47d41b9f4e584367542b21ca6defda9e0a"}, + {file = "onnx-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7a9b3ea02c30efc1d2662337e280266aca491a8e86be0d8a657f874b7cccd1e"}, + {file = "onnx-1.12.0-cp39-cp39-win32.whl", hash = "sha256:f8800f28c746ab06e51ef8449fd1215621f4ddba91be3ffc264658937d38a2af"}, + {file = "onnx-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:af90427ca04c6b7b8107c2021e1273227a3ef1a7a01f3073039cae7855a59833"}, + {file = "onnx-1.12.0.tar.gz", hash = "sha256:13b3e77d27523b9dbf4f30dfc9c959455859d5e34e921c44f712d69b8369eff9"}, +] +onnxoptimizer = [ + {file = "onnxoptimizer-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1aba09d802146bd0e08d9feb83b1e47edc52aa560e48e87451554d436ff07c99"}, + {file = "onnxoptimizer-0.2.7-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:cba1ee65fe5e5752b887138ad805dc5b3845f09921b962a62b4dc9083b486f73"}, + {file = "onnxoptimizer-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f161979d34d9db636c623d0681c73de0cbe349805929cf966f7e657457a20d82"}, + {file = "onnxoptimizer-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:884ac67280d3a4929c7154660105e6ca034d5a222c989864899056225a0aaa61"}, + {file = "onnxoptimizer-0.2.7-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f67e5119419da0f85251d607097fbf486354cc65871caf859acb572526e5d4b0"}, + {file = "onnxoptimizer-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:0b604e402564ae1231e43edbd0ce766256fcd301f63b00ce8abe4e4f5dd23265"}, + {file = "onnxoptimizer-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7cfa72afc54735cf9a66ae7eaca40b6cddf9590e0c63c4f8761e03674b24a53"}, + {file = "onnxoptimizer-0.2.7-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:07b028534dd592eb6d6cc5f95fb0b4cb6d9470ce8846c81d0fb24047af70397d"}, + {file = "onnxoptimizer-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:42247221a35a8cf4cfa9f8f657b0cb234248c4d6ebe54ba03723468449de61c2"}, + {file = "onnxoptimizer-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c139cd3bebc3f3ea7d1386282a4168bd02bf4d15c261d50896ef517858aa8b8d"}, + {file = "onnxoptimizer-0.2.7-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e278c11eae62a631c342d3618bf315017f6fc54b2e3fbe7840b0a1700e722da4"}, + {file = "onnxoptimizer-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:86bdb883f33078d3ed89f2ff452e9b0b37624e332dc7d7aa49a23f0ce11c2478"}, + {file = "onnxoptimizer-0.2.7.tar.gz", hash = "sha256:a9f972b2b68ceb82b1f268042879f807fceb9ad76e38def2a39f102e62216d21"}, +] +onnxruntime-gpu = [ + {file = "onnxruntime_gpu-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42b0393c5122ed90fa2eb76192a486261d86e9526ccb78b2a98923c22791d2d1"}, + {file = "onnxruntime_gpu-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:ecfe97335027e569d4f46725ba89316041e562b8c499690e25e11cfee4601cd1"}, + {file = "onnxruntime_gpu-1.12.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2be6f7f5a1ce0bc8471ce42e10eab92cfb19d0748b857edcb5320b5e98311b7"}, + {file = "onnxruntime_gpu-1.12.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d73204323aefebe4eecab9fcf76e22b1a00394e3d838c2962a28a27301186b73"}, + {file = "onnxruntime_gpu-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37872527d03d3df10756408ca44014bd6ac354a044ab1c4286cd42dc138e518"}, + {file = "onnxruntime_gpu-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:296bd9733986cb7517d15bef5535c555d3f863963a71e6575e92d2a854aee61d"}, + {file = "onnxruntime_gpu-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e46d0724ce54c5908c5760037b78de741fbd48962b370c29ebc20e608b30eda"}, + {file = "onnxruntime_gpu-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:fd919373be35b9ba54210688265df38ad5e19a530449385c40dab51da407345d"}, +] +opencv-python-headless = [] +osmium = [ + {file = "osmium-3.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7bf648744dadd3396040ed57332780272356fb4b87dbd17521ba9b8b91c6e665"}, + {file = "osmium-3.4.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a8ee676ed0a0dbd359197ffb42518889af700da29629ac13834c1149a4b83ce6"}, + {file = "osmium-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:080345e4be12474da9b1d4f45fbf8214ab316826029f821f8043f1b36e749cc3"}, + {file = "osmium-3.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:58b61b72911b7bb87f617ae12872d7c11d360f08fb50927eb769a91be3434d7c"}, + {file = "osmium-3.4.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bfee94a25e419923bcb885bf624024a1610f0e1c26ceb1a7c65426420d549c0e"}, + {file = "osmium-3.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:2ac803d2d1b0097768a8bf0c174349d686d5dc2ec832ec84cadb20937a415d10"}, + {file = "osmium-3.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:daa478c951ade8b49348096f5e330bbe39cd2b5057127666a9102094cf7f31fb"}, + {file = "osmium-3.4.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5453ed8c8c69ab3ed2c17ae1fd3567b9b54036916f0ffe77235fe363e7029b01"}, + {file = "osmium-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f9776510dbaac32ded5d3bbe31bacdeeefefc79ce8ea54c743e9eb2ce4ace007"}, + {file = "osmium-3.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d49e56225f4e31867e2bbdef000ae3fb9b18ca6697e44c3315d64b46d53fc77e"}, + {file = "osmium-3.4.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:76e8461ae68c5307f44eb407424b7dcfc7d0d8bb5b52283088d8f549c0d715ba"}, + {file = "osmium-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f4710b8350d93edc194a466ab4cb42efcc58961be46901cced359f74bed27e5"}, + {file = "osmium-3.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a777eaa408a49f8c2f0f0358a09307c9fa69d4809ae3632f3e40c61bdbf11d17"}, + {file = "osmium-3.4.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50a9c94c4856d81c11e68ff327b81d759311974d7fb67618cec3b15e32b7f4c1"}, + {file = "osmium-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e45b7c54ac756e9cb40e2ba68691df635804eb6aa2023088af66936a9c8e3782"}, + {file = "osmium-3.4.1.tar.gz", hash = "sha256:575dad72ab169cf585b9aeefb4f5f99ac250bf7da1986992afcbf169dc70c381"}, +] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] +pandas = [ + {file = "pandas-1.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0a78e05ec09731c5b3bd7a9805927ea631fe6f6cb06f0e7c63191a9a778d52b4"}, + {file = "pandas-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5b0c970e2215572197b42f1cff58a908d734503ea54b326412c70d4692256391"}, + {file = "pandas-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f340331a3f411910adfb4bbe46c2ed5872d9e473a783d7f14ecf49bc0869c594"}, + {file = "pandas-1.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c709f4700573deb2036d240d140934df7e852520f4a584b2a8d5443b71f54d"}, + {file = "pandas-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32e3d9f65606b3f6e76555bfd1d0b68d94aff0929d82010b791b6254bf5a4b96"}, + {file = "pandas-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a52419d9ba5906db516109660b114faf791136c94c1a636ed6b29cbfff9187ee"}, + {file = "pandas-1.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:66a1ad667b56e679e06ba73bb88c7309b3f48a4c279bd3afea29f65a766e9036"}, + {file = "pandas-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:36aa1f8f680d7584e9b572c3203b20d22d697c31b71189322f16811d4ecfecd3"}, + {file = "pandas-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bcf1a82b770b8f8c1e495b19a20d8296f875a796c4fe6e91da5ef107f18c5ecb"}, + {file = "pandas-1.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c25e5c16ee5c0feb6cf9d982b869eec94a22ddfda9aa2fbed00842cbb697624"}, + {file = "pandas-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:932d2d7d3cab44cfa275601c982f30c2d874722ef6396bb539e41e4dc4618ed4"}, + {file = "pandas-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:eb7e8cf2cf11a2580088009b43de84cabbf6f5dae94ceb489f28dba01a17cb77"}, + {file = "pandas-1.5.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cb2a9cf1150302d69bb99861c5cddc9c25aceacb0a4ef5299785d0f5389a3209"}, + {file = "pandas-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81f0674fa50b38b6793cd84fae5d67f58f74c2d974d2cb4e476d26eee33343d0"}, + {file = "pandas-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:17da7035d9e6f9ea9cdc3a513161f8739b8f8489d31dc932bc5a29a27243f93d"}, + {file = "pandas-1.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:669c8605dba6c798c1863157aefde959c1796671ffb342b80fcb80a4c0bc4c26"}, + {file = "pandas-1.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:683779e5728ac9138406c59a11e09cd98c7d2c12f0a5fc2b9c5eecdbb4a00075"}, + {file = "pandas-1.5.1-cp38-cp38-win32.whl", hash = "sha256:ddf46b940ef815af4e542697eaf071f0531449407a7607dd731bf23d156e20a7"}, + {file = "pandas-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:db45b94885000981522fb92349e6b76f5aee0924cc5315881239c7859883117d"}, + {file = "pandas-1.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:927e59c694e039c75d7023465d311277a1fc29ed7236b5746e9dddf180393113"}, + {file = "pandas-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e675f8fe9aa6c418dc8d3aac0087b5294c1a4527f1eacf9fe5ea671685285454"}, + {file = "pandas-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04e51b01d5192499390c0015630975f57836cc95c7411415b499b599b05c0c96"}, + {file = "pandas-1.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cee0c74e93ed4f9d39007e439debcaadc519d7ea5c0afc3d590a3a7b2edf060"}, + {file = "pandas-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b156a971bc451c68c9e1f97567c94fd44155f073e3bceb1b0d195fd98ed12048"}, + {file = "pandas-1.5.1-cp39-cp39-win32.whl", hash = "sha256:05c527c64ee02a47a24031c880ee0ded05af0623163494173204c5b72ddce658"}, + {file = "pandas-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:6bb391659a747cf4f181a227c3e64b6d197100d53da98dcd766cc158bdd9ec68"}, + {file = "pandas-1.5.1.tar.gz", hash = "sha256:249cec5f2a5b22096440bd85c33106b6102e0672204abd2d5c014106459804ee"}, +] +pandocfilters = [ + {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, + {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, +] +parameterized = [ + {file = "parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9"}, + {file = "parameterized-0.8.1.tar.gz", hash = "sha256:41bbff37d6186430f77f900d777e5bb6a24928a1c46fb1de692f8b52b8833b5c"}, +] +paramiko = [ + {file = "paramiko-2.11.0-py2.py3-none-any.whl", hash = "sha256:655f25dc8baf763277b933dfcea101d636581df8d6b9774d1fb653426b72c270"}, + {file = "paramiko-2.11.0.tar.gz", hash = "sha256:003e6bee7c034c21fbb051bf83dc0a9ee4106204dd3c53054c71452cc4ec3938"}, +] +parso = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] +pexpect = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] +pickleshare = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] +pillow = [ + {file = "Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb"}, + {file = "Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f"}, + {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5"}, + {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c"}, + {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1"}, + {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58"}, + {file = "Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544"}, + {file = "Pillow-9.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e"}, + {file = "Pillow-9.2.0-cp310-cp310-win32.whl", hash = "sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28"}, + {file = "Pillow-9.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d"}, + {file = "Pillow-9.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc"}, + {file = "Pillow-9.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437"}, + {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004"}, + {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0"}, + {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4"}, + {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c"}, + {file = "Pillow-9.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a"}, + {file = "Pillow-9.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1"}, + {file = "Pillow-9.2.0-cp311-cp311-win32.whl", hash = "sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf"}, + {file = "Pillow-9.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c"}, + {file = "Pillow-9.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069"}, + {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f"}, + {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8"}, + {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b"}, + {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467"}, + {file = "Pillow-9.2.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59"}, + {file = "Pillow-9.2.0-cp37-cp37m-win32.whl", hash = "sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc"}, + {file = "Pillow-9.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d"}, + {file = "Pillow-9.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14"}, + {file = "Pillow-9.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3"}, + {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402"}, + {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f"}, + {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8"}, + {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff"}, + {file = "Pillow-9.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1"}, + {file = "Pillow-9.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76"}, + {file = "Pillow-9.2.0-cp38-cp38-win32.whl", hash = "sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f"}, + {file = "Pillow-9.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8"}, + {file = "Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc"}, + {file = "Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da"}, + {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4"}, + {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c"}, + {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421"}, + {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20"}, + {file = "Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60"}, + {file = "Pillow-9.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4"}, + {file = "Pillow-9.2.0-cp39-cp39-win32.whl", hash = "sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885"}, + {file = "Pillow-9.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"}, + {file = "Pillow-9.2.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3"}, + {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb"}, + {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be"}, + {file = "Pillow-9.2.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd"}, + {file = "Pillow-9.2.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013"}, + {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490"}, + {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac"}, + {file = "Pillow-9.2.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e"}, + {file = "Pillow-9.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927"}, + {file = "Pillow-9.2.0.tar.gz", hash = "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04"}, +] +pillow-avif-plugin = [ + {file = "pillow-avif-plugin-1.2.2.tar.gz", hash = "sha256:38033ef060b96b2615f5c9e8fa87d4928a4254f0f43081abd89c9017f82c589a"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:fc542b03ea87f0e832904fe1ff61cb586bafcd5f80e352ae7ca5cac008e9d651"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27m-macosx_11_0_arm64.whl", hash = "sha256:c77ed103dc587894e7d707cd4ffc0f5b1c641d09b1fb84245475f02c1db039c9"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27m-win_amd64.whl", hash = "sha256:5c0b979acd9a58a5d5f662eb167d65c8e103af0198fcaa200661abf9733dbf9b"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6dade8e87909766a655a88df0a3c0078c9020315e2fefab8cf3496d9940fd0f8"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:54b1a27610cbf754e332b0f3e7be188cceedcfcdcb4cff92d272aff04082eb1d"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:887665e08bee4ded0512fe991bbbe7403c90aa9646be8d27295271dcdc10581e"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:feba13f19bd9381e079e72f088a66a6509caefb52304888751d637c23b1faa00"}, + {file = "pillow_avif_plugin-1.2.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7238447e395ccee68052c06c0fb824696f5cd1f3050f50466f1889d8356a28f7"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:703f4e15dcfc9335f69ebd09cecb576f3db0c3586af6bd43d0971a591183b0de"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c4665a8d3aa5fb60ed2976eb52ae886f6a276c7ddf346c118b16dc6f1ceec7c"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:593006af5569df6f3aefba184a90a5112798859ec8c745bcb495ab8b84d194bc"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e2fa7245f7544f4ae03ab4efc035a398883b404488806094e661b3438d921b88"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017e5e52cb4320414e8ce3e2089eae2cb87c22c73ff6012b17ae326fc5753b20"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a57136d4866de5dc80cfb24d66655955fbdd87acf1d11d88c8dc2ab41023e46"}, + {file = "pillow_avif_plugin-1.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:f339511d0fccb69e3a5e3af39f8fe6700b0a07279015006ea56f8f49e7fecff4"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05e821ecd90bb0b8d2dc7610625372cc47de9cb893d09662528bad572f669d1c"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33886a5f9796fe9a8a3bc25ccfdeba7db119adb50b7004f1928a14b07d0213a"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75b7ed186c2f740dd26e556f6a966c59a170b70263e429a2c81920fe444da8a7"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11aef6b79078b8dad25c928e5871c146ab94424472851d5bf539ba62abde9ac"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10696c536d68a14cefea3b98edb8d5a7ae29e8e07458f1d59c5d1cd780a8bf2a"}, + {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1a7291d6a5fb7336e72685a31d193e0b3a6bee9986c9ac4d8bd4b68dbe6d4f7f"}, + {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:14b9c5dbf237e7dc12f69819ea181a457b3bd4f59f8cd71d028d3635fd3bcab4"}, + {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:799cbfbeee831332d280c80df9ce16b5c3b1224c318264e97e89df8da32e870e"}, + {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8f64153b2bb8007d00a3ccb32bb374dda185bf1b4a145c2e971fc67b68d015c"}, + {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b7937a20042fdd4272cdb3f2942d0290a045e6016335eeb79685ee24e8aa652"}, + {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:e5aa90fee46584d5958832a47e19fb7c18de059cacdac33494a55b9a064a56dc"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:1124f4a5e2312663cdb96879dd01a200475bd86626bf4905fca33c6d438e479b"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:a1d2a17a6b133793ad733b33712cdc0bba13acc6fe83d259ef3c735e172550a4"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:eb2f34c093b93dbc05b28fc34715b411ee0a5f30788137b27eb89864375134c8"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bef5d0f2b198aca6a13ebd77006ecb25e08d2c09deb25dc89ec72d2460da8e67"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8ec81be95e14de6e8052cceae593d4ff43ba22938186b44c68964715a85c1f9"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:39cbf7b21392778f1bd3988c97429ff7b86a9a972f033c9c3674544114e612ab"}, + {file = "pillow_avif_plugin-1.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c9099647c81ec26b2f92dde414876f000f74588f15f5e60228dbf0494891d817"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:050599ad735e6a3d6c565bc563ced74872acd3e8bd3e7ac9f014dc2e82249611"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3adf80a6ee5e895b75bcd3743f81b3ed96cd0c418326f499312b1bde87b41f1"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:251f1fc60caedd2c641c9f28c4f5a74610aa6c1d1b54e681ce63d508a8e30c53"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3216e9f28514947fcdecd41782ccb5bb3a73360d758b1a2ff7fbf3831e0f5bf7"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a229d44f8446d6e2515e965d6d066cfd9308d50c6ada22ecb2f13a9b0c492e86"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:529eb2d9e3827acf874c6ddedc28729bfb709c115cc972c77464cc7bacdf2b38"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9d3ee3b5b66d58c33bc723074e2db7e1256d341ba90edfd2c9ea19c7964836da"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a34a928ed23508a694b34a14252e178b82db577285d43a1eaf143a6a8a6ddd63"}, + {file = "pillow_avif_plugin-1.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:d40bf89d78da035dea9d5167335f73e71b696509e14513d875ac2605b91ae269"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:ad8958a5ea5e3f6ae2a4ded374fb7b84b3af2176e295ca6c3d1d0b6e9866933e"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab19285161028059dfc6362b7aba6a02ff5371d22492d8a71eade7d7e5ca6f59"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8f70d2787bf9bed4588fedd9e1f149eb7c2a9990df3ee123eb18d86882ca0b8a"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220fc8e8b9e1e3e98cd7f6dcc116cff8ca453b249dba62264ab0dc2a92fc4e1b"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0514b09d518a699525061160093da58eb3a04649daf98d8e9ee52d739de5be6e"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a6314e0144a2b08e39b6842fa5b981383d7932f6e8363b6bbb291a9efc23deb1"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3bf72f8df4b08b63b183c6368e3bd0cd098bfacc494803383589655607bc1f76"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0d54543ed9fbb6c18b61c93a2296e2a9bfc85ef559cb6a50b92fe80cc4711db5"}, + {file = "pillow_avif_plugin-1.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:86c62edb830a83a97c2a2f9a262968f12ce32adbf1069fd5fae47a0fae706e16"}, +] +pipenv = [ + {file = "pipenv-2022.10.12-py2.py3-none-any.whl", hash = "sha256:f43972a42411107ade86b6f17dd698dfcd843bd84eb7264163ebb363f6b0ede4"}, + {file = "pipenv-2022.10.12.tar.gz", hash = "sha256:a4d88f6667cbcd9ea432d626a8b373cd3101886b9fb964ea7e7f9650a83fc307"}, +] +pkginfo = [ + {file = "pkginfo-1.8.3-py2.py3-none-any.whl", hash = "sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594"}, + {file = "pkginfo-1.8.3.tar.gz", hash = "sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c"}, +] +pkgutil-resolve-name = [ + {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, + {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, +] +platformdirs = [ + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, +] +plotly = [ + {file = "plotly-5.10.0-py2.py3-none-any.whl", hash = "sha256:989b13825cc974390aa0169479485d9257d37848a47bc63957251f8e1a7046ba"}, + {file = "plotly-5.10.0.tar.gz", hash = "sha256:4d36d9859b7a153b273562deeed8c292587a472eb1fd57cd4158ec89d9defadb"}, +] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +poetry = [ + {file = "poetry-1.2.2-py3-none-any.whl", hash = "sha256:93ea3c4a622485c2a7b7249f1e34e4ac84f8229ded76153b67506313201b154f"}, + {file = "poetry-1.2.2.tar.gz", hash = "sha256:6d9ed0b1b826a0a79190f2078d7d78483fa24bf2494f3b170e354eaa5e7b5ea1"}, +] +poetry-core = [ + {file = "poetry-core-1.3.2.tar.gz", hash = "sha256:0ab006a40cb38d6a38b97264f6835da2f08a96912f2728ce668e9ac6a34f686f"}, + {file = "poetry_core-1.3.2-py3-none-any.whl", hash = "sha256:ea0f5a90b339cde132b4e43cff78a1b440cd928db864bb67cfc97fdfcefe7218"}, +] +poetry-plugin-export = [ + {file = "poetry-plugin-export-1.1.2.tar.gz", hash = "sha256:5e92525dd63f38ce74a51ed68ea91d753523f21ce5f9ef8d3b793e2a4b2222ef"}, + {file = "poetry_plugin_export-1.1.2-py3-none-any.whl", hash = "sha256:946e3313b3d00c18fb9a50522e9d5e6a7e111beaba8d6ae33297662fc2070ac1"}, +] +portalocker = [ + {file = "portalocker-2.6.0-py2.py3-none-any.whl", hash = "sha256:102ed1f2badd8dec9af3d732ef70e94b215b85ba45a8d7ff3c0003f19b442f4e"}, + {file = "portalocker-2.6.0.tar.gz", hash = "sha256:964f6830fb42a74b5d32bce99ed37d8308c1d7d44ddf18f3dd89f4680de97b39"}, +] +pprofile = [ + {file = "pprofile-2.1.0.tar.gz", hash = "sha256:b2bb56603dadf40c0bc0f61621f22c20e41638425f729945d9b7f8e4ae8cdd4a"}, +] +pre-commit = [ + {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, + {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, +] +pretrainedmodels = [ + {file = "pretrainedmodels-0.7.4.tar.gz", hash = "sha256:7e77ead4619a3e11ab3c41982c8ad5b86edffe37c87fd2a37ec3c2cc6470b98a"}, +] +prometheus-client = [ + {file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"}, + {file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"}, +] +prompt-toolkit = [ + {file = "prompt_toolkit-3.0.31-py3-none-any.whl", hash = "sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d"}, + {file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"}, +] +protobuf = [ + {file = "protobuf-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996"}, + {file = "protobuf-3.20.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3"}, + {file = "protobuf-3.20.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde"}, + {file = "protobuf-3.20.1-cp310-cp310-win32.whl", hash = "sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c"}, + {file = "protobuf-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7"}, + {file = "protobuf-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153"}, + {file = "protobuf-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f"}, + {file = "protobuf-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20"}, + {file = "protobuf-3.20.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531"}, + {file = "protobuf-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e"}, + {file = "protobuf-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c"}, + {file = "protobuf-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067"}, + {file = "protobuf-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf"}, + {file = "protobuf-3.20.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab"}, + {file = "protobuf-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c"}, + {file = "protobuf-3.20.1-cp38-cp38-win32.whl", hash = "sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7"}, + {file = "protobuf-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739"}, + {file = "protobuf-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7"}, + {file = "protobuf-3.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f"}, + {file = "protobuf-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9"}, + {file = "protobuf-3.20.1-cp39-cp39-win32.whl", hash = "sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8"}, + {file = "protobuf-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91"}, + {file = "protobuf-3.20.1-py2.py3-none-any.whl", hash = "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388"}, + {file = "protobuf-3.20.1.tar.gz", hash = "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9"}, +] +psutil = [ + {file = "psutil-5.9.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b4a247cd3feaae39bb6085fcebf35b3b8ecd9b022db796d89c8f05067ca28e71"}, + {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5fa88e3d5d0b480602553d362c4b33a63e0c40bfea7312a7bf78799e01e0810b"}, + {file = "psutil-5.9.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:767ef4fa33acda16703725c0473a91e1832d296c37c63896c7153ba81698f1ab"}, + {file = "psutil-5.9.3-cp27-cp27m-win32.whl", hash = "sha256:9a4af6ed1094f867834f5f07acd1250605a0874169a5fcadbcec864aec2496a6"}, + {file = "psutil-5.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:fa5e32c7d9b60b2528108ade2929b115167fe98d59f89555574715054f50fa31"}, + {file = "psutil-5.9.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:fe79b4ad4836e3da6c4650cb85a663b3a51aef22e1a829c384e18fae87e5e727"}, + {file = "psutil-5.9.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:db8e62016add2235cc87fb7ea000ede9e4ca0aa1f221b40cef049d02d5d2593d"}, + {file = "psutil-5.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:941a6c2c591da455d760121b44097781bc970be40e0e43081b9139da485ad5b7"}, + {file = "psutil-5.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:71b1206e7909792d16933a0d2c1c7f04ae196186c51ba8567abae1d041f06dcb"}, + {file = "psutil-5.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f57d63a2b5beaf797b87024d018772439f9d3103a395627b77d17a8d72009543"}, + {file = "psutil-5.9.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7507f6c7b0262d3e7b0eeda15045bf5881f4ada70473b87bc7b7c93b992a7d7"}, + {file = "psutil-5.9.3-cp310-cp310-win32.whl", hash = "sha256:1b540599481c73408f6b392cdffef5b01e8ff7a2ac8caae0a91b8222e88e8f1e"}, + {file = "psutil-5.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:547ebb02031fdada635452250ff39942db8310b5c4a8102dfe9384ee5791e650"}, + {file = "psutil-5.9.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d8c3cc6bb76492133474e130a12351a325336c01c96a24aae731abf5a47fe088"}, + {file = "psutil-5.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07d880053c6461c9b89cd5d4808f3b8336665fa3acdefd6777662c5ed73a851a"}, + {file = "psutil-5.9.3-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e8b50241dd3c2ed498507f87a6602825073c07f3b7e9560c58411c14fe1e1c9"}, + {file = "psutil-5.9.3-cp36-cp36m-win32.whl", hash = "sha256:828c9dc9478b34ab96be75c81942d8df0c2bb49edbb481f597314d92b6441d89"}, + {file = "psutil-5.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:ed15edb14f52925869250b1375f0ff58ca5c4fa8adefe4883cfb0737d32f5c02"}, + {file = "psutil-5.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d266cd05bd4a95ca1c2b9b5aac50d249cf7c94a542f47e0b22928ddf8b80d1ef"}, + {file = "psutil-5.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e4939ff75149b67aef77980409f156f0082fa36accc475d45c705bb00c6c16a"}, + {file = "psutil-5.9.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68fa227c32240c52982cb931801c5707a7f96dd8927f9102d6c7771ea1ff5698"}, + {file = "psutil-5.9.3-cp37-cp37m-win32.whl", hash = "sha256:beb57d8a1ca0ae0eb3d08ccaceb77e1a6d93606f0e1754f0d60a6ebd5c288837"}, + {file = "psutil-5.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:12500d761ac091f2426567f19f95fd3f15a197d96befb44a5c1e3cbe6db5752c"}, + {file = "psutil-5.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba38cf9984d5462b506e239cf4bc24e84ead4b1d71a3be35e66dad0d13ded7c1"}, + {file = "psutil-5.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46907fa62acaac364fff0b8a9da7b360265d217e4fdeaca0a2397a6883dffba2"}, + {file = "psutil-5.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a04a1836894c8279e5e0a0127c0db8e198ca133d28be8a2a72b4db16f6cf99c1"}, + {file = "psutil-5.9.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a4e07611997acf178ad13b842377e3d8e9d0a5bac43ece9bfc22a96735d9a4f"}, + {file = "psutil-5.9.3-cp38-cp38-win32.whl", hash = "sha256:6ced1ad823ecfa7d3ce26fe8aa4996e2e53fb49b7fed8ad81c80958501ec0619"}, + {file = "psutil-5.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35feafe232d1aaf35d51bd42790cbccb882456f9f18cdc411532902370d660df"}, + {file = "psutil-5.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:538fcf6ae856b5e12d13d7da25ad67f02113c96f5989e6ad44422cb5994ca7fc"}, + {file = "psutil-5.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a3d81165b8474087bb90ec4f333a638ccfd1d69d34a9b4a1a7eaac06648f9fbe"}, + {file = "psutil-5.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a7826e68b0cf4ce2c1ee385d64eab7d70e3133171376cac53d7c1790357ec8f"}, + {file = "psutil-5.9.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ec296f565191f89c48f33d9544d8d82b0d2af7dd7d2d4e6319f27a818f8d1cc"}, + {file = "psutil-5.9.3-cp39-cp39-win32.whl", hash = "sha256:9ec95df684583b5596c82bb380c53a603bb051cf019d5c849c47e117c5064395"}, + {file = "psutil-5.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4bd4854f0c83aa84a5a40d3b5d0eb1f3c128f4146371e03baed4589fe4f3c931"}, + {file = "psutil-5.9.3.tar.gz", hash = "sha256:7ccfcdfea4fc4b0a02ca2c31de7fcd186beb9cff8207800e14ab66f79c773af6"}, +] +ptyprocess = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] +pure-eval = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] +pycapnp = [ + {file = "pycapnp-1.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:bdd013eae51d190a2426d00cc72d0aaed148a5be778ca86ee1adae3ab7a0613f"}, + {file = "pycapnp-1.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b9a1d6306a0e3e0090574aeb08d432bd67f9eb04ab564e89ef34cd1fe320b20f"}, + {file = "pycapnp-1.1.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:47c8bc28521312660c95cfc8a552654949407f8b17bc7ed6955ad7dae34d21a4"}, + {file = "pycapnp-1.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:60adf2674f89f629551171116b8f400b17e9a41a2ef15736767acec405d4ca50"}, + {file = "pycapnp-1.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a788a374ccb93354943c89f5b1caf785faf7bb90191cd6265e042aa004f8b206"}, + {file = "pycapnp-1.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a1746017079107232faf26af8ef4284ab0b20ce5cbe688d44e7553a67e5e5cb"}, + {file = "pycapnp-1.1.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0c770145a4eccfe97f53ab500283aa9bf969d4a37bffc75737a964db4f2af833"}, + {file = "pycapnp-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:1774a4fe9db5f094ba40cf00898fa4b437773e7f9c538b779275b9f422a92ebc"}, + {file = "pycapnp-1.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2b28d5d951602c0b832bbe63f85ebdd7685b33118b1c11c2c65a243ec9f35a66"}, + {file = "pycapnp-1.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:61b009faba34855c9d29db107e188898c83099347e22ebcbc1d955774403247b"}, + {file = "pycapnp-1.1.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a7aa9af0185e5977a59228db5042dffb048b2d4bf4f665d2105b4781cf2fcbc"}, + {file = "pycapnp-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:13badfb644e2eb7f1219aab259d18b262d1512021e4112fa1ad5e74d17bc30cf"}, + {file = "pycapnp-1.1.0.tar.gz", hash = "sha256:786a2e39b79e592a41e8a1eaeea6e41e2015ecb9f5b7f7c20dfc5768ba1ae077"}, +] +pycodestyle = [ + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, +] +pycparser = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] +pycryptodome = [ + {file = "pycryptodome-3.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff7ae90e36c1715a54446e7872b76102baa5c63aa980917f4aa45e8c78d1a3ec"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2ffd8b31561455453ca9f62cb4c24e6b8d119d6d531087af5f14b64bee2c23e6"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2ea63d46157386c5053cfebcdd9bd8e0c8b7b0ac4a0507a027f5174929403884"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0926f7cc3735033061ef3cf27ed16faad6544b14666410727b31fea85a5b16eb"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, + {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, + {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, + {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, + {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, + {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, + {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, + {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, + {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, + {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, + {file = "pycryptodome-3.15.0-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:ff287bcba9fbeb4f1cccc1f2e90a08d691480735a611ee83c80a7d74ad72b9d9"}, + {file = "pycryptodome-3.15.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:60b4faae330c3624cc5a546ba9cfd7b8273995a15de94ee4538130d74953ec2e"}, + {file = "pycryptodome-3.15.0-pp27-pypy_73-win32.whl", hash = "sha256:a8f06611e691c2ce45ca09bbf983e2ff2f8f4f87313609d80c125aff9fad6e7f"}, + {file = "pycryptodome-3.15.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b9cc96e274b253e47ad33ae1fccc36ea386f5251a823ccb50593a935db47fdd2"}, + {file = "pycryptodome-3.15.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:ecaaef2d21b365d9c5ca8427ffc10cebed9d9102749fd502218c23cb9a05feb5"}, + {file = "pycryptodome-3.15.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:d2a39a66057ab191e5c27211a7daf8f0737f23acbf6b3562b25a62df65ffcb7b"}, + {file = "pycryptodome-3.15.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:9c772c485b27967514d0df1458b56875f4b6d025566bf27399d0c239ff1b369f"}, + {file = "pycryptodome-3.15.0.tar.gz", hash = "sha256:9135dddad504592bcc18b0d2d95ce86c3a5ea87ec6447ef25cfedea12d6018b8"}, +] +pycuda = [ + {file = "pycuda-2022.1.tar.gz", hash = "sha256:acd9030d93e76e60b122e33ad16bcf01bb1344f4c304dedff1cd2bffb0f313a3"}, +] +pycurl = [ + {file = "pycurl-7.45.1.tar.gz", hash = "sha256:a863ad18ff478f5545924057887cdae422e1b2746e41674615f687498ea5b88a"}, +] +pyflakes = [ + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, +] +pygame = [ + {file = "pygame-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f149e182d0eeef15d8a9b4c9dad1b87dc6eba3a99bd3c44a777a3a2b053a3dca"}, + {file = "pygame-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc4444d61d48c5546df5137cdf81554887ddb6e2ef1be7f51eb77ea3b6bdd56f"}, + {file = "pygame-2.1.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a0ccf8e3dce7ca67d523a6020b7e3dbf4b26797a9a8db5cc4c7b5ef20fb64701"}, + {file = "pygame-2.1.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7889dce887ec83c9a0bef8d9eb3669d8863fdaf37c45bacec707d8ad90b24a38"}, + {file = "pygame-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db2f40d5a75fd9cdda473c58b0d8b294da6e0179f00bb3b1fc2f7f29cac09bea"}, + {file = "pygame-2.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4b4cd440d50a9f8551b8989e856aab175593af07eb825cad22fd2f8f6f2ffce"}, + {file = "pygame-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:754c2906f2ef47173a14493e1de116b2a56a2c8e1764f1202ba844d080248a5b"}, + {file = "pygame-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c99b95e62cdda29c2e60235d7763447c168a6a877403e6f9ca5b2e2bb297c2ce"}, + {file = "pygame-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:9649419254d3282dae41f23837de4108b17bc62187c3acd8af2ae3801b765cbd"}, + {file = "pygame-2.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dcc285ee1f1d0e2672cc52f880fd3f564b1505de710e817f692fbf64a72ca657"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e1bb25986db77a48f632469c6bc61baf7508ce945aa6161c02180d4ee5ac5b8d"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e7a8e18677e0064b7a422f6653a622652d932826a27e50f279d55a8b122a1a83"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd528dbb91eca16f7522c975d0f9e94b95f6b5024c82c3247dc0383d242d33c6"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc9586e17875c0cdf8764597955f9daa979098fd4f80be07ed68276ac225480"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ce7f3d8af14d7e04eb7eb41c5e5313c43508c252bb2b9eb53e51fc87ada9fd"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e09044e9e1aa8512d6a9c7ce5f94b881824bcfc401105f3c24f546dfc3bb4aa5"}, + {file = "pygame-2.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:40e4d8d65985bb467d9c5a1305fb53fd6820c61d764979600becab973339676f"}, + {file = "pygame-2.1.2-cp36-cp36m-win32.whl", hash = "sha256:50d9a21edd551669862c27c9272747401b20b1939abaacb842c08ea1cdd1c04d"}, + {file = "pygame-2.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:e18c9466131378421d00fc40b637425229238d506a073d9c537b230b355a25d6"}, + {file = "pygame-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:07ca9f683075aea9bd977af9f09a720ebf747343d3ea8103e4f1735283b02330"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3c8d6637ff75351e581327efefa9d04eeb0f257b533392b6cc6b15ceca4f7c5e"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ebbefb8b576572c8fc97a3321d37dc2b4afea6b6e3877a67f7158d8c2c4cefe"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d6452419e01a0f848aed0597f69fd10a4c2a7750c15d1b0607f86090a39dcf3"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e627300a66a90651fb39e41601d447b1fdbbfffca3f08ef0278d6cc0436b2160"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56a811d8821f7b9a594e3d0e0dd8bd39b25e3eea8963d5963263b90fd2ea5c2"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24b4f7f30fa2b3d092b60be6fcc725fb91d569fc87a9bcc91614ee8b0c005726"}, + {file = "pygame-2.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8e87716114e97322fb177e223d889a4be369a0f73212f4f8507fe0cd43253b23"}, + {file = "pygame-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:20676da24e3e3e6b9fc4eecc7ba09d77ef46c3a83a028763ba1d222476c2e3fb"}, + {file = "pygame-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:93c4cbfc942dd00410eaa9e84252129f9f9993f37f683006d7b49ab245342254"}, + {file = "pygame-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2405414d8c572668e04739875661e030a0c588e197fa95463fe301c3d0a0510b"}, + {file = "pygame-2.1.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e8632f6b2ddb90f6f3950744bd65d5ef15af615e3034057fa30ff836f48a7179"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ca5ef1315fa67c241a657ab077be44f230c05740c95f0b46409457dceefdc7e5"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1219a963941bd53aa754e8449364c142004fe706c33a9c22ff2a76521a82d078"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bb0674aa789848ddc264bfc60c54965bf3bb659c141de4f600e379acc9b944c"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24254c4244f0d9bdc904f5d3f38e86757ca4c6aa0e44a6d55ef5e016bc7274d6"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97a74ba186deee68318a52637012ef6abf5be6282c659e1d1ba6ad08cf35ec85"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0e97d38308c441942577fea7fcd1326308bc56d6be6c024218e94d075d322e0f"}, + {file = "pygame-2.1.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ea36f4f93524554a35cac2359df63b50af6556ed866830aa1f07f0d8580280ea"}, + {file = "pygame-2.1.2-cp38-cp38-win32.whl", hash = "sha256:4aa3ae32320cc704d63e185864e44f6265c2a6e52c9384afe152cc3d51b3a2ef"}, + {file = "pygame-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:9d7b021b8dde5d528363e474bc18bd6f79a9666eef89fb4859bcb8f0a536c9de"}, + {file = "pygame-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:660c80c0b2e80f1f801715583b759fb4c7bc0c11eb3b534e89c9fc4bfbc38acd"}, + {file = "pygame-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dad6bf3fdd3752d7519422f3732be779b98fe7c87d32c3efe2fdffdcbeebb6ca"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:119dee20c372c85dc47b717119534d15a60c64ceab8b0eb09278866d10486afe"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fc2e5db54491e8f27785fc5204c96f540d3557dcf5b0a9a857b6594d6b32561b"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2d3c50ee9847b743db6cd7b1bb17a94c2c2abc16679d70f5e745cabdf19e655"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ecda8dd4583982bb65f9c682f244a5e94524dcf628379766227e9ed97201a49"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e06ae8e1c830f1b9c36a2bc6bb11de840232e95b78e2c349c6ed803a303be19"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5ea87da5fe4b6164c3854f3b0c9146811dbad0dd7fa74297683dfacc485ae1c"}, + {file = "pygame-2.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0427c103f741234336e5606d2fad86f5403c1a3d1dc55c309fbff3c984f0c9ae"}, + {file = "pygame-2.1.2-cp39-cp39-win32.whl", hash = "sha256:5e88b0d4338b94960686f59396f23f7f684fed4859fcc3b9f40286d72c1c61af"}, + {file = "pygame-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:5d0c14152d0ca8ef5fbcc5ed9981462bdf59a9ae85a291e62d8a8d0b7e5cbe43"}, + {file = "pygame-2.1.2-pp36-pypy36_pp73-win32.whl", hash = "sha256:636f51f56615d67459b11918206bb4da30cd7d7042027bf997c218ccd6c77902"}, + {file = "pygame-2.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ff961c3280d6ee5f4163f4772f963d7a4dbe42e36c6dd54b79ad436c1f046e5d"}, + {file = "pygame-2.1.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fc30e834f65b893d1b4c230070183bf98e6b70c41c1511687e8436a33d5ce49d"}, + {file = "pygame-2.1.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5c7600bf307de1ca1dca0cc7840e34604d5b0b0a5a5dad345c3fa62b054b886d"}, + {file = "pygame-2.1.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7fdb93b4282962c9a2ebf1af994ee698be823dd913218ed97a5f2fb372b10b66"}, + {file = "pygame-2.1.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fddec8829e96424800c806582d73a5173b7d48946cccf7d035839ca09850db8"}, + {file = "pygame-2.1.2.tar.gz", hash = "sha256:d6d0eca28f886f0477cd0721ac688189155a587f2bb8eae740e52ca56c3ad23c"}, +] +pygments = [ + {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, + {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, +] +pyjwt = [ + {file = "PyJWT-2.6.0-py3-none-any.whl", hash = "sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14"}, + {file = "PyJWT-2.6.0.tar.gz", hash = "sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd"}, +] +pylev = [ + {file = "pylev-1.4.0-py2.py3-none-any.whl", hash = "sha256:7b2e2aa7b00e05bb3f7650eb506fc89f474f70493271a35c242d9a92188ad3dd"}, + {file = "pylev-1.4.0.tar.gz", hash = "sha256:9e77e941042ad3a4cc305dcdf2b2dec1aec2fbe3dd9015d2698ad02b173006d1"}, +] +pylint = [ + {file = "pylint-2.15.4-py3-none-any.whl", hash = "sha256:629cf1dbdfb6609d7e7a45815a8bb59300e34aa35783b5ac563acaca2c4022e9"}, + {file = "pylint-2.15.4.tar.gz", hash = "sha256:5441e9294335d354b7bad57c1044e5bd7cce25c433475d76b440e53452fa5cb8"}, +] +pymsalruntime = [ + {file = "pymsalruntime-0.11.2-cp310-cp310-win32.whl", hash = "sha256:a45e35c9fa58c196029bb9f5b8bedd313b2a8ac971d576c57c31cb06139de247"}, + {file = "pymsalruntime-0.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:81bd2502779b1c032d878b3e6bdb64882b8c7f94560cffed62e2555470d1fe45"}, + {file = "pymsalruntime-0.11.2-cp36-cp36m-win32.whl", hash = "sha256:e6f6316128de8f62caeadf2a755e3919cc4532964d77a550974b156f27ae5f33"}, + {file = "pymsalruntime-0.11.2-cp36-cp36m-win_amd64.whl", hash = "sha256:ee139e7222e89f5bda3d6e8f9426b6bc0e8b4ef7c6fc2e6b9bd8b6c11579c3fb"}, + {file = "pymsalruntime-0.11.2-cp37-cp37m-win32.whl", hash = "sha256:6eedca38877cc8718ac273cf796aebed9a25d64258d717599f601bc01f9b7922"}, + {file = "pymsalruntime-0.11.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b0f289e4d3b01bbddf422cd82899295cf5ee4c41eda45752dd3a0733acd0ba0f"}, + {file = "pymsalruntime-0.11.2-cp38-cp38-win32.whl", hash = "sha256:5760a1c1b6fa8c10f15a325815e0315a703106d3984cbc939d17f48d84ab21bb"}, + {file = "pymsalruntime-0.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:e0654d04f54d1cee218a868da77f4a5a2b5369e2cc9bb35f539144256f08b00a"}, + {file = "pymsalruntime-0.11.2-cp39-cp39-win32.whl", hash = "sha256:06501f5a1fcf83ba2edbae34c94df08f50c31290301ac20f1828c4cecc2ae1bc"}, + {file = "pymsalruntime-0.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:c10f8761baa042cba3a502be50fb19d0fe46850de82cb730b836ac3aff7a9b0e"}, + {file = "pymsalruntime-0.11.2.tar.gz", hash = "sha256:636d01c7f6f165b48e288c2af0bd21447649846af00050956ba28a5d4079e98b"}, +] +pymysql = [ + {file = "PyMySQL-0.9.3-py2.py3-none-any.whl", hash = "sha256:3943fbbbc1e902f41daf7f9165519f140c4451c179380677e6a848587042561a"}, + {file = "PyMySQL-0.9.3.tar.gz", hash = "sha256:d8c059dcd81dedb85a9f034d5e22dcb4442c0b201908bede99e306d65ea7c8e7"}, +] +pynacl = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] +pyopencl = [ + {file = "pyopencl-2022.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c270c7090f6bd8a1cc006aca38256936a0b82f70165e8aff873763218f29bf85"}, + {file = "pyopencl-2022.2.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a823c2003d2d3754836f7e65f19e553f8ca022f493d0111ea3bacd886853596"}, + {file = "pyopencl-2022.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1d1605eed80f9305251578b41068e1021f140e6d503b22933a4860c43e7cde"}, + {file = "pyopencl-2022.2.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:85bf733b73158a66484763ff7bca7b2d5d0187933987a2753cad3f0deeff989f"}, + {file = "pyopencl-2022.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f4288700717e3f0b0ce7c6663729ea6a1362d86964261fcaa84ca2efcf06b0"}, + {file = "pyopencl-2022.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:dc72723fd7d5041521f9dccece70ab1ab06f2ad74b1738712a49a3b56cea3628"}, + {file = "pyopencl-2022.2.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:82b3f13843c034cee54906b2c750a65910c9f28ba58b61abf80b9bc9c1595a1f"}, + {file = "pyopencl-2022.2.4-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a0893caf4b522559a233c4d66e7c8a96a01d8f2c038ff7fd5b3d795a1eb2ed"}, + {file = "pyopencl-2022.2.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3a5d59d87d3e271f7d41c80d558cf45f4226003ec3c341d8374d3ef849614b4"}, + {file = "pyopencl-2022.2.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cef4b300b64b58d55364d6d9eb37123907ee1f32f2dc7f0b7d1fcabbaf6fe260"}, + {file = "pyopencl-2022.2.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:47f751cfa75d3038ba0aedf587dd42dc447b8e49b88339048b2147cce176e286"}, + {file = "pyopencl-2022.2.4-cp36-cp36m-win_amd64.whl", hash = "sha256:3b82458c982e6eb61691712139fc8cfd69f28ef127db2b0de06e87058e919f96"}, + {file = "pyopencl-2022.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28a0df521643644a1d5b521032b7c6617f7d53b09851a21ce9b10b8ed869dfd5"}, + {file = "pyopencl-2022.2.4-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3611fe2f7c219dcf3d3a119873bfe7a837a467aac00c6e53682dda71a060d29f"}, + {file = "pyopencl-2022.2.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5cfc4459e5c84ecba49b928d2e9a439f0421342e16884a6749aa227efea900"}, + {file = "pyopencl-2022.2.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:37001a8b70bde143597f22e79dbac90ae8c997e2136b0ec4391a2824f78eb548"}, + {file = "pyopencl-2022.2.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:349e1ff88b2c0ddb343666e1857b86c65fa34545354012382fe84b5d564ffde1"}, + {file = "pyopencl-2022.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:da4bc9167f04eb47774e30c5cc6b411b970d8b09ea61873b86058dd2d64445d1"}, + {file = "pyopencl-2022.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8fae8ba0a020c5db230bba53c39fd8f950983a992fbb1318a19ba06af83bd416"}, + {file = "pyopencl-2022.2.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8685df5b6ec23da07751afd589a168825f6fa727634bf957652091ed7c937151"}, + {file = "pyopencl-2022.2.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84f94a99822d81372b16dcdc56ee9f7e3d2268acaf9cca21924e65b4ddefae20"}, + {file = "pyopencl-2022.2.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:532d7972d8cc27278761634e5367ff84cacee81f32490ffce9285ea122804768"}, + {file = "pyopencl-2022.2.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d31c4cd0af50aa602b2131a7b5c964e9105291d611f2d4418ed4628094c9336f"}, + {file = "pyopencl-2022.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:ca9d67ca0b072989530c71c4f781acc1efd1adb6a459e742a6d38d2b8ab1d8e8"}, + {file = "pyopencl-2022.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6d2a3d6dfbae423dbf6dce45ca8a1b32cca2ee842aea49d246f8bbf8ab90812"}, + {file = "pyopencl-2022.2.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6e7fbacef495944e1ebb1456ac7a4c38562077d50dfd804dca6aef204f6a79a"}, + {file = "pyopencl-2022.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3735b5d2add089ea02b43ace69b50fb8fb55b11b93f7bc4be5b4249fb3370b64"}, + {file = "pyopencl-2022.2.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d9e88c92569a5bbcbec802dc193be06a19891979fb02f9ca4739239e2cfd5e04"}, + {file = "pyopencl-2022.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0b456e153c1ae1f92379680710daa228c9aa0302918e24f12355533bd4b5e1f4"}, + {file = "pyopencl-2022.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:876912cfebfe9aa92a478d0bf737178e7b686d27103d7279cd1dc754b8e6e85d"}, + {file = "pyopencl-2022.2.4-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72f259595ac26d250f39ffbfcb47cfa81181aff6f24d70e718f67114a452eb43"}, + {file = "pyopencl-2022.2.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0caf451084194da8262d6197251cccdac4c2945d0cb8807fe4bd1d7b0b6ecd5c"}, + {file = "pyopencl-2022.2.4-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d64d2354fef846fa7e252078c5a4b74a3c302454de6167d6802a9e1d374e60"}, + {file = "pyopencl-2022.2.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:912bc9c48c443f5a88e8827ee68e9cb03f6a1d78ac6f64bb7a4d65f849fa7069"}, + {file = "pyopencl-2022.2.4-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebf8ebabee550849e8d4a21e13487d34b17c89749b38169bba249020f21363cf"}, + {file = "pyopencl-2022.2.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3384a1089df1256df00fde4fc87d1f7f500fc640f4ff47adf55a592502a16396"}, + {file = "pyopencl-2022.2.4.tar.gz", hash = "sha256:b57c9ef8bd8e6db07e89106f3091ba236b24f95a38fd40dfb17d2ed7ff6be4ad"}, +] +pyopenssl = [ + {file = "pyOpenSSL-22.0.0-py2.py3-none-any.whl", hash = "sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0"}, + {file = "pyOpenSSL-22.0.0.tar.gz", hash = "sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf"}, +] +pyparsing = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] +pyprof2calltree = [ + {file = "pyprof2calltree-1.4.5.tar.gz", hash = "sha256:a635672ff31677486350b2be9a823ef92f740e6354a6aeda8fa4a8a3768e8f2f"}, +] +pyproj = [ + {file = "pyproj-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f343725566267a296b09ee7e591894f1fdc90f84f8ad5ec476aeb53bd4479c07"}, + {file = "pyproj-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5816807ca0bdc7256558770c6206a6783a3f02bcf844f94ee245f197bb5f7285"}, + {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e609903572a56cca758bbaee5c1663c3e829ddce5eec4f368e68277e37022b"}, + {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fd425ee8b6781c249c7adb7daa2e6c41ce573afabe4f380f5eecd913b56a3be"}, + {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954b068136518b3174d0a99448056e97af62b63392a95c420894f7de2229dae6"}, + {file = "pyproj-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:4a23d84c5ffc383c7d9f0bde3a06fc1f6697b1b96725597f8f01e7b4bef0a2b5"}, + {file = "pyproj-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f9c100fd0fd80edbc7e4daa303600a8cbef6f0de43d005617acb38276b88dc0"}, + {file = "pyproj-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa5171f700f174777a9e9ed8f4655583243967c0f9cf2c90e3f54e54ff740134"}, + {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a496d9057b2128db9d733e66b206f2d5954bbae6b800d412f562d780561478c"}, + {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52e54796e2d9554a5eb8f11df4748af1fbbc47f76aa234d6faf09216a84554c5"}, + {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a454a7c4423faa2a14e939d08ef293ee347fa529c9df79022b0585a6e1d8310c"}, + {file = "pyproj-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:25a36e297f3e0524694d40259e3e895edc1a47492a0e30608268ffc1328e3f5d"}, + {file = "pyproj-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:77d5f519f3cdb94b026ecca626f78db4f041afe201cf082079c8c0092a30b087"}, + {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccb4b70ad25218027f77e0c8934d10f9b7cdf91d5e64080147743d58fddbc3c0"}, + {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e161114bc92701647a83c4bbce79489984f12d980cabb365516e953d1450885"}, + {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f80adda8c54b84271a93829477a01aa57bc178c834362e9f74e1de1b5033c74c"}, + {file = "pyproj-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:221d8939685e0c43ee594c9f04b6a73a10e8e1cc0e85f28be0b4eb2f1bc8777d"}, + {file = "pyproj-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d94afed99f31673d3d19fe750283621e193e2a53ca9e0443bf9d092c3905833b"}, + {file = "pyproj-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fff9c3a991508f16027be27d153f6c5583d03799443639d13c681e60f49e2d7"}, + {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85acf09e5a9e35cd9ee72989793adb7089b4e611be02a43d3d0bda50ad116b"}, + {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45554f47d1a12a84b0620e4abc08a2a1b5d9f273a4759eaef75e74788ec7162a"}, + {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f62c20656ac9b6076ebb213e9a635d52f4f01fef95310121d337e62e910cb6"}, + {file = "pyproj-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:65a0bcdbad95b3c00b419e5d75b1f7e450ec17349b5ea16bf7438ac1d50a12a2"}, + {file = "pyproj-3.4.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:14ad113b5753c6057f9b2f3c85a6497cef7fa237c4328f2943c0223e98c1dde6"}, + {file = "pyproj-3.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4688b4cd62cbd86b5e855f9e27d90fbb53f2b4c2ea1cd394a46919e1a4151b89"}, + {file = "pyproj-3.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47ad53452ae1dc8b0bf1df920a210bb5616989085aa646592f8681f1d741a754"}, + {file = "pyproj-3.4.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:48787962232109bad8b72e27949037a9b03591228a6955f25dbe451233e8648a"}, + {file = "pyproj-3.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2cb8592259ea54e7557523b079d3f2304081680bdb48bfbf0fd879ee6156129c"}, + {file = "pyproj-3.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82200b4569d68b421c079d2973475b58d5959306fe758b43366e79fe96facfe5"}, + {file = "pyproj-3.4.0.tar.gz", hash = "sha256:a708445927ace9857f52c3ba67d2915da7b41a8fdcd9b8f99a4c9ed60a75eb33"}, +] +pyreadline3 = [ + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, +] +pyrsistent = [ + {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"}, + {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"}, + {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"}, + {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"}, + {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"}, + {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"}, + {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"}, + {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"}, + {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"}, + {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"}, + {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"}, + {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"}, + {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"}, + {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"}, + {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"}, + {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"}, + {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"}, + {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"}, + {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"}, + {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"}, + {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"}, +] +pyserial = [ + {file = "pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"}, + {file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"}, +] +pysocks = [ + {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, + {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, + {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, +] +pytest = [ + {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, + {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, +] +pytest-forked = [ + {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, + {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, +] +pytest-xdist = [ + {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, + {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +python-engineio = [ + {file = "python-engineio-4.3.4.tar.gz", hash = "sha256:d8d8b072799c36cadcdcc2b40d2a560ce09797ab3d2d596b2ad519a5e4df19ae"}, + {file = "python_engineio-4.3.4-py3-none-any.whl", hash = "sha256:7454314a529bba20e745928601ffeaf101c1b5aca9a6c4e48ad397803d10ea0c"}, +] +python-logstash = [ + {file = "python-logstash-0.4.8.tar.gz", hash = "sha256:d04e1ce11ecc107e4a4f3b807fc57d96811e964a554081b3bbb44732f74ef5f9"}, +] +python-socketio = [ + {file = "python-socketio-5.7.2.tar.gz", hash = "sha256:92395062d9db3c13d30e7cdedaa0e1330bba78505645db695415f9a3c628d097"}, + {file = "python_socketio-5.7.2-py3-none-any.whl", hash = "sha256:d9a9f047e6fdd306c852fbac36516f4b495c2096f8ad9ceb8803b8e5ff5622e3"}, +] +pytools = [ + {file = "pytools-2022.1.12.tar.gz", hash = "sha256:4d62875e9a2ab2a24e393a9a8b799492f1a721bffa840af3807bfd42871dd1f4"}, +] +pytz = [ + {file = "pytz-2022.5-py2.py3-none-any.whl", hash = "sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22"}, + {file = "pytz-2022.5.tar.gz", hash = "sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"}, +] +pywavelets = [ + {file = "PyWavelets-1.4.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:d854411eb5ee9cb4bc5d0e66e3634aeb8f594210f6a1bed96dbed57ec70f181c"}, + {file = "PyWavelets-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:231b0e0b1cdc1112f4af3c24eea7bf181c418d37922a67670e9bf6cfa2d544d4"}, + {file = "PyWavelets-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:754fa5085768227c4f4a26c1e0c78bc509a266d9ebd0eb69a278be7e3ece943c"}, + {file = "PyWavelets-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da7b9c006171be1f9ddb12cc6e0d3d703b95f7f43cb5e2c6f5f15d3233fcf202"}, + {file = "PyWavelets-1.4.1-cp310-cp310-win32.whl", hash = "sha256:67a0d28a08909f21400cb09ff62ba94c064882ffd9e3a6b27880a111211d59bd"}, + {file = "PyWavelets-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:91d3d393cffa634f0e550d88c0e3f217c96cfb9e32781f2960876f1808d9b45b"}, + {file = "PyWavelets-1.4.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:64c6bac6204327321db30b775060fbe8e8642316e6bff17f06b9f34936f88875"}, + {file = "PyWavelets-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f19327f2129fb7977bc59b966b4974dfd72879c093e44a7287500a7032695de"}, + {file = "PyWavelets-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad987748f60418d5f4138db89d82ba0cb49b086e0cbb8fd5c3ed4a814cfb705e"}, + {file = "PyWavelets-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:875d4d620eee655346e3589a16a73790cf9f8917abba062234439b594e706784"}, + {file = "PyWavelets-1.4.1-cp311-cp311-win32.whl", hash = "sha256:7231461d7a8eb3bdc7aa2d97d9f67ea5a9f8902522818e7e2ead9c2b3408eeb1"}, + {file = "PyWavelets-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:daf0aa79842b571308d7c31a9c43bc99a30b6328e6aea3f50388cd8f69ba7dbc"}, + {file = "PyWavelets-1.4.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:ab7da0a17822cd2f6545626946d3b82d1a8e106afc4b50e3387719ba01c7b966"}, + {file = "PyWavelets-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:578af438a02a86b70f1975b546f68aaaf38f28fb082a61ceb799816049ed18aa"}, + {file = "PyWavelets-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb5ca8d11d3f98e89e65796a2125be98424d22e5ada360a0dbabff659fca0fc"}, + {file = "PyWavelets-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:058b46434eac4c04dd89aeef6fa39e4b6496a951d78c500b6641fd5b2cc2f9f4"}, + {file = "PyWavelets-1.4.1-cp38-cp38-win32.whl", hash = "sha256:de7cd61a88a982edfec01ea755b0740e94766e00a1ceceeafef3ed4c85c605cd"}, + {file = "PyWavelets-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:7ab8d9db0fe549ab2ee0bea61f614e658dd2df419d5b75fba47baa761e95f8f2"}, + {file = "PyWavelets-1.4.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:23bafd60350b2b868076d976bdd92f950b3944f119b4754b1d7ff22b7acbf6c6"}, + {file = "PyWavelets-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0e56cd7a53aed3cceca91a04d62feb3a0aca6725b1912d29546c26f6ea90426"}, + {file = "PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030670a213ee8fefa56f6387b0c8e7d970c7f7ad6850dc048bd7c89364771b9b"}, + {file = "PyWavelets-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71ab30f51ee4470741bb55fc6b197b4a2b612232e30f6ac069106f0156342356"}, + {file = "PyWavelets-1.4.1-cp39-cp39-win32.whl", hash = "sha256:47cac4fa25bed76a45bc781a293c26ac63e8eaae9eb8f9be961758d22b58649c"}, + {file = "PyWavelets-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:88aa5449e109d8f5e7f0adef85f7f73b1ab086102865be64421a3a3d02d277f4"}, + {file = "PyWavelets-1.4.1.tar.gz", hash = "sha256:6437af3ddf083118c26d8f97ab43b0724b956c9f958e9ea788659f6a2834ba93"}, +] +pywin32 = [ + {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"}, + {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"}, + {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"}, + {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"}, + {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"}, + {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"}, + {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"}, + {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"}, + {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"}, + {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"}, + {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"}, + {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"}, + {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"}, + {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"}, +] +pywin32-ctypes = [ + {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, + {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, +] +pywinpty = [ + {file = "pywinpty-2.0.8-cp310-none-win_amd64.whl", hash = "sha256:9cbf89834abc8d4d4c5f295f11e15dd93889a8069db876f2bc10cc64aa4060ac"}, + {file = "pywinpty-2.0.8-cp37-none-win_amd64.whl", hash = "sha256:a2f9a95f3b74262ef73f1be5257c295c8caab1f79f081aa3400ca61c724f9bc6"}, + {file = "pywinpty-2.0.8-cp38-none-win_amd64.whl", hash = "sha256:23389d56258d6a1fbc4b41257bd65e5bdabaf6fde7f30a13806e557ea9ee6865"}, + {file = "pywinpty-2.0.8-cp39-none-win_amd64.whl", hash = "sha256:ea7c1da94eed5ef93e75026c67c60d4dca33ea9a1c212fa89221079a7b463c68"}, + {file = "pywinpty-2.0.8.tar.gz", hash = "sha256:a89b9021c63ef78b1e7d8e14f0fac4748c88a0c2e4f529c84f37f6e72b914280"}, +] +pyyaml = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] +pyzmq = [ + {file = "pyzmq-23.2.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:a3fd44b5046d247e7f0f1660bcafe7b5fb0db55d0934c05dd57dda9e1f823ce7"}, + {file = "pyzmq-23.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2141e6798d5981be04c08996d27962086a1aa3ea536fe9cf7e89817fd4523f86"}, + {file = "pyzmq-23.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a39ddb0431a68954bd318b923230fa5b649c9c62b0e8340388820c5f1b15bd2"}, + {file = "pyzmq-23.2.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e06747014a5ad1b28cebf5bc1ddcdaccfb44e9b441d35e6feb1286c8a72e54be"}, + {file = "pyzmq-23.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e0113d70b095339e99bb522fe7294f5ae6a7f3b2b8f52f659469a74b5cc7661"}, + {file = "pyzmq-23.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:71b32a1e827bdcbf73750e60370d3b07685816ff3d8695f450f0f8c3226503f8"}, + {file = "pyzmq-23.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:55568a020ad2cae9ae36da6058e7ca332a56df968f601cbdb7cf6efb2a77579a"}, + {file = "pyzmq-23.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c02a0cd39dc01659b3d6cb70bb3a41aebd9885fd78239acdd8d9c91351c4568"}, + {file = "pyzmq-23.2.1-cp310-cp310-win32.whl", hash = "sha256:e1fe30bcd5aea5948c42685fad910cd285eacb2518ea4dc6c170d6b535bee95d"}, + {file = "pyzmq-23.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:650389bbfca73955b262b2230423d89992f38ec48033307ae80e700eaa2fbb63"}, + {file = "pyzmq-23.2.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:e753eee6d3b93c5354e8ba0a1d62956ee49355f0a36e00570823ef64e66183f5"}, + {file = "pyzmq-23.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f07016e3cf088dbfc6e7c5a7b3f540db5c23b0190d539e4fd3e2b5e6beffa4b5"}, + {file = "pyzmq-23.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4805af9614b0b41b7e57d17673459facf85604dac502a5a9244f6e8c9a4de658"}, + {file = "pyzmq-23.2.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39dd252b683816935702825e5bf775df16090619ced9bb4ba68c2d0b6f0c9b18"}, + {file = "pyzmq-23.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:84678153432241bcdca2210cf4ff83560b200556867aea913ffbb960f5d5f340"}, + {file = "pyzmq-23.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:90d88f9d9a2ae6cfb1dc4ea2d1710cdf6456bc1b9a06dd1bb485c5d298f2517e"}, + {file = "pyzmq-23.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:794871988c34727c7f79bdfe2546e6854ae1fa2e1feb382784f23a9c6c63ecb3"}, + {file = "pyzmq-23.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c56b1a62a1fb87565343c57b6743fd5da6e138b8c6562361d7d9b5ce4acf399a"}, + {file = "pyzmq-23.2.1-cp311-cp311-win32.whl", hash = "sha256:c3ebf1668664d20c8f7d468955f18379b7d1f7bc8946b13243d050fa3888c7ff"}, + {file = "pyzmq-23.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:ec9803aca9491fd6f0d853d2a6147f19f8deaaa23b1b713d05c5d09e56ea7142"}, + {file = "pyzmq-23.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:385609812eafd9970c3752c51f2f6c4f224807e3e441bcfd8c8273877d00c8a8"}, + {file = "pyzmq-23.2.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b861db65f6b8906c8d6db51dde2448f266f0c66bf28db2c37aea50f58a849859"}, + {file = "pyzmq-23.2.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6b1e79bba24f6df1712e3188d5c32c480d8eda03e8ecff44dc8ecb0805fa62f3"}, + {file = "pyzmq-23.2.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8dc66f109a245653b19df0f44a5af7a3f14cb8ad6c780ead506158a057bd36ce"}, + {file = "pyzmq-23.2.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b815991c7d024bf461f358ad871f2be1135576274caed5749c4828859e40354e"}, + {file = "pyzmq-23.2.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:29b74774a0bfd3c4d98ac853f0bdca55bd9ec89d5b0def5486407cca54472ef8"}, + {file = "pyzmq-23.2.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4bb798bef181648827019001f6be43e1c48b34b477763b37a8d27d8c06d197b8"}, + {file = "pyzmq-23.2.1-cp36-cp36m-win32.whl", hash = "sha256:565bd5ab81f6964fc4067ccf2e00877ad0fa917308975694bbb54378389215f8"}, + {file = "pyzmq-23.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:1f368a82b29f80071781b20663c0fc0c8f6b13273f9f5abe1526af939534f90f"}, + {file = "pyzmq-23.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c9cfaf530e6a7ff65f0afe275e99f983f68b54dfb23ea401f0bc297a632766b6"}, + {file = "pyzmq-23.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c558b50402fca1acc94329c5d8f12aa429738904a5cfb32b9ed3c61235221bb"}, + {file = "pyzmq-23.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:20bafc4095eab00f41a510579363a3f5e1f5c69d7ee10f1d88895c4df0259183"}, + {file = "pyzmq-23.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f619fd38fc2641abfb53cca719c165182500600b82c695cc548a0f05f764be05"}, + {file = "pyzmq-23.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:044447ae4b2016a6b8697571fd633f799f860b19b76c4a2fd9b1140d52ee6745"}, + {file = "pyzmq-23.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:49d30ba7074f469e8167917abf9eb854c6503ae10153034a6d4df33618f1db5f"}, + {file = "pyzmq-23.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:48400b96788cdaca647021bf19a9cd668384f46e4d9c55cf045bdd17f65299c8"}, + {file = "pyzmq-23.2.1-cp37-cp37m-win32.whl", hash = "sha256:8a68f57b7a3f7b6b52ada79876be1efb97c8c0952423436e84d70cc139f16f0d"}, + {file = "pyzmq-23.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9e5bf6e7239fc9687239de7a283aa8b801ab85371116045b33ae20132a1325d6"}, + {file = "pyzmq-23.2.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:0ff6294e001129a9f22dcbfba186165c7e6f573c46de2704d76f873c94c65416"}, + {file = "pyzmq-23.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ffc6b1623d0f9affb351db4ca61f432dca3628a5ee015f9bf2bfbe9c6836881c"}, + {file = "pyzmq-23.2.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4d6f110c56f7d5b4d64dde3a382ae61b6d48174e30742859d8e971b18b6c9e5c"}, + {file = "pyzmq-23.2.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9269fbfe3a4eb2009199120861c4571ef1655fdf6951c3e7f233567c94e8c602"}, + {file = "pyzmq-23.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12e62ff0d5223ec09b597ab6d73858b9f64a51221399f3cb08aa495e1dff7935"}, + {file = "pyzmq-23.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6fd5d0d50cbcf4bc376861529a907bed026a4cbe8c22a500ff8243231ef02433"}, + {file = "pyzmq-23.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9d0ab2936085c85a1fc6f9fd8f89d5235ae99b051e90ec5baa5e73ad44346e1f"}, + {file = "pyzmq-23.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:022cf5ea7bcaa8a06a03c2706e0ae66904b6138b2155577cd34c64bc7cc637ab"}, + {file = "pyzmq-23.2.1-cp38-cp38-win32.whl", hash = "sha256:28dbdb90b2f6b131f8f10e6081012e4e25234213433420e67e0c1162de537113"}, + {file = "pyzmq-23.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:10d1910ec381b851aeb024a042a13db178cb1edf125e76a4e9d2548ad103aadb"}, + {file = "pyzmq-23.2.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:99a5a77a10863493a1ee8dece02578c6b32025fb3afff91b40476bc489e81648"}, + {file = "pyzmq-23.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aecd6ceaccc4b594e0092d6513ef3f1c0fa678dd89f86bb8ff1a47014b8fca35"}, + {file = "pyzmq-23.2.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:415ff62ac525d9add1e3550430a09b9928d2d24a20cc4ce809e67caac41219ab"}, + {file = "pyzmq-23.2.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:67975a9e1237b9ccc78f457bef17691bbdd2055a9d26e81ee914ba376846d0ce"}, + {file = "pyzmq-23.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e106b64bad744fe469dc3dd864f2764d66399178c1bf39d45294cc7980f14f"}, + {file = "pyzmq-23.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8c842109d31a9281d678f668629241c405928afbebd913c48a5a8e7aee61f63d"}, + {file = "pyzmq-23.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fefdf9b685fda4141b95ebec975946076a5e0723ff70b037032b2085c5317684"}, + {file = "pyzmq-23.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:79a87831b47a9f6161ad23fa5e89d5469dc585abc49f90b9b07fea8905ae1234"}, + {file = "pyzmq-23.2.1-cp39-cp39-win32.whl", hash = "sha256:342ca3077f47ec2ee41b9825142b614e03e026347167cbc72a59b618c4f6106c"}, + {file = "pyzmq-23.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:5e05492be125dce279721d6b54fd1b956546ecc4bcdfcf8e7b4c413bc0874c10"}, + {file = "pyzmq-23.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:07ed8aaf7ffe150af873269690cc654ffeca7491f62aae0f3821baa181f8d5fe"}, + {file = "pyzmq-23.2.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad28ddb40db8e450d7d4bf8a1d765d3f87b63b10e7e9a825a3c130c6371a8c03"}, + {file = "pyzmq-23.2.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2f67b63f53c6994d601404fd1a329e6d940ac3dd1d92946a93b2b9c70df67b9f"}, + {file = "pyzmq-23.2.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c890309296f53f9aa32ffcfc51d805705e1982bffd27c9692a8f1e1b8de279f4"}, + {file = "pyzmq-23.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:624fd38071a817644acdae075b92a23ea0bdd126a58148288e8284d23ec361ce"}, + {file = "pyzmq-23.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a114992a193577cb62233abf8cb2832970f9975805a64740e325d2f895e7f85a"}, + {file = "pyzmq-23.2.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c780acddd2934c6831ff832ecbf78a45a7b62d4eb216480f863854a8b7d54fa7"}, + {file = "pyzmq-23.2.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d904f6595acfaaf99a1a61881fea068500c40374d263e5e073aa4005e5f9c28a"}, + {file = "pyzmq-23.2.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:929d548b74c0f82f7f95b54e4a43f9e4ce2523cfb8a54d3f7141e45652304b2a"}, + {file = "pyzmq-23.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f392cbea531b7142d1958c0d4a0c9c8d760dc451e5848d8dd3387804d3e3e62c"}, + {file = "pyzmq-23.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a0f09d85c45f58aa8e715b42f8b26beba68b3b63a8f7049113478aca26efbc30"}, + {file = "pyzmq-23.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e708fbfdf4ee3107422b69ca65da1b9f056b431fc0888096a8c1d6cd908e8f"}, + {file = "pyzmq-23.2.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35e635343ff367f697d00fa1484262bb68e36bc74c9b80737eac5a1e04c4e1b1"}, + {file = "pyzmq-23.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efb9e38b2a590282704269585de7eb33bf43dc294cad092e1b172e23d4c217e5"}, + {file = "pyzmq-23.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:407f909c4e8fde62fbdad9ebd448319792258cc0550c2815567a4d9d8d9e6d18"}, + {file = "pyzmq-23.2.1.tar.gz", hash = "sha256:2b381aa867ece7d0a82f30a0c7f3d4387b7cf2e0697e33efaa5bed6c5784abcd"}, +] +qtconsole = [ + {file = "qtconsole-5.3.2-py3-none-any.whl", hash = "sha256:c29d24464f57cdbaa17d6f6060be6e6d5e29126e7feb57eebc1747433382b3d1"}, + {file = "qtconsole-5.3.2.tar.gz", hash = "sha256:8eadf012e83ab018295803c247c6ab7eacd3d5ab1e1d88a0f37fdcfdab9295a3"}, +] +qtpy = [ + {file = "QtPy-2.2.1-py3-none-any.whl", hash = "sha256:268cf5328f41353be1b127e04a81bc74ec9a9b54c9ac75dd8fe0ff48d8ad6ead"}, + {file = "QtPy-2.2.1.tar.gz", hash = "sha256:7d5231133b772e40b4ee514b6673aca558331e4b88ca038b26c9e16c5c95524f"}, +] +qudida = [ + {file = "qudida-0.0.4-py3-none-any.whl", hash = "sha256:4519714c40cd0f2e6c51e1735edae8f8b19f4efe1f33be13e9d644ca5f736dd6"}, + {file = "qudida-0.0.4.tar.gz", hash = "sha256:db198e2887ab0c9aa0023e565afbff41dfb76b361f85fd5e13f780d75ba18cc8"}, +] +reactivex = [ + {file = "reactivex-4.0.4-py3-none-any.whl", hash = "sha256:0004796c420bd9e68aad8e65627d85a8e13f293de76656165dffbcb3a0e3fb6a"}, + {file = "reactivex-4.0.4.tar.gz", hash = "sha256:e912e6591022ab9176df8348a653fe8c8fa7a301f26f9931c9d8c78a650e04e8"}, +] +redis = [ + {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"}, + {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"}, +] +requests = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] +requests-oauthlib = [ + {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, + {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, +] +requests-toolbelt = [ + {file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"}, + {file = "requests_toolbelt-0.9.1-py2.py3-none-any.whl", hash = "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f"}, +] +reverse-geocoder = [ + {file = "reverse_geocoder-1.5.1.tar.gz", hash = "sha256:2a2e781b5f69376d922b78fe8978f1350c84fce0ddb07e02c834ecf98b57c75c"}, +] +s2sphere = [ + {file = "s2sphere-0.2.5-py2.py3-none-any.whl", hash = "sha256:d2340c9cf458ddc9a89afd1d8048a4195ce6fa6b0095ab900d4be5271e537401"}, + {file = "s2sphere-0.2.5.tar.gz", hash = "sha256:c2478c1ff7c601a59a7151a57b605435897514578fa6bdb8730721c182adbbaf"}, +] +scikit-image = [ + {file = "scikit-image-0.19.3.tar.gz", hash = "sha256:24b5367de1762da6ee126dd8f30cc4e7efda474e0d7d70685433f0e3aa2ec450"}, + {file = "scikit_image-0.19.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:3a01372ae4bca223873304b0bff79b9d92446ac6d6177f73d89b45561e2d09d8"}, + {file = "scikit_image-0.19.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:fdf48d9b1f13af69e4e2c78e05067e322e9c8c97463c315cd0ecb47a94e259fc"}, + {file = "scikit_image-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b6a8f98f2ac9bb73706461fd1dec875f6a5141759ed526850a5a49e90003d19"}, + {file = "scikit_image-0.19.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfbb073f23deb48e0e60c47f8741d8089121d89cc78629ea8c5b51096efc5be7"}, + {file = "scikit_image-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:cc24177de3fdceca5d04807ad9c87d665f0bf01032ed94a9055cd1ed2b3f33e9"}, + {file = "scikit_image-0.19.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:fd9dd3994bb6f9f7a35f228323f3c4dc44b3cf2ff15fd72d895216e9333550c6"}, + {file = "scikit_image-0.19.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad5d8000207a264d1a55681a9276e6a739d3f05cf4429004ad00d61d1892235f"}, + {file = "scikit_image-0.19.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:84baa3179f3ae983c3a5d81c1e404bc92dcf7daeb41bfe9369badcda3fb22b92"}, + {file = "scikit_image-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f9f8a1387afc6c70f2bed007c3854a2d7489f9f7713c242f16f32ee05934bc2"}, + {file = "scikit_image-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:9fb0923a3bfa99457c5e17888f27b3b8a83a3600b4fef317992e7b7234764732"}, + {file = "scikit_image-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:ce3d2207f253b8eb2c824e30d145a9f07a34a14212d57f3beca9f7e03c383cbe"}, + {file = "scikit_image-0.19.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:2a02d1bd0e2b53e36b952bd5fd6118d9ccc3ee51de35705d63d8eb1f2e86adef"}, + {file = "scikit_image-0.19.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:03779a7e1736fdf89d83c0ba67d44110496edd736a3bfce61a2b5177a1c8a099"}, + {file = "scikit_image-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19a21a101a20c587a3b611a2cf6f86c35aae9f8d9563279b987e83ee1c9a9790"}, + {file = "scikit_image-0.19.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f50b923f8099c1045fcde7418d86b206c87e333e43da980f41d8577b9605245"}, + {file = "scikit_image-0.19.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e207c6ce5ce121d7d9b9d2b61b9adca57d1abed112c902d8ffbfdc20fb42c12b"}, + {file = "scikit_image-0.19.3-cp38-cp38-win32.whl", hash = "sha256:a7c3985c68bfe05f7571167ee021d14f5b8d1a4a250c91f0b13be7fb07e6af34"}, + {file = "scikit_image-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:651de1c2ce1fbee834753b46b8e7d81cb12a5594898babba63ac82b30ddad49d"}, + {file = "scikit_image-0.19.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:8d8917fcf85b987b1f287f823f3a1a7dac38b70aaca759bc0200f3bc292d5ced"}, + {file = "scikit_image-0.19.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:0b0a199157ce8487c77de4fde0edc0b42d6d42818881c11f459262351d678b2d"}, + {file = "scikit_image-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33dfd463ee6cc509defa279b963829f2230c9e0639ccd3931045be055878eea6"}, + {file = "scikit_image-0.19.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8714348ddd671f819457a797c97d4c672166f093def66d66c3254cbd1d43f83"}, + {file = "scikit_image-0.19.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff3b1025356508d41f4fe48528e509d95f9e4015e90cf158cd58c56dc63e0ac5"}, + {file = "scikit_image-0.19.3-cp39-cp39-win32.whl", hash = "sha256:9439e5294de3f18d6e82ec8eee2c46590231cf9c690da80545e83a0733b7a69e"}, + {file = "scikit_image-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:32fb88cc36203b99c9672fb972c9ef98635deaa5fc889fe969f3e11c44f22919"}, +] +scikit-learn = [ + {file = "scikit-learn-1.1.2.tar.gz", hash = "sha256:7c22d1305b16f08d57751a4ea36071e2215efb4c09cb79183faa4e8e82a3dbf8"}, + {file = "scikit_learn-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6c840f662b5d3377c4ccb8be1fc21bb52cb5d8b8790f8d6bf021739f84e543cf"}, + {file = "scikit_learn-1.1.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2b8db962360c93554cab7bb3c096c4a24695da394dd4b3c3f13409f409b425bc"}, + {file = "scikit_learn-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e7d1fc817867a350133f937aaebcafbc06192517cbdf0cf7e5774ad4d1adb9f"}, + {file = "scikit_learn-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec3ea40d467966821843210c02117d82b097b54276fdcfb50f4dfb5c60dbe39"}, + {file = "scikit_learn-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:bbef6ea1c012ff9f3e6f6e9ca006b8772d8383e177b898091e68fbd9b3f840f9"}, + {file = "scikit_learn-1.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a90ca42fe8242fd6ff56cda2fecc5fca586a88a24ab602d275d2d0dcc0b928fb"}, + {file = "scikit_learn-1.1.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a682ec0f82b6f30fb07486daed1c8001b6683cc66b51877644dfc532bece6a18"}, + {file = "scikit_learn-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c33e16e9a165af6012f5be530ccfbb672e2bc5f9b840238a05eb7f6694304e3f"}, + {file = "scikit_learn-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f94c0146bad51daef919c402a3da8c1c6162619653e1c00c92baa168fda292f2"}, + {file = "scikit_learn-1.1.2-cp38-cp38-win32.whl", hash = "sha256:2f46c6e3ff1054a5ec701646dcfd61d43b8ecac4d416014daed8843cf4c33d4d"}, + {file = "scikit_learn-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1e706deca9b2ad87ae27dafd5ac4e8eff01b6db492ed5c12cef4735ec5f21ea"}, + {file = "scikit_learn-1.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:567417dbbe6a6278399c3e6daf1654414a5a1a4d818d28f251fa7fc28730a1bf"}, + {file = "scikit_learn-1.1.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:d6f232779023c3b060b80b5c82e5823723bc424dcac1d1a148aa2492c54d245d"}, + {file = "scikit_learn-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:589d46f28460469f444b898223b13d99db9463e1038dc581ba698111f612264b"}, + {file = "scikit_learn-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76800652fb6d6bf527bce36ecc2cc25738b28fe1a17bd294a218fff8e8bd6d50"}, + {file = "scikit_learn-1.1.2-cp39-cp39-win32.whl", hash = "sha256:1c8fecb7c9984d9ec2ea48898229f98aad681a0873e0935f2b7f724fbce4a047"}, + {file = "scikit_learn-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:407e9a1cb9e6ba458a539986a9bd25546a757088095b3aab91d465b79a760d37"}, +] +scipy = [ + {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, + {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, + {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, + {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, + {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, + {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, + {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, +] +scons = [ + {file = "SCons-4.4.0-py3-none-any.whl", hash = "sha256:cbbd73b83cf85f1aaaf986370359de1bbfd3af97a765cb3554734f6dcec734e1"}, + {file = "SCons-4.4.0.tar.gz", hash = "sha256:7703c4e9d2200b4854a31800c1dbd4587e1fa86e75f58795c740bcfa7eca7eaa"}, +] +secretstorage = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] +segmentation-models-pytorch = [ + {file = "segmentation_models_pytorch-0.2.1-py3-none-any.whl", hash = "sha256:98822571470867fb0f416c112c32f7f1d21702dd32195ec8f7736932c2de0486"}, + {file = "segmentation_models_pytorch-0.2.1.tar.gz", hash = "sha256:86744552b04c6bedf7e10f7928791894d8d9b399b9ed58ed1a3236d2bf69ead6"}, +] +send2trash = [ + {file = "Send2Trash-1.8.0-py3-none-any.whl", hash = "sha256:f20eaadfdb517eaca5ce077640cb261c7d2698385a6a0f072a4a5447fd49fa08"}, + {file = "Send2Trash-1.8.0.tar.gz", hash = "sha256:d2c24762fd3759860a0aff155e45871447ea58d2be6bdd39b5c8f966a0c99c2d"}, +] +sentry-sdk = [ + {file = "sentry-sdk-1.10.0.tar.gz", hash = "sha256:1b965bcdbfe52321bb1307c7c93c74035afdbfceb5f585f01a963327c5befc4e"}, + {file = "sentry_sdk-1.10.0-py2.py3-none-any.whl", hash = "sha256:8c648e96e0e2ec5e17ca75a28c442e2f523453fa7cf761ec093f4a656153490e"}, +] +setproctitle = [ + {file = "setproctitle-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:288943dec88e178bb2fd868adf491197cc0fc8b6810416b1c6775e686bab87fe"}, + {file = "setproctitle-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:630f6fe5e24a619ccf970c78e084319ee8be5be253ecc9b5b216b0f474f5ef18"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c877691b90026670e5a70adfbcc735460a9f4c274d35ec5e8a43ce3f8443005"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a55fe05f15c10e8c705038777656fe45e3bd676d49ad9ac8370b75c66dd7cd7"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab45146c71ca6592c9cc8b354a2cc9cc4843c33efcbe1d245d7d37ce9696552d"}, + {file = "setproctitle-1.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:265ecbe2c6eafe82e104f994ddd7c811520acdd0647b73f65c24f51374cf9494"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c2c46200656280a064073447ebd363937562debef329482fd7e570c8d498f806"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:fa2f50678f04fda7a75d0fe5dd02bbdd3b13cbe6ed4cf626e4472a7ccf47ae94"}, + {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, + {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, + {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, + {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c8d9650154afaa86a44ff195b7b10d683c73509d085339d174e394a22cccbb9"}, + {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0452282258dfcc01697026a8841258dd2057c4438b43914b611bccbcd048f10"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e49ae693306d7624015f31cb3e82708916759d592c2e5f72a35c8f4cc8aef258"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1ff863a20d1ff6ba2c24e22436a3daa3cd80be1dfb26891aae73f61b54b04aca"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:55ce1e9925ce1765865442ede9dca0ba9bde10593fcd570b1f0fa25d3ec6b31c"}, + {file = "setproctitle-1.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7fe9df7aeb8c64db6c34fc3b13271a363475d77bc157d3f00275a53910cb1989"}, + {file = "setproctitle-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:e5c50e164cd2459bc5137c15288a9ef57160fd5cbf293265ea3c45efe7870865"}, + {file = "setproctitle-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a499fff50387c1520c085a07578a000123f519e5f3eee61dd68e1d301659651f"}, + {file = "setproctitle-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b932c3041aa924163f4aab970c2f0e6b4d9d773f4d50326e0ea1cd69240e5c5"}, + {file = "setproctitle-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4bfc89bd33ebb8e4c0e9846a09b1f5a4a86f5cb7a317e75cc42fee1131b4f4f"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd3cf4286a60fdc95451d8d14e0389a6b4f5cebe02c7f2609325eb016535963"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fb4f769c02f63fac90989711a3fee83919f47ae9afd4758ced5d86596318c65"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5194b4969f82ea842a4f6af2f82cd16ebdc3f1771fb2771796e6add9835c1973"}, + {file = "setproctitle-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cde41857a644b7353a0060b5f94f7ba7cf593ebde5a1094da1be581ac9a31"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9124bedd8006b0e04d4e8a71a0945da9b67e7a4ab88fdad7b1440dc5b6122c42"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8a09d570b39517de10ee5b718730e171251ce63bbb890c430c725c8c53d4484"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:8ff3c8cb26afaed25e8bca7b9dd0c1e36de71f35a3a0706b5c0d5172587a3827"}, + {file = "setproctitle-1.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:589be87172b238f839e19f146b9ea47c71e413e951ef0dc6db4218ddacf3c202"}, + {file = "setproctitle-1.3.2-cp38-cp38-win32.whl", hash = "sha256:4749a2b0c9ac52f864d13cee94546606f92b981b50e46226f7f830a56a9dc8e1"}, + {file = "setproctitle-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:e43f315c68aa61cbdef522a2272c5a5b9b8fd03c301d3167b5e1343ef50c676c"}, + {file = "setproctitle-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:de3a540cd1817ede31f530d20e6a4935bbc1b145fd8f8cf393903b1e02f1ae76"}, + {file = "setproctitle-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4058564195b975ddc3f0462375c533cce310ccdd41b80ac9aed641c296c3eff4"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c5d5dad7c28bdd1ec4187d818e43796f58a845aa892bb4481587010dc4d362b"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffc61a388a5834a97953d6444a2888c24a05f2e333f9ed49f977a87bb1ad4761"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fa1a0fbee72b47dc339c87c890d3c03a72ea65c061ade3204f285582f2da30f"}, + {file = "setproctitle-1.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8a988c7220c002c45347430993830666e55bc350179d91fcee0feafe64e1d4"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bae283e85fc084b18ffeb92e061ff7ac5af9e183c9d1345c93e178c3e5069cbe"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fed18e44711c5af4b681c2b3b18f85e6f0f1b2370a28854c645d636d5305ccd8"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:b34baef93bfb20a8ecb930e395ccd2ae3268050d8cf4fe187de5e2bd806fd796"}, + {file = "setproctitle-1.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7f0bed90a216ef28b9d227d8d73e28a8c9b88c0f48a082d13ab3fa83c581488f"}, + {file = "setproctitle-1.3.2-cp39-cp39-win32.whl", hash = "sha256:4d8938249a7cea45ab7e1e48b77685d0f2bab1ebfa9dde23e94ab97968996a7c"}, + {file = "setproctitle-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:a47d97a75fd2d10c37410b180f67a5835cb1d8fdea2648fd7f359d4277f180b9"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dad42e676c5261eb50fdb16bdf3e2771cf8f99a79ef69ba88729aeb3472d8575"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c91b9bc8985d00239f7dc08a49927a7ca1ca8a6af2c3890feec3ed9665b6f91e"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8579a43eafd246e285eb3a5b939e7158073d5087aacdd2308f23200eac2458b"}, + {file = "setproctitle-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:2fbd8187948284293f43533c150cd69a0e4192c83c377da837dbcd29f6b83084"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:faec934cfe5fd6ac1151c02e67156c3f526e82f96b24d550b5d51efa4a5527c6"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1aafc91cbdacc9e5fe712c52077369168e6b6c346f3a9d51bf600b53eae56bb"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b617f12c9be61e8f4b2857be4a4319754756845dbbbd9c3718f468bbb1e17bcb"}, + {file = "setproctitle-1.3.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b2c9cb2705fc84cb8798f1ba74194f4c080aaef19d9dae843591c09b97678e98"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a149a5f7f2c5a065d4e63cb0d7a4b6d3b66e6e80f12e3f8827c4f63974cbf122"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e3ac25bfc4a0f29d2409650c7532d5ddfdbf29f16f8a256fc31c47d0dc05172"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65d884e22037b23fa25b2baf1a3316602ed5c5971eb3e9d771a38c3a69ce6e13"}, + {file = "setproctitle-1.3.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7aa0aac1711fadffc1d51e9d00a3bea61f68443d6ac0241a224e4d622489d665"}, + {file = "setproctitle-1.3.2.tar.gz", hash = "sha256:b9fb97907c830d260fa0658ed58afd48a86b2b88aac521135c352ff7fd3477fd"}, +] +setuptools = [ + {file = "setuptools-65.5.0-py3-none-any.whl", hash = "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"}, + {file = "setuptools-65.5.0.tar.gz", hash = "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17"}, +] +setuptools-scm = [ + {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"}, + {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"}, +] +shellingham = [ + {file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"}, + {file = "shellingham-1.5.0.tar.gz", hash = "sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad"}, +] +simplejson = [ + {file = "simplejson-3.17.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a89acae02b2975b1f8e4974cb8cdf9bf9f6c91162fb8dec50c259ce700f2770a"}, + {file = "simplejson-3.17.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:82ff356ff91be0ab2293fc6d8d262451eb6ac4fd999244c4b5f863e049ba219c"}, + {file = "simplejson-3.17.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:0de783e9c2b87bdd75b57efa2b6260c24b94605b5c9843517577d40ee0c3cc8a"}, + {file = "simplejson-3.17.6-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:d24a9e61df7a7787b338a58abfba975414937b609eb6b18973e25f573bc0eeeb"}, + {file = "simplejson-3.17.6-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:e8603e691580487f11306ecb066c76f1f4a8b54fb3bdb23fa40643a059509366"}, + {file = "simplejson-3.17.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9b01e7b00654115965a206e3015f0166674ec1e575198a62a977355597c0bef5"}, + {file = "simplejson-3.17.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:37bc0cf0e5599f36072077e56e248f3336917ded1d33d2688624d8ed3cefd7d2"}, + {file = "simplejson-3.17.6-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:cf6e7d5fe2aeb54898df18db1baf479863eae581cce05410f61f6b4188c8ada1"}, + {file = "simplejson-3.17.6-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:bdfc54b4468ed4cd7415928cbe782f4d782722a81aeb0f81e2ddca9932632211"}, + {file = "simplejson-3.17.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd16302d39c4d6f4afde80edd0c97d4db643327d355a312762ccd9bd2ca515ed"}, + {file = "simplejson-3.17.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:deac4bdafa19bbb89edfb73b19f7f69a52d0b5bd3bb0c4ad404c1bbfd7b4b7fd"}, + {file = "simplejson-3.17.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8bbdb166e2fb816e43ab034c865147edafe28e1b19c72433147789ac83e2dda"}, + {file = "simplejson-3.17.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7854326920d41c3b5d468154318fe6ba4390cb2410480976787c640707e0180"}, + {file = "simplejson-3.17.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:04e31fa6ac8e326480703fb6ded1488bfa6f1d3f760d32e29dbf66d0838982ce"}, + {file = "simplejson-3.17.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f63600ec06982cdf480899026f4fda622776f5fabed9a869fdb32d72bc17e99a"}, + {file = "simplejson-3.17.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e03c3b8cc7883a54c3f34a6a135c4a17bc9088a33f36796acdb47162791b02f6"}, + {file = "simplejson-3.17.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a2d30d6c1652140181dc6861f564449ad71a45e4f165a6868c27d36745b65d40"}, + {file = "simplejson-3.17.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a1aa6e4cae8e3b8d5321be4f51c5ce77188faf7baa9fe1e78611f93a8eed2882"}, + {file = "simplejson-3.17.6-cp310-cp310-win32.whl", hash = "sha256:97202f939c3ff341fc3fa84d15db86156b1edc669424ba20b0a1fcd4a796a045"}, + {file = "simplejson-3.17.6-cp310-cp310-win_amd64.whl", hash = "sha256:80d3bc9944be1d73e5b1726c3bbfd2628d3d7fe2880711b1eb90b617b9b8ac70"}, + {file = "simplejson-3.17.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9fa621b3c0c05d965882c920347b6593751b7ab20d8fa81e426f1735ca1a9fc7"}, + {file = "simplejson-3.17.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2fb11922f58df8528adfca123f6a84748ad17d066007e7ac977720063556bd"}, + {file = "simplejson-3.17.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:724c1fe135aa437d5126138d977004d165a3b5e2ee98fc4eb3e7c0ef645e7e27"}, + {file = "simplejson-3.17.6-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4ff4ac6ff3aa8f814ac0f50bf218a2e1a434a17aafad4f0400a57a8cc62ef17f"}, + {file = "simplejson-3.17.6-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:67093a526e42981fdd954868062e56c9b67fdd7e712616cc3265ad0c210ecb51"}, + {file = "simplejson-3.17.6-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b4af7ad7e4ac515bc6e602e7b79e2204e25dbd10ab3aa2beef3c5a9cad2c7"}, + {file = "simplejson-3.17.6-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:1c9b1ed7ed282b36571638297525f8ef80f34b3e2d600a56f962c6044f24200d"}, + {file = "simplejson-3.17.6-cp36-cp36m-win32.whl", hash = "sha256:632ecbbd2228575e6860c9e49ea3cc5423764d5aa70b92acc4e74096fb434044"}, + {file = "simplejson-3.17.6-cp36-cp36m-win_amd64.whl", hash = "sha256:4c09868ddb86bf79b1feb4e3e7e4a35cd6e61ddb3452b54e20cf296313622566"}, + {file = "simplejson-3.17.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b6bd8144f15a491c662f06814bd8eaa54b17f26095bb775411f39bacaf66837"}, + {file = "simplejson-3.17.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5decdc78849617917c206b01e9fc1d694fd58caa961be816cb37d3150d613d9a"}, + {file = "simplejson-3.17.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:521877c7bd060470806eb6335926e27453d740ac1958eaf0d8c00911bc5e1802"}, + {file = "simplejson-3.17.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:65b998193bd7b0c7ecdfffbc825d808eac66279313cb67d8892bb259c9d91494"}, + {file = "simplejson-3.17.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ac786f6cb7aa10d44e9641c7a7d16d7f6e095b138795cd43503769d4154e0dc2"}, + {file = "simplejson-3.17.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3ff5b3464e1ce86a8de8c88e61d4836927d5595c2162cab22e96ff551b916e81"}, + {file = "simplejson-3.17.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:69bd56b1d257a91e763256d63606937ae4eb890b18a789b66951c00062afec33"}, + {file = "simplejson-3.17.6-cp37-cp37m-win32.whl", hash = "sha256:b81076552d34c27e5149a40187a8f7e2abb2d3185576a317aaf14aeeedad862a"}, + {file = "simplejson-3.17.6-cp37-cp37m-win_amd64.whl", hash = "sha256:07ecaafc1b1501f275bf5acdee34a4ad33c7c24ede287183ea77a02dc071e0c0"}, + {file = "simplejson-3.17.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:068670af975247acbb9fc3d5393293368cda17026db467bf7a51548ee8f17ee1"}, + {file = "simplejson-3.17.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4d1c135af0c72cb28dd259cf7ba218338f4dc027061262e46fe058b4e6a4c6a3"}, + {file = "simplejson-3.17.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23fe704da910ff45e72543cbba152821685a889cf00fc58d5c8ee96a9bad5f94"}, + {file = "simplejson-3.17.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f444762fed1bc1fd75187ef14a20ed900c1fbb245d45be9e834b822a0223bc81"}, + {file = "simplejson-3.17.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:681eb4d37c9a9a6eb9b3245a5e89d7f7b2b9895590bb08a20aa598c1eb0a1d9d"}, + {file = "simplejson-3.17.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8e8607d8f6b4f9d46fee11447e334d6ab50e993dd4dbfb22f674616ce20907ab"}, + {file = "simplejson-3.17.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b10556817f09d46d420edd982dd0653940b90151d0576f09143a8e773459f6fe"}, + {file = "simplejson-3.17.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e1ec8a9ee0987d4524ffd6299e778c16cc35fef6d1a2764e609f90962f0b293a"}, + {file = "simplejson-3.17.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b4126cac7d69ac06ff22efd3e0b3328a4a70624fcd6bca4fc1b4e6d9e2e12bf"}, + {file = "simplejson-3.17.6-cp38-cp38-win32.whl", hash = "sha256:35a49ebef25f1ebdef54262e54ae80904d8692367a9f208cdfbc38dbf649e00a"}, + {file = "simplejson-3.17.6-cp38-cp38-win_amd64.whl", hash = "sha256:743cd768affaa508a21499f4858c5b824ffa2e1394ed94eb85caf47ac0732198"}, + {file = "simplejson-3.17.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fb62d517a516128bacf08cb6a86ecd39fb06d08e7c4980251f5d5601d29989ba"}, + {file = "simplejson-3.17.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:12133863178a8080a3dccbf5cb2edfab0001bc41e5d6d2446af2a1131105adfe"}, + {file = "simplejson-3.17.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5540fba2d437edaf4aa4fbb80f43f42a8334206ad1ad3b27aef577fd989f20d9"}, + {file = "simplejson-3.17.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d74ee72b5071818a1a5dab47338e87f08a738cb938a3b0653b9e4d959ddd1fd9"}, + {file = "simplejson-3.17.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:28221620f4dcabdeac310846629b976e599a13f59abb21616356a85231ebd6ad"}, + {file = "simplejson-3.17.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b09bc62e5193e31d7f9876220fb429ec13a6a181a24d897b9edfbbdbcd678851"}, + {file = "simplejson-3.17.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7255a37ff50593c9b2f1afa8fafd6ef5763213c1ed5a9e2c6f5b9cc925ab979f"}, + {file = "simplejson-3.17.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:401d40969cee3df7bda211e57b903a534561b77a7ade0dd622a8d1a31eaa8ba7"}, + {file = "simplejson-3.17.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a649d0f66029c7eb67042b15374bd93a26aae202591d9afd71e111dd0006b198"}, + {file = "simplejson-3.17.6-cp39-cp39-win32.whl", hash = "sha256:522fad7be85de57430d6d287c4b635813932946ebf41b913fe7e880d154ade2e"}, + {file = "simplejson-3.17.6-cp39-cp39-win_amd64.whl", hash = "sha256:3fe87570168b2ae018391e2b43fbf66e8593a86feccb4b0500d134c998983ccc"}, + {file = "simplejson-3.17.6.tar.gz", hash = "sha256:cf98038d2abf63a1ada5730e91e84c642ba6c225b0198c3684151b1f80c5f8a6"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +smbus2 = [ + {file = "smbus2-0.4.2-py2.py3-none-any.whl", hash = "sha256:50f3c78e436b42a9583948be06961a8104cf020ebad5edfaaf2657528bef0818"}, + {file = "smbus2-0.4.2.tar.gz", hash = "sha256:634541ed794068a822fe7499f1577468b9d4641b68dd9bfb6d0eb7270f4d2a32"}, +] +sniffio = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] +sortedcontainers = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] +soupsieve = [ + {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"}, + {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, +] +sphinx = [ + {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, + {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, +] +sphinx-rtd-theme = [ + {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, + {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, +] +sphinx-sitemap = [ + {file = "sphinx-sitemap-2.2.0.tar.gz", hash = "sha256:65adda39233cb17c0da10ba1cebaa2df73e271cdb6f8efd5cec8eef3b3cf7737"}, +] +sphinxcontrib-applehelp = [ + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, +] +sphinxcontrib-devhelp = [ + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, +] +sphinxcontrib-htmlhelp = [ + {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, + {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, +] +sphinxcontrib-jsmath = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] +sphinxcontrib-qthelp = [ + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, +] +sphinxcontrib-serializinghtml = [ + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, +] +sqlalchemy = [ + {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-win32.whl", hash = "sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27m-win_amd64.whl", hash = "sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc"}, + {file = "SQLAlchemy-1.4.42-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-win32.whl", hash = "sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565"}, + {file = "SQLAlchemy-1.4.42-cp310-cp310-win_amd64.whl", hash = "sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-win32.whl", hash = "sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516"}, + {file = "SQLAlchemy-1.4.42-cp311-cp311-win_amd64.whl", hash = "sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-win32.whl", hash = "sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde"}, + {file = "SQLAlchemy-1.4.42-cp36-cp36m-win_amd64.whl", hash = "sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-win32.whl", hash = "sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565"}, + {file = "SQLAlchemy-1.4.42-cp37-cp37m-win_amd64.whl", hash = "sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-win32.whl", hash = "sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471"}, + {file = "SQLAlchemy-1.4.42-cp38-cp38-win_amd64.whl", hash = "sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-win32.whl", hash = "sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a"}, + {file = "SQLAlchemy-1.4.42-cp39-cp39-win_amd64.whl", hash = "sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934"}, + {file = "SQLAlchemy-1.4.42.tar.gz", hash = "sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363"}, +] +stack-data = [ + {file = "stack_data-0.5.1-py3-none-any.whl", hash = "sha256:5120731a18ba4c82cefcf84a945f6f3e62319ef413bfc210e32aca3a69310ba2"}, + {file = "stack_data-0.5.1.tar.gz", hash = "sha256:95eb784942e861a3d80efd549ff9af6cf847d88343a12eb681d7157cfcb6e32b"}, +] +subprocess32 = [ + {file = "subprocess32-3.5.4-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b"}, + {file = "subprocess32-3.5.4-cp27-cp27mu-manylinux2014_x86_64.whl", hash = "sha256:e45d985aef903c5b7444d34350b05da91a9e0ea015415ab45a21212786c649d0"}, + {file = "subprocess32-3.5.4.tar.gz", hash = "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d"}, +] +sympy = [ + {file = "sympy-1.11.1-py3-none-any.whl", hash = "sha256:938f984ee2b1e8eae8a07b884c8b7a1146010040fccddc6539c54f401c8f6fcf"}, + {file = "sympy-1.11.1.tar.gz", hash = "sha256:e32380dce63cb7c0108ed525570092fd45168bdae2faa17e528221ef72e88658"}, +] +tabulate = [ + {file = "tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc"}, + {file = "tabulate-0.8.10.tar.gz", hash = "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519"}, +] +tenacity = [ + {file = "tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac"}, + {file = "tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445"}, +] +terminado = [ + {file = "terminado-0.16.0-py3-none-any.whl", hash = "sha256:3e995072a7178a104c41134548ce9b03e4e7f0a538e9c29df4f1fbc81c7cfc75"}, + {file = "terminado-0.16.0.tar.gz", hash = "sha256:fac14374eb5498bdc157ed32e510b1f60d5c3c7981a9f5ba018bb9a64cec0c25"}, +] +threadpoolctl = [ + {file = "threadpoolctl-3.1.0-py3-none-any.whl", hash = "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b"}, + {file = "threadpoolctl-3.1.0.tar.gz", hash = "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380"}, +] +tifffile = [ + {file = "tifffile-2022.10.10-py3-none-any.whl", hash = "sha256:87f3aee8a0d06b74655269a105de75c1958a24653e1930d523eb516100043503"}, + {file = "tifffile-2022.10.10.tar.gz", hash = "sha256:50b61ba943b866d191295bc38a00191c9fdab23ece063544c7f1a264e3f6aa8e"}, +] +timezonefinder = [ + {file = "timezonefinder-6.1.3-cp38-cp38-manylinux_2_31_x86_64.whl", hash = "sha256:96c96db94e75e072187843152e6c5dc0718500a9a91986032365abe09162d0e7"}, + {file = "timezonefinder-6.1.3.tar.gz", hash = "sha256:f2ee561b1e7692b933fcd914df38800e93db7caf278e7328de7328829b04f275"}, +] +timm = [ + {file = "timm-0.4.12-py3-none-any.whl", hash = "sha256:dba6b1702b7d24bf9f0f1c2fc394b4ee28f93cde5404f1dc732d63ccd00533b6"}, + {file = "timm-0.4.12.tar.gz", hash = "sha256:b14be70dbd4528b5ca8657cf5bc2672c7918c3d9ebfbffe80f4785b54e884b1e"}, +] +tinycss2 = [ + {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, + {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +tomlkit = [ + {file = "tomlkit-0.11.5-py3-none-any.whl", hash = "sha256:f2ef9da9cef846ee027947dc99a45d6b68a63b0ebc21944649505bf2e8bc5fe7"}, + {file = "tomlkit-0.11.5.tar.gz", hash = "sha256:571854ebbb5eac89abcb4a2e47d7ea27b89bf29e09c35395da6f03dd4ae23d1c"}, +] +torch = [] +torchsummary = [ + {file = "torchsummary-1.5.1-py3-none-any.whl", hash = "sha256:10f41d1743fb918f83293f13183f532ab1bb8f6639a1b89e5f8592ec1919a976"}, + {file = "torchsummary-1.5.1.tar.gz", hash = "sha256:981bf689e22e0cf7f95c746002f20a24ad26aa6b9d861134a14bc6ce92230590"}, +] +torchvision = [] +tornado = [ + {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"}, + {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"}, + {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"}, + {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"}, + {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"}, + {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"}, + {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"}, + {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"}, + {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"}, + {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"}, + {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, +] +tqdm = [ + {file = "tqdm-4.64.1-py2.py3-none-any.whl", hash = "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"}, + {file = "tqdm-4.64.1.tar.gz", hash = "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4"}, +] +traitlets = [ + {file = "traitlets-5.5.0-py3-none-any.whl", hash = "sha256:1201b2c9f76097195989cdf7f65db9897593b0dfd69e4ac96016661bb6f0d30f"}, + {file = "traitlets-5.5.0.tar.gz", hash = "sha256:b122f9ff2f2f6c1709dab289a05555be011c87828e911c0cf4074b85cb780a79"}, +] +triton = [ + {file = "triton-1.1.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8441e6f44517aef8f6345f621c003926cbe970892802411a949ccda516cbd5ba"}, + {file = "triton-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840776bc1f4757fb2d6af974694c5e5313220ceec238ee6118b9728bc2aa9ade"}, + {file = "triton-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d42cdaa7d56de463d762c18cc876bfd0828a2b6a706263393fe7e10d1c83ca"}, + {file = "triton-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc19c0e902bbf7d29de4d444455608065a2c56e3524f4bc94e724511ca518f3"}, + {file = "triton-1.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02f798cd2dd922228082ce1a4e9d81badb9a6217a9aac6d783e95bf7055974d"}, +] +types-atomicwrites = [ + {file = "types-atomicwrites-1.4.5.1.tar.gz", hash = "sha256:9e9f0923ebf93524b28bcece5a23ac8c3820f39b060df29f671936d2e4bc04bc"}, + {file = "types_atomicwrites-1.4.5.1-py3-none-any.whl", hash = "sha256:2f1febbdc78b55453b189fa5b136dce34bab7d1d82319163d470e404aab55c83"}, +] +types-certifi = [ + {file = "types-certifi-2021.10.8.3.tar.gz", hash = "sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f"}, + {file = "types_certifi-2021.10.8.3-py3-none-any.whl", hash = "sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a"}, +] +types-pycurl = [ + {file = "types-pycurl-7.45.1.tar.gz", hash = "sha256:82e00aa2981595bfa55e5a3bac42221eb3435b0026dffbe1177f6ac9f2d51200"}, + {file = "types_pycurl-7.45.1-py3-none-any.whl", hash = "sha256:9eab3414da4a1b1e9a628bd288fc5172b8c182e1d9fb6d8d082441b0fd64baed"}, +] +types-pyyaml = [ + {file = "types-PyYAML-6.0.12.tar.gz", hash = "sha256:f6f350418125872f3f0409d96a62a5a5ceb45231af5cc07ee0034ec48a3c82fa"}, + {file = "types_PyYAML-6.0.12-py3-none-any.whl", hash = "sha256:29228db9f82df4f1b7febee06bbfb601677882e98a3da98132e31c6874163e15"}, +] +types-requests = [ + {file = "types-requests-2.28.11.2.tar.gz", hash = "sha256:fdcd7bd148139fb8eef72cf4a41ac7273872cad9e6ada14b11ff5dfdeee60ed3"}, + {file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"}, +] +types-urllib3 = [ + {file = "types-urllib3-1.26.25.1.tar.gz", hash = "sha256:a948584944b2412c9a74b9cf64f6c48caf8652cb88b38361316f6d15d8a184cd"}, + {file = "types_urllib3-1.26.25.1-py3-none-any.whl", hash = "sha256:f6422596cc9ee5fdf68f9d547f541096a20c2dcfd587e37c804c9ea720bf5cb2"}, +] +typing-extensions = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, +] +utm = [ + {file = "utm-0.7.0.tar.gz", hash = "sha256:3c9a3650e98bb6eecec535418d0dfd4db8f88c8ceaca112a0ff0787e116566e2"}, +] +virtualenv = [ + {file = "virtualenv-20.16.5-py3-none-any.whl", hash = "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"}, + {file = "virtualenv-20.16.5.tar.gz", hash = "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da"}, +] +virtualenv-clone = [ + {file = "virtualenv-clone-0.5.7.tar.gz", hash = "sha256:418ee935c36152f8f153c79824bb93eaf6f0f7984bae31d3f48f350b9183501a"}, + {file = "virtualenv_clone-0.5.7-py3-none-any.whl", hash = "sha256:44d5263bceed0bac3e1424d64f798095233b64def1c5689afa43dc3223caf5b0"}, +] +wcwidth = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] +webencodings = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] +websocket-client = [ + {file = "websocket-client-1.4.1.tar.gz", hash = "sha256:f9611eb65c8241a67fb373bef040b3cf8ad377a9f6546a12b620b6511e8ea9ef"}, + {file = "websocket_client-1.4.1-py3-none-any.whl", hash = "sha256:398909eb7e261f44b8f4bd474785b6ec5f5b499d4953342fe9755e01ef624090"}, +] +werkzeug = [ + {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, + {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, +] +widgetsnbextension = [ + {file = "widgetsnbextension-4.0.3-py3-none-any.whl", hash = "sha256:7f3b0de8fda692d31ef03743b598620e31c2668b835edbd3962d080ccecf31eb"}, + {file = "widgetsnbextension-4.0.3.tar.gz", hash = "sha256:34824864c062b0b3030ad78210db5ae6a3960dfb61d5b27562d6631774de0286"}, +] +wrapt = [ + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +] +xattr = [ + {file = "xattr-0.9.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:58a9fb4fd19b467e88f4b75b5243706caa57e312d3aee757b53b57c7fd0f4ba9"}, + {file = "xattr-0.9.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e71efca59705c7abde5b7f76323ebe00ed2977f10cba4204b9421dada036b5ca"}, + {file = "xattr-0.9.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:1aad96b6603961c3d1ca1aaa8369b1a8d684a7b37357b2428087c286bf0e561c"}, + {file = "xattr-0.9.9-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:46cb74f98d31d9d70f975ec3e6554360a9bdcbb4b9fb50a69fabe54f9f928c97"}, + {file = "xattr-0.9.9-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:80c2db56058a687d7439be041f916cbeb2943fbe2623e53d5da721a4552d8991"}, + {file = "xattr-0.9.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c360d1cc42e885b64d84f64de3c501dd7bce576248327ef583b4625ee63aa023"}, + {file = "xattr-0.9.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:debd87afe6bdf88c3689bde52eecf2b166388b13ef7388259d23223374db417d"}, + {file = "xattr-0.9.9-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:4280c9f33a8678828f1bbc3d3dc8b823b5e4a113ee5ecb0fb98bff60cc2b9ad1"}, + {file = "xattr-0.9.9-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:e0916ec1656d2071cd3139d1f52426825985d8ed076f981ef7f0bc13dfa8e96c"}, + {file = "xattr-0.9.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a517916fbf2f58a3222bb2048fe1eeff4e23e07a4ce6228a27de004c80bf53ab"}, + {file = "xattr-0.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e886c882b3b28c7a684c3e3daf46347da5428a46b88bc6d62c4867d574b90c54"}, + {file = "xattr-0.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:373e3d1fd9258438fc38d1438142d3659f36743f374a20457346ef26741ed441"}, + {file = "xattr-0.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7beeb54ca140273b2f6320bb98b701ec30628af2ebe4eb30f7051419eb4ef3"}, + {file = "xattr-0.9.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3ca29cdaae9c47c625d84bb6c9046f7275cccde0ea805caa23ca58d3671f3f"}, + {file = "xattr-0.9.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c381d890931cd18b137ce3fb5c5f08b672c3c61e2e47b1a7442ee46e827abfe"}, + {file = "xattr-0.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:59c5783ccf57cf2700ce57d51a92134900ed26f6ab20d209f383fb898903fea6"}, + {file = "xattr-0.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:966b885b69d95362e2a12d39f84889cf857090e57263b5ac33409498aa00c160"}, + {file = "xattr-0.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efaaf0cb1ea8e9febb7baad301ae8cc9ad7a96fdfc5c6399d165e7a19e3e61ce"}, + {file = "xattr-0.9.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f19fa75ed1e9db86354efab29869cb2be6976d456bd7c89e67b118d5384a1d98"}, + {file = "xattr-0.9.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ca28ad06828244b315214ee35388f57e81e90aac2ceac3f32e42ae394e31b9c"}, + {file = "xattr-0.9.9-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:532c7f1656dd2fe937116b9e210229f716d7fc7ac142f9cdace7da92266d32e8"}, + {file = "xattr-0.9.9-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11c28033c17e98c67e0def9d6ebd415ad3c006a7bc3fee6bad79c5e52d0dff49"}, + {file = "xattr-0.9.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:473cabb30e544ea08c8c01c1ef18053147cdc8552d443ac97815e46fbb13c7d4"}, + {file = "xattr-0.9.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c4a308522b444d090fbd66a385c9519b6b977818226921b0d2fc403667c93564"}, + {file = "xattr-0.9.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:82493434488aca72d88b5129dac8f212e7b8bdca7ceffe7bb977c850f2452e4e"}, + {file = "xattr-0.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e41d289706c7e8940f4d08e865da6a8ae988123e40a44f9a97ddc09e67795d7d"}, + {file = "xattr-0.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef08698e360cf43688dca3db3421b156b29948a714d5d089348073f463c11646"}, + {file = "xattr-0.9.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4eb10ac16ca8d534c0395425d52121e0c1981f808e1b3f577f6a5ec33d3853e4"}, + {file = "xattr-0.9.9-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5605fec07b0e964bd980cc70ec335b9eb1b7ac7c6f314c7c2d8f54b09104fe4c"}, + {file = "xattr-0.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:974e7d577ddb15e4552fb0ec10a4cfe09bdf6267365aa2b8394bb04637785aad"}, + {file = "xattr-0.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ad6777de922c638bfa87a0d7faebc5722ddef04a1210b2a8909289b58b769af0"}, + {file = "xattr-0.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3887e70873ebf0efbde32f9929ec1c7e45ec0013561743e2cc0406a91e51113b"}, + {file = "xattr-0.9.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:83caa8e93a45a0f25f91b92d9b45f490c87bff74f02555df6312efeba0dacc31"}, + {file = "xattr-0.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e33ec0a1d913d946d1ab7509f37ee37306c45af735347f13b963df34ffe6e029"}, + {file = "xattr-0.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:263c58dca83372260c5c195e0b59959e38e1f107f0b7350de82e3db38479036c"}, + {file = "xattr-0.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:125dfb9905428162349d3b8b825d9a18280893f0cb0db2a2467d5ef253fa6ce2"}, + {file = "xattr-0.9.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e243524e0dde16d7a2e1b52512ad2c6964df2143dd1c79b820dcb4c6c0822c20"}, + {file = "xattr-0.9.9-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ec07d24a14406bdc6a123041c63a88e1c4a3f820e4a7d30f7609d57311b499"}, + {file = "xattr-0.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85c1df5f1d209345ea96de137419e886a27bb55076b3ae01faacf35aafcf3a61"}, + {file = "xattr-0.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ca74d3eff92d6dc16e271fbad9cbab547fb9a0c983189c4031c3ff3d150dd871"}, + {file = "xattr-0.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7d17505e49ac70c0e71939c5aac96417a863583fb30a2d6304d5ac881230548f"}, + {file = "xattr-0.9.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ae47a6398d3c04623fa386a4aa2f66e5cd3cdb1a7e69d1bfaeb8c73983bf271"}, + {file = "xattr-0.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:809e2537d0aff9fca97dacf3245cbbaf711bbced5d1b0235a8d1906b04e26114"}, + {file = "xattr-0.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de3af84364f06d67b3662ccf7c1a73e1d389d8d274394e952651e7bf1bbd2718"}, + {file = "xattr-0.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b62cdad232d2d2dedd39b543701db8e3883444ec0d57ce3fab8f75e5f8b0301"}, + {file = "xattr-0.9.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b11d2eda397d47f7075743409683c233519ca52aa1dac109b413a4d8c15b740"}, + {file = "xattr-0.9.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661c0a939aefdf071887121f534bb10588d69c7b2dfca5c486af2fc81a0786e8"}, + {file = "xattr-0.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5db7c2db320a8d5264d437d71f1eb7270a7e4a6545296e7766161d17752590b7"}, + {file = "xattr-0.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:83203e60cbaca9536d297e5039b285a600ff84e6e9e8536fe2d521825eeeb437"}, + {file = "xattr-0.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42bfb4e4da06477e739770ac6942edbdc71e9fc3b497b67db5fba712fa8109c2"}, + {file = "xattr-0.9.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:67047d04d1c56ad4f0f5886085e91b0077238ab3faaec6492c3c21920c6566eb"}, + {file = "xattr-0.9.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:885782bc82ded1a3f684d54a1af259ae9fcc347fa54b5a05b8aad82b8a42044c"}, + {file = "xattr-0.9.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bc84ccec618b5aa089e7cee8b07fcc92d4069aac4053da604c8143a0d6b1381"}, + {file = "xattr-0.9.9-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baeff3e5dda8ea7e9424cfaee51829f46afe3836c30d02f343f9049c685681ca"}, + {file = "xattr-0.9.9.tar.gz", hash = "sha256:09cb7e1efb3aa1b4991d6be4eb25b73dc518b4fe894f0915f5b0dcede972f346"}, +] +yarl = [ + {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"}, + {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"}, + {file = "yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"}, + {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ec362167e2c9fd178f82f252b6d97669d7245695dc057ee182118042026da40"}, + {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20df6ff4089bc86e4a66e3b1380460f864df3dd9dccaf88d6b3385d24405893b"}, + {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5999c4662631cb798496535afbd837a102859568adc67d75d2045e31ec3ac497"}, + {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed19b74e81b10b592084a5ad1e70f845f0aacb57577018d31de064e71ffa267a"}, + {file = "yarl-1.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4808f996ca39a6463f45182e2af2fae55e2560be586d447ce8016f389f626f"}, + {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d800b9c2eaf0684c08be5f50e52bfa2aa920e7163c2ea43f4f431e829b4f0fd"}, + {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6628d750041550c5d9da50bb40b5cf28a2e63b9388bac10fedd4f19236ef4957"}, + {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f5af52738e225fcc526ae64071b7e5342abe03f42e0e8918227b38c9aa711e28"}, + {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:76577f13333b4fe345c3704811ac7509b31499132ff0181f25ee26619de2c843"}, + {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c03f456522d1ec815893d85fccb5def01ffaa74c1b16ff30f8aaa03eb21e453"}, + {file = "yarl-1.8.1-cp310-cp310-win32.whl", hash = "sha256:ea30a42dc94d42f2ba4d0f7c0ffb4f4f9baa1b23045910c0c32df9c9902cb272"}, + {file = "yarl-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9130ddf1ae9978abe63808b6b60a897e41fccb834408cde79522feb37fb72fb0"}, + {file = "yarl-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0ab5a138211c1c366404d912824bdcf5545ccba5b3ff52c42c4af4cbdc2c5035"}, + {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0fb2cb4204ddb456a8e32381f9a90000429489a25f64e817e6ff94879d432fc"}, + {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"}, + {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca7e596c55bd675432b11320b4eacc62310c2145d6801a1f8e9ad160685a231"}, + {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f77539733e0ec2475ddcd4e26777d08996f8cd55d2aef82ec4d3896687abda"}, + {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e256649f42771829974e742061c3501cc50cf16e63f91ed8d1bf98242e5507"}, + {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7fce6cbc6c170ede0221cc8c91b285f7f3c8b9fe28283b51885ff621bbe0f8ee"}, + {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:59ddd85a1214862ce7c7c66457f05543b6a275b70a65de366030d56159a979f0"}, + {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:12768232751689c1a89b0376a96a32bc7633c08da45ad985d0c49ede691f5c0d"}, + {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b19255dde4b4f4c32e012038f2c169bb72e7f081552bea4641cab4d88bc409dd"}, + {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6c8148e0b52bf9535c40c48faebb00cb294ee577ca069d21bd5c48d302a83780"}, + {file = "yarl-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:de839c3a1826a909fdbfe05f6fe2167c4ab033f1133757b5936efe2f84904c07"}, + {file = "yarl-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:dd032e8422a52e5a4860e062eb84ac94ea08861d334a4bcaf142a63ce8ad4802"}, + {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19cd801d6f983918a3f3a39f3a45b553c015c5aac92ccd1fac619bd74beece4a"}, + {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6347f1a58e658b97b0a0d1ff7658a03cb79bdbda0331603bed24dd7054a6dea1"}, + {file = "yarl-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c0da7e44d0c9108d8b98469338705e07f4bb7dab96dbd8fa4e91b337db42548"}, + {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5587bba41399854703212b87071c6d8638fa6e61656385875f8c6dff92b2e461"}, + {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31a9a04ecccd6b03e2b0e12e82131f1488dea5555a13a4d32f064e22a6003cfe"}, + {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205904cffd69ae972a1707a1bd3ea7cded594b1d773a0ce66714edf17833cdae"}, + {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea513a25976d21733bff523e0ca836ef1679630ef4ad22d46987d04b372d57fc"}, + {file = "yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"}, + {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2b8f245dad9e331540c350285910b20dd913dc86d4ee410c11d48523c4fd546"}, + {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ab2a60d57ca88e1d4ca34a10e9fb4ab2ac5ad315543351de3a612bbb0560bead"}, + {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:449c957ffc6bc2309e1fbe67ab7d2c1efca89d3f4912baeb8ead207bb3cc1cd4"}, + {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a165442348c211b5dea67c0206fc61366212d7082ba8118c8c5c1c853ea4d82e"}, + {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b3ded839a5c5608eec8b6f9ae9a62cb22cd037ea97c627f38ae0841a48f09eae"}, + {file = "yarl-1.8.1-cp38-cp38-win32.whl", hash = "sha256:c1445a0c562ed561d06d8cbc5c8916c6008a31c60bc3655cdd2de1d3bf5174a0"}, + {file = "yarl-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:56c11efb0a89700987d05597b08a1efcd78d74c52febe530126785e1b1a285f4"}, + {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e80ed5a9939ceb6fda42811542f31c8602be336b1fb977bccb012e83da7e4936"}, + {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6afb336e23a793cd3b6476c30f030a0d4c7539cd81649683b5e0c1b0ab0bf350"}, + {file = "yarl-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c322cbaa4ed78a8aac89b2174a6df398faf50e5fc12c4c191c40c59d5e28357"}, + {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fae37373155f5ef9b403ab48af5136ae9851151f7aacd9926251ab26b953118b"}, + {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5395da939ffa959974577eff2cbfc24b004a2fb6c346918f39966a5786874e54"}, + {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:076eede537ab978b605f41db79a56cad2e7efeea2aa6e0fa8f05a26c24a034fb"}, + {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1a50e461615747dd93c099f297c1994d472b0f4d2db8a64e55b1edf704ec1c"}, + {file = "yarl-1.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7de89c8456525650ffa2bb56a3eee6af891e98f498babd43ae307bd42dca98f6"}, + {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a88510731cd8d4befaba5fbd734a7dd914de5ab8132a5b3dde0bbd6c9476c64"}, + {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"}, + {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:21ac44b763e0eec15746a3d440f5e09ad2ecc8b5f6dcd3ea8cb4773d6d4703e3"}, + {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0272228fabe78ce00a3365ffffd6f643f57a91043e119c289aaba202f4095b0"}, + {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99449cd5366fe4608e7226c6cae80873296dfa0cde45d9b498fefa1de315a09e"}, + {file = "yarl-1.8.1-cp39-cp39-win32.whl", hash = "sha256:8b0af1cf36b93cee99a31a545fe91d08223e64390c5ecc5e94c39511832a4bb6"}, + {file = "yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"}, + {file = "yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"}, +] +zerorpc = [] +zipp = [ + {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, + {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, +] +zope-event = [ + {file = "zope.event-4.5.0-py2.py3-none-any.whl", hash = "sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42"}, + {file = "zope.event-4.5.0.tar.gz", hash = "sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330"}, +] +zope-interface = [ + {file = "zope.interface-5.5.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:2cb3003941f5f4fa577479ac6d5db2b940acb600096dd9ea9bf07007f5cab46f"}, + {file = "zope.interface-5.5.0-cp27-cp27m-win32.whl", hash = "sha256:8c791f4c203ccdbcda588ea4c8a6e4353e10435ea48ddd3d8734a26fe9714cba"}, + {file = "zope.interface-5.5.0-cp27-cp27m-win_amd64.whl", hash = "sha256:3eedf3d04179774d750e8bb4463e6da350956a50ed44d7b86098e452d7ec385e"}, + {file = "zope.interface-5.5.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:58a66c2020a347973168a4a9d64317bac52f9fdfd3e6b80b252be30da881a64e"}, + {file = "zope.interface-5.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7912ae76e1df6a1fb841b619110b1be4c86dfb36699d7fd2f177105cdea885"}, + {file = "zope.interface-5.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:423c074e404f13e6fa07f4454f47fdbb38d358be22945bc812b94289d9142374"}, + {file = "zope.interface-5.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7bdcec93f152e0e1942102537eed7b166d6661ae57835b20a52a2a3d6a3e1bf3"}, + {file = "zope.interface-5.5.0-cp310-cp310-win32.whl", hash = "sha256:03f5ae315db0d0de668125d983e2a819a554f3fdb2d53b7e934e3eb3c3c7375d"}, + {file = "zope.interface-5.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:8b9f153208d74ccfa25449a0c6cb756ab792ce0dc99d9d771d935f039b38740c"}, + {file = "zope.interface-5.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeac590cce44e68ee8ad0b8ecf4d7bf15801f102d564ca1b0eb1f12f584ee656"}, + {file = "zope.interface-5.5.0-cp35-cp35m-win32.whl", hash = "sha256:7d9ec1e6694af39b687045712a8ad14ddcb568670d5eb1b66b48b98b9312afba"}, + {file = "zope.interface-5.5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:d18fb0f6c8169d26044128a2e7d3c39377a8a151c564e87b875d379dbafd3930"}, + {file = "zope.interface-5.5.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0eb2b3e84f48dd9cfc8621c80fba905d7e228615c67f76c7df7c716065669bb6"}, + {file = "zope.interface-5.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df6593e150d13cfcce69b0aec5df7bc248cb91e4258a7374c129bb6d56b4e5ca"}, + {file = "zope.interface-5.5.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9dc4493aa3d87591e3d2bf1453e25b98038c839ca8e499df3d7106631b66fe83"}, + {file = "zope.interface-5.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5c6023ae7defd052cf76986ce77922177b0c2f3913bea31b5b28fbdf6cb7099e"}, + {file = "zope.interface-5.5.0-cp36-cp36m-win32.whl", hash = "sha256:a69c28d85bb7cf557751a5214cb3f657b2b035c8c96d71080c1253b75b79b69b"}, + {file = "zope.interface-5.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:85dd6dd9aaae7a176948d8bb62e20e2968588fd787c29c5d0d964ab475168d3d"}, + {file = "zope.interface-5.5.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:970661ece2029915b8f7f70892e88404340fbdefd64728380cad41c8dce14ff4"}, + {file = "zope.interface-5.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e3495bb0cdcea212154e558082c256f11b18031f05193ae2fb85d048848db14"}, + {file = "zope.interface-5.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3f68404edb1a4fb6aa8a94675521ca26c83ebbdbb90e894f749ae0dc4ca98418"}, + {file = "zope.interface-5.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:740f3c1b44380658777669bcc42f650f5348e53797f2cee0d93dc9b0f9d7cc69"}, + {file = "zope.interface-5.5.0-cp37-cp37m-win32.whl", hash = "sha256:006f8dd81fae28027fc28ada214855166712bf4f0bfbc5a8788f9b70982b9437"}, + {file = "zope.interface-5.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:43490ad65d4c64e45a30e51a2beb7a6b63e1ff395302ad22392224eb618476d6"}, + {file = "zope.interface-5.5.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f70726b60009433111fe9928f5d89cbb18962411d33c45fb19eb81b9bbd26fcd"}, + {file = "zope.interface-5.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa614d049667bed1c737435c609c0956c5dc0dbafdc1145ee7935e4658582cb"}, + {file = "zope.interface-5.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:58a975f89e4584d0223ab813c5ba4787064c68feef4b30d600f5e01de90ae9ce"}, + {file = "zope.interface-5.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:37ec9ade9902f412cc7e7a32d71f79dec3035bad9bd0170226252eed88763c48"}, + {file = "zope.interface-5.5.0-cp38-cp38-win32.whl", hash = "sha256:be11fce0e6af6c0e8d93c10ef17b25aa7c4acb7ec644bff2596c0d639c49e20f"}, + {file = "zope.interface-5.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:cbbf83914b9a883ab324f728de869f4e406e0cbcd92df7e0a88decf6f9ab7d5a"}, + {file = "zope.interface-5.5.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:26c1456520fdcafecc5765bec4783eeafd2e893eabc636908f50ee31fe5c738c"}, + {file = "zope.interface-5.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47ff078734a1030c48103422a99e71a7662d20258c00306546441adf689416f7"}, + {file = "zope.interface-5.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:687cab7f9ae18d2c146f315d0ca81e5ffe89a139b88277afa70d52f632515854"}, + {file = "zope.interface-5.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d80f6236b57a95eb19d5e47eb68d0296119e1eff6deaa2971ab8abe3af918420"}, + {file = "zope.interface-5.5.0-cp39-cp39-win32.whl", hash = "sha256:9cdc4e898d3b1547d018829fd4a9f403e52e51bba24be0fbfa37f3174e1ef797"}, + {file = "zope.interface-5.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:6566b3d2657e7609cd8751bcb1eab1202b1692a7af223035a5887d64bb3a2f3b"}, + {file = "zope.interface-5.5.0.tar.gz", hash = "sha256:700ebf9662cf8df70e2f0cb4988e078c53f65ee3eefd5c9d80cf988c4175c8e3"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..7855ad0124 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,176 @@ +[tool.poetry] +name = "openpilot" +version = "0.1.0" +description = "an open source driver assistance system" +authors = ["Vehicle Researcher "] +license = "MIT" +readme = "README.md" +repository = "https://github.com/commaai/openpilot" +documentation = "https://docs.comma.ai" + + +[tool.poetry.dependencies] +python = "~3.8" +atomicwrites = "^1.4.0" +casadi = { version = "==3.5.5", markers = "platform_system != 'Darwin'" } +cffi = "^1.15.1" +crcmod = "^1.7" +cryptography = "^37.0.4" +Cython = "^0.29.30" +flake8 = "^4.0.1" +Flask = "^2.1.2" +future-fstrings = "^1.2.0" # for acados +gunicorn = "^20.1.0" +hatanaka = "==2.4" +hexdump = "^3.3" +Jinja2 = "^3.1.2" +json-rpc = "^1.13.0" +libusb1 = "^3.0.0" +nose = "^1.3.7" +numpy = "^1.23.0" +onnx = "^1.12.0" +onnxruntime-gpu = { version = "^1.11.1", markers = "platform_system != 'Darwin'" } +pillow = "^9.2.0" +poetry = "==1.2.2" +protobuf = "==3.20.1" +psutil = "^5.9.1" +pycapnp = "==1.1.0" +pycryptodome = "^3.15.0" +PyJWT = "^2.5.0" +pylint = "^2.15.4" +pyopencl = "^2022.2.4" +pyserial = "^3.5" +python-dateutil = "^2.8.2" +PyYAML = "^6.0" +pyzmq = "^23.2.0" +requests = "^2.28.1" +scons = "^4.3.0" +sentry-sdk = "^1.6.0" +setproctitle = "^1.2.3" +six = "^1.16.0" +smbus2 = "^0.4.2" +sympy = "^1.10.1" +timezonefinder = "^6.0.1" +tqdm = "^4.64.0" +urllib3 = "^1.26.10" +utm = "^0.7.0" +websocket_client = "^1.3.3" + + +[tool.poetry.group.dev.dependencies] +av = "^9.2.0" +azure-storage-blob = "~2.1" +breathe = "^4.34.0" +carla = "==0.9.13" +control = "^0.9.2" +coverage = "^6.4.1" +dictdiffer = "^0.9.0" +fastcluster = "^1.2.6" +ft4222 = "^1.4.1" +hexdump = "^3.3" +hypothesis = "==6.46.7" +inputs = "^0.5" +lru-dict = "^1.1.7" +lxml = "^4.9.1" +markdown-it-py = "^2.1.0" +matplotlib = "^3.5.2" +mpld3 = "^0.5.8" +mypy = "^0.961" +myst-parser = "^0.18.0" +natsort = "^8.1.0" +numpy = "^1.23.0" +opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" } +pandas = "^1.4.3" +parameterized = "^0.8.1" +paramiko = "^2.11.0" +pprofile = "^2.1.0" +pre-commit = "^2.19.0" +pycurl = "^7.45.1" +pygame = "^2.1.2" +pyprof2calltree = "^1.4.5" +pytest = "^7.1.2" +pytest-xdist = "^2.5.0" +reverse_geocoder = "^1.5.1" +scipy = "^1.8.1" +sphinx = "^5.0.2" +sphinx-rtd-theme = "^1.0.0" +sphinx-sitemap = "^2.2.0" +subprocess32 = "^3.5.4" +tabulate = "^0.8.10" +tenacity = "^8.0.1" +types-atomicwrites = "^1.4.5" +types-certifi = "^2021.10.8" +types-pycurl = "^7.45.1" +types-PyYAML = "^6.0" +types-requests = "^2.28.11" + + +[tool.poetry.group.xx] +optional = true + +[tool.poetry.group.xx.dependencies] +aenum = "^3.1.11" +aiohttp = "^3.8.1" +albumentations = "^1.2.1" +apex = { url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" } +azure-cli-core = "^2.38.0" +azure-common = "^1.1.28" +azure-core = "^1.24.2" +azure-nspkg = "~3.0" +azure-storage-blob = "~2.1" +azure-storage-common = "~2.1" +azure-storage-nspkg = "~3.1" +blosc = "==1.9.2" +cloudpickle = "^2.1.0" +configargparse = "^1.5.3" +cupy-cuda113 = "^10.6.0" +datadog = "^0.44.0" +dotmap = "^1.3.30" +elasticsearch = "^8.3.1" +Flask-Cors = "^3.0.10" +Flask-SocketIO = "^5.2.0" +GeoAlchemy2 = "^0.12.1" +imageio = "^2.19.5" +influxdb-client = "^1.30.0" +ipykernel = "^6.15.1" +ipython = "^8.4.0" +joblib = "^1.1.0" +json-logging-py = "^0.2" +jupyter = "^1.0.0" +jupyterlab = "^3.4.4" +jupyterlab-vim = "^0.15.1" +Markdown = "^3.4.1" +mpld3 = "^0.5.8" +msgpack-python = "^0.5.6" +networkx = "~2.3" +nvidia-ml-py3 = "^7.352.0" +onnxoptimizer = "^0.2.6" +opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" } +osmium = "^3.3.0" +pandas = "^1.4.3" +pillow-avif-plugin = "^1.2.2" +pipenv = "==2022.10.12" +plotly = "^5.9.0" +pycuda = "^2022.1" +Pygments = "^2.12.0" +PyMySQL = "~0.9" +pyproj = "^3.3.1" +python-logstash = "^0.4.8" +redis = "^4.3.4" +s2sphere = "^0.2.5" +scikit-image = "^0.19.3" +scikit-learn = "^1.1.1" +segmentation-models-pytorch = "==0.2.1" +simplejson = "^3.17.6" +SQLAlchemy = "^1.4.39" +torch = { url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } +torchsummary = "^1.5.1" +torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } +triton = "^1.1.1" +Werkzeug = "^2.1.2" +zerorpc = { git = "git@github.com:commaai/zerorpc-python.git", branch = "master" } + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/tools/README.md b/tools/README.md index 59eea3230d..3969deb24d 100644 --- a/tools/README.md +++ b/tools/README.md @@ -6,13 +6,12 @@ openpilot is developed and tested on **Ubuntu 20.04**, which is the primary deve ## Setup your PC - First, clone openpilot: ``` bash cd ~ git clone https://github.com/commaai/openpilot.git -cd openpilot +cd openpilot git submodule update --init ``` @@ -26,10 +25,10 @@ tools/ubuntu_setup.sh tools/mac_setup.sh ``` -Activate a shell with the install Python dependencies: +Activate a shell with the Python dependencies installed: ``` bash -cd openpilot && pipenv shell +cd openpilot && poetry shell ``` Build openpilot with this command: @@ -43,7 +42,7 @@ Neither openpilot nor any of the tools are developed or tested on Windows, but t Follow [these instructions](https://docs.microsoft.com/en-us/windows/wsl/install) to setup the WSL and install the `Ubuntu-20.04` distribution. Once your Ubuntu WSL environment is setup, follow the Linux setup instructions to finish setting up your environment. -GUI applications do not work with WSL out of the box. You will have to either [upgrade your system to Windows 11](https://docs.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) or [set up an Xorg server](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/running-wsl-gui-apps-on-windows-10/ba-p/1493242). +GUI applications do not work with WSL out of the box. You will have to either [upgrade your system to Windows 11](https://docs.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) or [set up an Xorg server](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/running-wsl-gui-apps-on-windows-10/ba-p/1493242). ## CTF diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index 214a917f8b..e85292da03 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -88,7 +88,7 @@ eval "$(pyenv init --path)" echo "[ ] installed python dependencies t=$SECONDS" # install casadi -VENV=`pipenv --venv` +VENV=`poetry env info --path` PYTHON_VER=3.8 PYTHON_VERSION=$(cat $ROOT/.python-version) if [ ! -f "$VENV/include/casadi/casadi.hpp" ]; then diff --git a/update_requirements.sh b/update_requirements.sh index 060dca76ef..8571726e10 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -40,27 +40,29 @@ fi eval "$(pyenv init --path)" echo "update pip" -pip install pip==21.3.1 -pip install pipenv==2021.11.23 +pip install pip==22.3 +pip install poetry==1.2.2 +poetry config virtualenvs.prefer-active-python true --local + +POETRY_INSTALL_ARGS="" if [ -d "./xx" ]; then - echo "WARNING: using xx Pipfile ******" - export PIPENV_SYSTEM=1 - export PIPENV_PIPFILE=./xx/Pipfile -fi - -if [ -z "$PIPENV_SYSTEM" ]; then - echo "PYTHONPATH=${PWD}" > .env - RUN="pipenv run" -else - RUN="" + echo "WARNING: using xx dependency group, installing globally" + poetry config virtualenvs.create false --local + POETRY_INSTALL_ARGS="--with xx --sync" fi echo "pip packages install..." -pipenv sync --dev -pipenv --clear +poetry install --no-cache --no-root $POETRY_INSTALL_ARGS pyenv rehash +if [ -d "./xx" ] || [ -n "$POETRY_VIRTUALENVS_CREATE" ]; then + RUN="" +else + echo "PYTHONPATH=${PWD}" > .env + RUN="poetry run" +fi + echo "pre-commit hooks install..." shopt -s nullglob for f in .pre-commit-config.yaml */.pre-commit-config.yaml; do From dba8e8ec0ee026f73b5a87d2c4b00556fdee58f7 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 21 Oct 2022 18:04:07 -0700 Subject: [PATCH 0050/1179] Revert "ci: don't trigger on pull request sync event (#25900)" This reverts commit 68530f18b4cb2a1f20dfb19319d91216c23e00bb. --- .github/workflows/selfdrive_tests.yaml | 1 - .github/workflows/tools_tests.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 0693a66164..e921cd3d00 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -5,7 +5,6 @@ on: branches-ignore: - 'testing-closet*' pull_request: - types: [opened, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 71bad021d0..549a2f4195 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -5,7 +5,6 @@ on: branches-ignore: - 'testing-closet*' pull_request: - types: [opened, reopened] concurrency: group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} From 6efd2c3de3d5b2955f3e7ab5c93701e94ac25537 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 21 Oct 2022 18:15:52 -0700 Subject: [PATCH 0051/1179] GM camera ACC: cancel after delay (#26197) * add delay to GM camera ACC cancel to avoid FCW and cruise fault * we can revert brake pressed threshold now * bump panda * add proper threshold * bump * bujmp panda --- panda | 2 +- selfdrive/car/gm/carcontroller.py | 10 +++++++++- selfdrive/car/gm/carstate.py | 7 +------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/panda b/panda index d51dd496cb..2db69bc941 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d51dd496cbdc8665928af40247582bc62dba1f2a +Subproject commit 2db69bc94120a3c10f39cdedc9d83315f9ba801e diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index f28a0f7b59..c96b982503 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -10,6 +10,9 @@ from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButt VisualAlert = car.CarControl.HUDControl.VisualAlert NetworkLocation = car.CarParams.NetworkLocation +# Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s +CAMERA_CANCEL_DELAY_FRAMES = 10 + class CarController: def __init__(self, dbc_name, CP, VM): @@ -20,6 +23,7 @@ class CarController: self.apply_brake = 0 self.frame = 0 self.last_button_frame = 0 + self.cancel_counter = 0 self.lka_steering_cmd_counter = 0 self.sent_lka_steering_cmd = False @@ -111,9 +115,13 @@ class CarController: can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN) else: + # While car is braking, cancel button causes ECM to enter a soft disable state with a fault status. + # A delayed cancellation allows camera to cancel and avoids a fault when user depresses brake quickly + self.cancel_counter = self.cancel_counter + 1 if CC.cruiseControl.cancel else 0 + # Stock longitudinal, integrated at camera if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: - if CC.cruiseControl.cancel: + if self.cancel_counter > CAMERA_CANCEL_DELAY_FRAMES: self.last_button_frame = self.frame can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index de63f56eab..7cb2274674 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -55,12 +55,7 @@ class CarState(CarStateBase): # To avoid a cruise fault we need to match the ECM's brake pressed signal and threshold # https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"] - if self.CP.networkLocation != NetworkLocation.fwdCamera: - ret.brakePressed = ret.brake >= 8 - else: - # While car is braking, cancel button causes ECM to enter a soft disable state with a fault status. - # Match ECM threshold at a standstill to allow the camera to cancel earlier - ret.brakePressed = ret.brake >= 20 + ret.brakePressed = ret.brake >= 8 # Regen braking is braking if self.CP.transmissionType == TransmissionType.direct: From 42ef62e39102ca5ad03982232ebadc37928a6ca2 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Fri, 21 Oct 2022 20:30:48 -0700 Subject: [PATCH 0052/1179] Use calibrator to stabilize wide transform (#26201) * Use calibrator to stabilize wide transform * Need array * Needs init * Bump to master * Needs to be arr * publish mshg * Check size * Update ref --- cereal | 2 +- selfdrive/locationd/calibrationd.py | 35 +++++++++++++++++++++--- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cereal b/cereal index 38133307b2..79e6e4c26d 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 38133307b2e6036e76684b39878e79212e545e06 +Subproject commit 79e6e4c26dd12ba979a5fb872b4e68a707c32203 diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 9e6536f9b5..163c3cfd4d 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -31,6 +31,7 @@ INPUTS_NEEDED = 5 # Minimum blocks needed for valid calibration INPUTS_WANTED = 50 # We want a little bit more than we need for stability MAX_ALLOWED_SPREAD = np.radians(2) RPY_INIT = np.array([0.0,0.0,0.0]) +WIDE_FROM_DEVICE_EULER_INIT = np.array([0.0, 0.0, 0.0]) # These values are needed to accommodate biggest modelframe PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657]) @@ -67,6 +68,7 @@ class Calibrator: calibration_params = params.get("CalibrationParams") self.wide_camera = params.get_bool('WideCameraOnly') rpy_init = RPY_INIT + wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT valid_blocks = 0 if param_put and calibration_params: @@ -74,24 +76,34 @@ class Calibrator: msg = log.Event.from_bytes(calibration_params) rpy_init = np.array(msg.liveCalibration.rpyCalib) valid_blocks = msg.liveCalibration.validBlocks + wide_from_device_euler = np.array(msg.liveCalibration.wideFromDeviceEuler) except Exception: cloudlog.exception("Error reading cached CalibrationParams") - self.reset(rpy_init, valid_blocks) + self.reset(rpy_init, valid_blocks, wide_from_device_euler) self.update_status() - def reset(self, rpy_init: np.ndarray = RPY_INIT, valid_blocks: int = 0, smooth_from: Optional[np.ndarray] = None) -> None: + def reset(self, rpy_init: np.ndarray = RPY_INIT, + valid_blocks: int = 0, + wide_from_device_euler: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT, + smooth_from: Optional[np.ndarray] = None) -> None: if not np.isfinite(rpy_init).all(): self.rpy = RPY_INIT.copy() else: self.rpy = rpy_init.copy() + if not np.isfinite(wide_from_device_euler).all(): + self.wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT.copy() + else: + self.wide_from_device_euler = wide_from_device_euler.copy() + if not np.isfinite(valid_blocks) or valid_blocks < 0: self.valid_blocks = 0 else: self.valid_blocks = valid_blocks self.rpys = np.tile(self.rpy, (INPUTS_WANTED, 1)) + self.wide_from_device_eulers = np.tile(wide_from_device_euler, (INPUTS_WANTED, 1)) self.idx = 0 self.block_idx = 0 @@ -115,6 +127,8 @@ class Calibrator: if valid_idxs: rpys = self.rpys[valid_idxs] self.rpy = np.mean(rpys, axis=0) + wide_from_device_eulers = self.wide_from_device_eulers[valid_idxs] + self.wide_from_device_euler = np.mean(wide_from_device_eulers, axis=0) max_rpy_calib = np.array(np.max(rpys, axis=0)) min_rpy_calib = np.array(np.min(rpys, axis=0)) self.calib_spread = np.abs(max_rpy_calib - min_rpy_calib) @@ -146,7 +160,10 @@ class Calibrator: else: return self.rpy - def handle_cam_odom(self, trans: List[float], rot: List[float], trans_std: List[float]) -> Optional[np.ndarray]: + def handle_cam_odom(self, trans: List[float], + rot: List[float], + wide_from_device_euler: List[float], + trans_std: List[float]) -> Optional[np.ndarray]: self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) @@ -165,7 +182,15 @@ class Calibrator: new_rpy = euler_from_rot(rot_from_euler(self.get_smooth_rpy()).dot(rot_from_euler(observed_rpy))) new_rpy = sanity_clip(new_rpy) - self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) + if len(wide_from_device_euler): + new_wide_from_device_euler = np.array(wide_from_device_euler) + else: + new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT + + self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) + self.wide_from_device_eulers[self.block_idx] = (self.idx*self.wide_from_device_eulers[self.block_idx] + + (BLOCK_SIZE - self.idx) * new_wide_from_device_euler) / float(BLOCK_SIZE) self.idx = (self.idx + 1) % BLOCK_SIZE if self.idx == 0: self.block_idx += 1 @@ -187,6 +212,7 @@ class Calibrator: liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100) liveCalibration.rpyCalib = smooth_rpy.tolist() liveCalibration.rpyCalibSpread = self.calib_spread.tolist() + liveCalibration.wideFromDeviceEuler = self.wide_from_device_euler.tolist() if self.not_car: liveCalibration.validBlocks = INPUTS_NEEDED @@ -223,6 +249,7 @@ def calibrationd_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[m calibrator.handle_v_ego(sm['carState'].vEgo) new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans, sm['cameraOdometry'].rot, + sm['cameraOdometry'].wideFromDeviceEuler, sm['cameraOdometry'].transStd) if DEBUG and new_rpy is not None: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 230e81d949..d03b897f9d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f5a352666728344ca5065bb44c47c1f5650b4243 +a5c77655fba5563e8128fb655f69b1bbd02198aa From 04b40aad92afaac555c3c7d814699c467d975627 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 21 Oct 2022 21:13:55 -0700 Subject: [PATCH 0053/1179] ci: run some jobs only on push (#26202) * ci: run some jobs only on push alternative to #25900 * tools too --- .github/workflows/selfdrive_tests.yaml | 11 ++++++++++- .github/workflows/tools_tests.yaml | 5 +---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index e921cd3d00..a5f2bf3452 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -33,6 +33,7 @@ jobs: name: build release runs-on: ubuntu-20.04 timeout-minutes: 30 + if: github.event_name == 'push' env: STRIPPED_DIR: /tmp/releasepilot steps: @@ -67,6 +68,7 @@ jobs: name: build all runs-on: ubuntu-20.04 timeout-minutes: 30 + if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -85,6 +87,7 @@ jobs: # name: build macos # runs-on: macos-latest # timeout-minutes: 60 + # if: github.event_name == 'push' # steps: # - uses: actions/checkout@v3 # with: @@ -142,7 +145,7 @@ jobs: name: docker push runs-on: ubuntu-20.04 timeout-minutes: 22 - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' + if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'commaai/openpilot' needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast steps: - uses: actions/checkout@v3 @@ -167,6 +170,7 @@ jobs: name: static analysis runs-on: ubuntu-20.04 timeout-minutes: 20 + if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -181,6 +185,7 @@ jobs: name: valgrind runs-on: ubuntu-20.04 timeout-minutes: 20 + if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -199,6 +204,7 @@ jobs: name: unit tests runs-on: ubuntu-20.04 timeout-minutes: 30 + if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -279,6 +285,7 @@ jobs: name: model tests runs-on: ubuntu-20.04 timeout-minutes: 20 + if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -307,6 +314,7 @@ jobs: name: longitudinal runs-on: ubuntu-20.04 timeout-minutes: 20 + if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -335,6 +343,7 @@ jobs: name: cars runs-on: ubuntu-20.04 timeout-minutes: 20 + if: github.event_name == 'push' strategy: fail-fast: false matrix: diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 549a2f4195..25357e0889 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -4,7 +4,6 @@ on: push: branches-ignore: - 'testing-closet*' - pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} @@ -83,9 +82,7 @@ jobs: 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' + if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' run: | $DOCKER_LOGIN docker push $DOCKER_REGISTRY/openpilot-docs:latest - - From 75b7fd0a7d9728dbf84e4cff209cbc44799dbdeb Mon Sep 17 00:00:00 2001 From: Bruce Wayne Date: Fri, 21 Oct 2022 21:44:47 -0700 Subject: [PATCH 0054/1179] Revert "Use calibrator to stabilize wide transform (#26201)" This reverts commit 42ef62e39102ca5ad03982232ebadc37928a6ca2. --- cereal | 2 +- selfdrive/locationd/calibrationd.py | 35 +++--------------------- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/cereal b/cereal index 79e6e4c26d..38133307b2 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 79e6e4c26dd12ba979a5fb872b4e68a707c32203 +Subproject commit 38133307b2e6036e76684b39878e79212e545e06 diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 163c3cfd4d..9e6536f9b5 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -31,7 +31,6 @@ INPUTS_NEEDED = 5 # Minimum blocks needed for valid calibration INPUTS_WANTED = 50 # We want a little bit more than we need for stability MAX_ALLOWED_SPREAD = np.radians(2) RPY_INIT = np.array([0.0,0.0,0.0]) -WIDE_FROM_DEVICE_EULER_INIT = np.array([0.0, 0.0, 0.0]) # These values are needed to accommodate biggest modelframe PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657]) @@ -68,7 +67,6 @@ class Calibrator: calibration_params = params.get("CalibrationParams") self.wide_camera = params.get_bool('WideCameraOnly') rpy_init = RPY_INIT - wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT valid_blocks = 0 if param_put and calibration_params: @@ -76,34 +74,24 @@ class Calibrator: msg = log.Event.from_bytes(calibration_params) rpy_init = np.array(msg.liveCalibration.rpyCalib) valid_blocks = msg.liveCalibration.validBlocks - wide_from_device_euler = np.array(msg.liveCalibration.wideFromDeviceEuler) except Exception: cloudlog.exception("Error reading cached CalibrationParams") - self.reset(rpy_init, valid_blocks, wide_from_device_euler) + self.reset(rpy_init, valid_blocks) self.update_status() - def reset(self, rpy_init: np.ndarray = RPY_INIT, - valid_blocks: int = 0, - wide_from_device_euler: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT, - smooth_from: Optional[np.ndarray] = None) -> None: + def reset(self, rpy_init: np.ndarray = RPY_INIT, valid_blocks: int = 0, smooth_from: Optional[np.ndarray] = None) -> None: if not np.isfinite(rpy_init).all(): self.rpy = RPY_INIT.copy() else: self.rpy = rpy_init.copy() - if not np.isfinite(wide_from_device_euler).all(): - self.wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT.copy() - else: - self.wide_from_device_euler = wide_from_device_euler.copy() - if not np.isfinite(valid_blocks) or valid_blocks < 0: self.valid_blocks = 0 else: self.valid_blocks = valid_blocks self.rpys = np.tile(self.rpy, (INPUTS_WANTED, 1)) - self.wide_from_device_eulers = np.tile(wide_from_device_euler, (INPUTS_WANTED, 1)) self.idx = 0 self.block_idx = 0 @@ -127,8 +115,6 @@ class Calibrator: if valid_idxs: rpys = self.rpys[valid_idxs] self.rpy = np.mean(rpys, axis=0) - wide_from_device_eulers = self.wide_from_device_eulers[valid_idxs] - self.wide_from_device_euler = np.mean(wide_from_device_eulers, axis=0) max_rpy_calib = np.array(np.max(rpys, axis=0)) min_rpy_calib = np.array(np.min(rpys, axis=0)) self.calib_spread = np.abs(max_rpy_calib - min_rpy_calib) @@ -160,10 +146,7 @@ class Calibrator: else: return self.rpy - def handle_cam_odom(self, trans: List[float], - rot: List[float], - wide_from_device_euler: List[float], - trans_std: List[float]) -> Optional[np.ndarray]: + def handle_cam_odom(self, trans: List[float], rot: List[float], trans_std: List[float]) -> Optional[np.ndarray]: self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) @@ -182,15 +165,7 @@ class Calibrator: new_rpy = euler_from_rot(rot_from_euler(self.get_smooth_rpy()).dot(rot_from_euler(observed_rpy))) new_rpy = sanity_clip(new_rpy) - if len(wide_from_device_euler): - new_wide_from_device_euler = np.array(wide_from_device_euler) - else: - new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT - - self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + - (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) - self.wide_from_device_eulers[self.block_idx] = (self.idx*self.wide_from_device_eulers[self.block_idx] + - (BLOCK_SIZE - self.idx) * new_wide_from_device_euler) / float(BLOCK_SIZE) + self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) self.idx = (self.idx + 1) % BLOCK_SIZE if self.idx == 0: self.block_idx += 1 @@ -212,7 +187,6 @@ class Calibrator: liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100) liveCalibration.rpyCalib = smooth_rpy.tolist() liveCalibration.rpyCalibSpread = self.calib_spread.tolist() - liveCalibration.wideFromDeviceEuler = self.wide_from_device_euler.tolist() if self.not_car: liveCalibration.validBlocks = INPUTS_NEEDED @@ -249,7 +223,6 @@ def calibrationd_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[m calibrator.handle_v_ego(sm['carState'].vEgo) new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans, sm['cameraOdometry'].rot, - sm['cameraOdometry'].wideFromDeviceEuler, sm['cameraOdometry'].transStd) if DEBUG and new_rpy is not None: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d03b897f9d..230e81d949 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a5c77655fba5563e8128fb655f69b1bbd02198aa +f5a352666728344ca5065bb44c47c1f5650b4243 From db6c9b9d456ce6b7246f9002bde05ea6b6f53054 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 21 Oct 2022 23:09:24 -0700 Subject: [PATCH 0055/1179] install xx deps with XX env (#26205) --- update_requirements.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update_requirements.sh b/update_requirements.sh index 8571726e10..0967e2dc6c 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -46,7 +46,7 @@ pip install poetry==1.2.2 poetry config virtualenvs.prefer-active-python true --local POETRY_INSTALL_ARGS="" -if [ -d "./xx" ]; then +if [ -d "./xx" ] || [ -n "$XX" ]; then echo "WARNING: using xx dependency group, installing globally" poetry config virtualenvs.create false --local POETRY_INSTALL_ARGS="--with xx --sync" From 66c01801a5223503435f1da366a3a6c4974ef988 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 22 Oct 2022 00:09:37 -0700 Subject: [PATCH 0056/1179] GM: clean up gmcan (#26206) * camera * clean up gmcan * fix * revv --- selfdrive/car/gm/carcontroller.py | 1 + selfdrive/car/gm/gmcan.py | 43 +++++++++++++++++++------------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index c96b982503..b56b3bfca6 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -125,6 +125,7 @@ class CarController: self.last_button_frame = self.frame can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) + if self.CP.networkLocation == NetworkLocation.fwdCamera: # Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1 if self.frame % 10 == 0: can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status)) diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index ec046dc3c2..42df2c6afd 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -1,5 +1,6 @@ from selfdrive.car import make_can_msg + def create_buttons(packer, bus, idx, button): values = { "ACCButtons": button, @@ -7,14 +8,15 @@ def create_buttons(packer, bus, idx, button): } return packer.make_can_msg("ASCMSteeringButton", bus, values) + def create_pscm_status(packer, bus, pscm_status): checksum_mod = int(1 - pscm_status["HandsOffSWlDetectionStatus"]) << 5 pscm_status["HandsOffSWlDetectionStatus"] = 1 pscm_status["PSCMStatusChecksum"] += checksum_mod return packer.make_can_msg("PSCMStatus", bus, pscm_status) -def create_steering_control(packer, bus, apply_steer, idx, lkas_active): +def create_steering_control(packer, bus, apply_steer, idx, lkas_active): values = { "LKASteeringCmdActive": lkas_active, "LKASteeringCmd": apply_steer, @@ -24,15 +26,17 @@ def create_steering_control(packer, bus, apply_steer, idx, lkas_active): return packer.make_can_msg("ASCMLKASteeringCmd", bus, values) + def create_adas_keepalive(bus): dat = b"\x00\x00\x00\x00\x00\x00\x00" return [make_can_msg(0x409, dat, bus), make_can_msg(0x40a, dat, bus)] -def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_stop): + +def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop): values = { - "GasRegenCmdActive": acc_engaged, + "GasRegenCmdActive": enabled, "RollingCounter": idx, - "GasRegenCmdActiveInv": 1 - acc_engaged, + "GasRegenCmdActiveInv": 1 - enabled, "GasRegenCmd": throttle, "GasRegenFullStopActive": at_full_stop, "GasRegenAlwaysOne": 1, @@ -47,6 +51,7 @@ def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_st return packer.make_can_msg("ASCMGasRegenCmd", bus, values) + def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_full_stop): mode = 0x1 if apply_brake > 0: @@ -63,44 +68,48 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_f checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff values = { - "RollingCounter" : idx, - "FrictionBrakeMode" : mode, + "RollingCounter": idx, + "FrictionBrakeMode": mode, "FrictionBrakeChecksum": checksum, - "FrictionBrakeCmd" : -apply_brake + "FrictionBrakeCmd": -apply_brake } return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values) -def create_acc_dashboard_command(packer, bus, acc_engaged, target_speed_kph, lead_car_in_sight, fcw): + +def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, lead_car_in_sight, fcw): target_speed = min(target_speed_kph, 255) values = { - "ACCAlwaysOne" : 1, - "ACCResumeButton" : 0, - "ACCSpeedSetpoint" : target_speed, - "ACCGapLevel" : 3 * acc_engaged, # 3 "far", 0 "inactive" - "ACCCmdActive" : acc_engaged, - "ACCAlwaysOne2" : 1, - "ACCLeadCar" : lead_car_in_sight, + "ACCAlwaysOne": 1, + "ACCResumeButton": 0, + "ACCSpeedSetpoint": target_speed, + "ACCGapLevel": 3 * enabled, # 3 "far", 0 "inactive" + "ACCCmdActive": enabled, + "ACCAlwaysOne2": 1, + "ACCLeadCar": lead_car_in_sight, "FCWAlert": 0x3 if fcw else 0 } return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values) + def create_adas_time_status(bus, tt, idx): dat = [(tt >> 20) & 0xff, (tt >> 12) & 0xff, (tt >> 4) & 0xff, - ((tt & 0xf) << 4) + (idx << 2)] + ((tt & 0xf) << 4) + (idx << 2)] chksum = 0x1000 - dat[0] - dat[1] - dat[2] - dat[3] chksum = chksum & 0xfff dat += [0x40 + (chksum >> 8), chksum & 0xff, 0x12] return make_can_msg(0xa1, bytes(dat), bus) + def create_adas_steering_status(bus, idx): dat = [idx << 6, 0xf0, 0x20, 0, 0, 0] chksum = 0x60 + sum(dat) dat += [chksum >> 8, chksum & 0xff] return make_can_msg(0x306, bytes(dat), bus) + def create_adas_accelerometer_speed_status(bus, speed_ms, idx): spd = int(speed_ms * 16) & 0xfff accel = 0 & 0xfff @@ -114,6 +123,7 @@ def create_adas_accelerometer_speed_status(bus, speed_ms, idx): dat += [(idx << 5) + (far_range_mode << 4) + (near_range_mode << 3) + (chksum >> 8), chksum & 0xff] return make_can_msg(0x308, bytes(dat), bus) + def create_adas_headlights_status(packer, bus): values = { "Always42": 0x42, @@ -121,6 +131,7 @@ def create_adas_headlights_status(packer, bus): } return packer.make_can_msg("ASCMHeadlight", bus, values) + def create_lka_icon_command(bus, active, critical, steer): if active and steer == 1: if critical: From 8bd512f9d76c8ad789bc80fb807d0ece193cb456 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 22 Oct 2022 00:53:50 -0700 Subject: [PATCH 0057/1179] deps: zerorpc over https --- poetry.lock | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7ad02c58cd..bf5c750069 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4316,7 +4316,7 @@ pyzmq = ">=13.1.0" [package.source] type = "git" -url = "git@github.com:commaai/zerorpc-python.git" +url = "https://github.com/commaai/zerorpc-python.git" reference = "master" resolved_reference = "0e27fd795bb9a7ec9cab81a771a2e35a91e397c9" diff --git a/pyproject.toml b/pyproject.toml index 7855ad0124..cbb5a983f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -168,7 +168,7 @@ torchsummary = "^1.5.1" torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } triton = "^1.1.1" Werkzeug = "^2.1.2" -zerorpc = { git = "git@github.com:commaai/zerorpc-python.git", branch = "master" } +zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } [build-system] From 335351123ab8a34d06bf164b5cf5be9046bf2c3c Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 22 Oct 2022 01:04:22 -0700 Subject: [PATCH 0058/1179] Revert "ci: run some jobs only on push (#26202)" This reverts commit 04b40aad92afaac555c3c7d814699c467d975627. --- .github/workflows/selfdrive_tests.yaml | 11 +---------- .github/workflows/tools_tests.yaml | 5 ++++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index a5f2bf3452..e921cd3d00 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -33,7 +33,6 @@ jobs: name: build release runs-on: ubuntu-20.04 timeout-minutes: 30 - if: github.event_name == 'push' env: STRIPPED_DIR: /tmp/releasepilot steps: @@ -68,7 +67,6 @@ jobs: name: build all runs-on: ubuntu-20.04 timeout-minutes: 30 - if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -87,7 +85,6 @@ jobs: # name: build macos # runs-on: macos-latest # timeout-minutes: 60 - # if: github.event_name == 'push' # steps: # - uses: actions/checkout@v3 # with: @@ -145,7 +142,7 @@ jobs: name: docker push runs-on: ubuntu-20.04 timeout-minutes: 22 - if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'commaai/openpilot' + 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: - uses: actions/checkout@v3 @@ -170,7 +167,6 @@ jobs: name: static analysis runs-on: ubuntu-20.04 timeout-minutes: 20 - if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -185,7 +181,6 @@ jobs: name: valgrind runs-on: ubuntu-20.04 timeout-minutes: 20 - if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -204,7 +199,6 @@ jobs: name: unit tests runs-on: ubuntu-20.04 timeout-minutes: 30 - if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -285,7 +279,6 @@ jobs: name: model tests runs-on: ubuntu-20.04 timeout-minutes: 20 - if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -314,7 +307,6 @@ jobs: name: longitudinal runs-on: ubuntu-20.04 timeout-minutes: 20 - if: github.event_name == 'push' steps: - uses: actions/checkout@v3 with: @@ -343,7 +335,6 @@ jobs: name: cars runs-on: ubuntu-20.04 timeout-minutes: 20 - if: github.event_name == 'push' strategy: fail-fast: false matrix: diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 25357e0889..549a2f4195 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -4,6 +4,7 @@ on: push: branches-ignore: - 'testing-closet*' + pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} @@ -82,7 +83,9 @@ jobs: 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.repository == 'commaai/openpilot' + 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 + + From e7e64be734899fa2cd8f3a2fe178c1aa958dd258 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 22 Oct 2022 16:05:09 +0800 Subject: [PATCH 0059/1179] cabana: fix incorrect freq&counter (#26207) fix wrong freq --- tools/cabana/canmessages.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 4cc91031ad..defeacd75a 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -65,7 +65,6 @@ QList CANMessages::findSignalValues(const QString &id, const Signal *si void CANMessages::process(QHash> *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { - ++counters[it.key()]; auto &msgs = can_msgs[it.key()]; const auto &new_msgs = it.value(); if (new_msgs.size() == settings.can_msg_log_size || msgs.empty()) { From 25b9588019beda1d1d79390bde738097a58b0c0f Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 22 Oct 2022 01:32:27 -0700 Subject: [PATCH 0060/1179] deps: add missing package einops --- poetry.lock | 66 ++++++++++++++++++++++++++++---------------------- pyproject.toml | 1 + 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/poetry.lock b/poetry.lock index bf5c750069..41fe2eb18c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -108,6 +108,7 @@ python-versions = "*" [package.source] type = "url" url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" + [[package]] name = "appdirs" version = "1.4.4" @@ -229,7 +230,7 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "av" @@ -530,7 +531,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode-backport = ["unicodedata2"] +unicode_backport = ["unicodedata2"] [[package]] name = "cleo" @@ -837,6 +838,14 @@ python-versions = ">=3.5.0" [package.dependencies] torch = "*" +[[package]] +name = "einops" +version = "0.5.0" +description = "A new flavour of deep learning operations" +category = "dev" +optional = false +python-versions = ">=3.7" + [[package]] name = "elastic-transport" version = "8.4.0" @@ -1401,7 +1410,7 @@ notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test_extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] [[package]] name = "ipython-genutils" @@ -1450,9 +1459,9 @@ python-versions = ">=3.6.1,<4.0" [package.extras] colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pipreqs", "requirementslib"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] +requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] name = "itsdangerous" @@ -1883,7 +1892,7 @@ mdurl = ">=0.1,<1.0" [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"] -code-style = ["pre-commit (==2.6)"] +code_style = ["pre-commit (==2.6)"] compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"] linkify = ["linkify-it-py (>=1.0,<2.0)"] plugins = ["mdit-py-plugins"] @@ -1950,7 +1959,7 @@ python-versions = ">=3.7" markdown-it-py = ">=1.0.0,<3.0.0" [package.extras] -code-style = ["pre-commit"] +code_style = ["pre-commit"] rtd = ["attrs", "myst-parser (>=0.16.1,<0.17.0)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] @@ -2160,7 +2169,7 @@ sphinx = ">=4,<6" typing-extensions = "*" [package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] +code_style = ["pre-commit (>=2.12,<3.0)"] linkify = ["linkify-it-py (>=1.0,<2.0)"] rtd = ["ipython", "sphinx-book-theme", "sphinx-design", "sphinxcontrib.mermaid (>=0.7.1,<0.8.0)", "sphinxext-opengraph (>=0.6.3,<0.7.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=6,<7)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx (<5.2)", "sphinx-pytest"] @@ -2479,6 +2488,7 @@ numpy = [ [package.source] type = "url" url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" + [[package]] name = "osmium" version = "3.4.1" @@ -3183,7 +3193,7 @@ optional = false python-versions = ">=3.6" [package.extras] -asyncio-client = ["aiohttp (>=3.4)"] +asyncio_client = ["aiohttp (>=3.4)"] client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] @@ -3207,7 +3217,7 @@ bidict = ">=0.21.0" python-engineio = ">=4.3.0" [package.extras] -asyncio-client = ["aiohttp (>=3.4)"] +asyncio_client = ["aiohttp (>=3.4)"] client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] @@ -3383,7 +3393,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-oauthlib" @@ -3574,7 +3584,7 @@ falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)"] httpx = ["httpx (>=0.16.0)"] -pure-eval = ["asttokens", "executing", "pure-eval"] +pure_eval = ["asttokens", "executing", "pure-eval"] pyspark = ["pyspark (>=2.4.4)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] rq = ["rq (>=0.6)"] @@ -3840,19 +3850,19 @@ aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] +mssql_pymssql = ["pymssql"] +mssql_pyodbc = ["pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] +mysql_connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql_psycopg2binary = ["psycopg2-binary"] +postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] sqlcipher = ["sqlcipher3_binary"] @@ -4033,6 +4043,7 @@ typing-extensions = "*" [package.source] type = "url" url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" + [[package]] name = "torchsummary" version = "1.5.1" @@ -4062,6 +4073,7 @@ scipy = ["scipy"] [package.source] type = "url" url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" + [[package]] name = "tornado" version = "6.2" @@ -4366,7 +4378,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "f357744f2550b64cbd25e35881d6ec3c1180c90f830eb8d9f53322d6de485561" +content-hash = "e596391b3ebe3de6835da44c7a4e9018e5e4c1f5a5450568ebfc156fa2c0ae0c" [metadata.files] adal = [ @@ -5137,6 +5149,10 @@ dulwich = [ efficientnet-pytorch = [ {file = "efficientnet_pytorch-0.6.3.tar.gz", hash = "sha256:6667459336893e9bf6367de3788ba449fed97f65da3b6782bf2204b6273a319f"}, ] +einops = [ + {file = "einops-0.5.0-py3-none-any.whl", hash = "sha256:055de7eeb3cb9e9710ef3085a811090c6b52e809b7044e8785824ed185f486d1"}, + {file = "einops-0.5.0.tar.gz", hash = "sha256:8b7a83cffc1ea88e306df099b7cbb9c3ba5003bd84d05ae44be5655864abb8d3"}, +] elastic-transport = [ {file = "elastic-transport-8.4.0.tar.gz", hash = "sha256:b9ad708ceb7fcdbc6b30a96f886609a109f042c0b9d9f2e44403b3133ba7ff10"}, {file = "elastic_transport-8.4.0-py3-none-any.whl", hash = "sha256:19db271ab79c9f70f8c43f8f5b5111408781a6176b54ab2e54d713b6d9ceb815"}, @@ -6541,11 +6557,6 @@ pillow-avif-plugin = [ {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017e5e52cb4320414e8ce3e2089eae2cb87c22c73ff6012b17ae326fc5753b20"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a57136d4866de5dc80cfb24d66655955fbdd87acf1d11d88c8dc2ab41023e46"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:f339511d0fccb69e3a5e3af39f8fe6700b0a07279015006ea56f8f49e7fecff4"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05e821ecd90bb0b8d2dc7610625372cc47de9cb893d09662528bad572f669d1c"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33886a5f9796fe9a8a3bc25ccfdeba7db119adb50b7004f1928a14b07d0213a"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75b7ed186c2f740dd26e556f6a966c59a170b70263e429a2c81920fe444da8a7"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11aef6b79078b8dad25c928e5871c146ab94424472851d5bf539ba62abde9ac"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10696c536d68a14cefea3b98edb8d5a7ae29e8e07458f1d59c5d1cd780a8bf2a"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1a7291d6a5fb7336e72685a31d193e0b3a6bee9986c9ac4d8bd4b68dbe6d4f7f"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:14b9c5dbf237e7dc12f69819ea181a457b3bd4f59f8cd71d028d3635fd3bcab4"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:799cbfbeee831332d280c80df9ce16b5c3b1224c318264e97e89df8da32e870e"}, @@ -6934,13 +6945,11 @@ pyprof2calltree = [ ] pyproj = [ {file = "pyproj-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f343725566267a296b09ee7e591894f1fdc90f84f8ad5ec476aeb53bd4479c07"}, - {file = "pyproj-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5816807ca0bdc7256558770c6206a6783a3f02bcf844f94ee245f197bb5f7285"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e609903572a56cca758bbaee5c1663c3e829ddce5eec4f368e68277e37022b"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fd425ee8b6781c249c7adb7daa2e6c41ce573afabe4f380f5eecd913b56a3be"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954b068136518b3174d0a99448056e97af62b63392a95c420894f7de2229dae6"}, {file = "pyproj-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:4a23d84c5ffc383c7d9f0bde3a06fc1f6697b1b96725597f8f01e7b4bef0a2b5"}, {file = "pyproj-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f9c100fd0fd80edbc7e4daa303600a8cbef6f0de43d005617acb38276b88dc0"}, - {file = "pyproj-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa5171f700f174777a9e9ed8f4655583243967c0f9cf2c90e3f54e54ff740134"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a496d9057b2128db9d733e66b206f2d5954bbae6b800d412f562d780561478c"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52e54796e2d9554a5eb8f11df4748af1fbbc47f76aa234d6faf09216a84554c5"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a454a7c4423faa2a14e939d08ef293ee347fa529c9df79022b0585a6e1d8310c"}, @@ -6951,7 +6960,6 @@ pyproj = [ {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f80adda8c54b84271a93829477a01aa57bc178c834362e9f74e1de1b5033c74c"}, {file = "pyproj-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:221d8939685e0c43ee594c9f04b6a73a10e8e1cc0e85f28be0b4eb2f1bc8777d"}, {file = "pyproj-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d94afed99f31673d3d19fe750283621e193e2a53ca9e0443bf9d092c3905833b"}, - {file = "pyproj-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fff9c3a991508f16027be27d153f6c5583d03799443639d13c681e60f49e2d7"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85acf09e5a9e35cd9ee72989793adb7089b4e611be02a43d3d0bda50ad116b"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45554f47d1a12a84b0620e4abc08a2a1b5d9f273a4759eaef75e74788ec7162a"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f62c20656ac9b6076ebb213e9a635d52f4f01fef95310121d337e62e910cb6"}, diff --git a/pyproject.toml b/pyproject.toml index cbb5a983f3..30aa1c1747 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,7 @@ configargparse = "^1.5.3" cupy-cuda113 = "^10.6.0" datadog = "^0.44.0" dotmap = "^1.3.30" +einops = "^0.5.0" elasticsearch = "^8.3.1" Flask-Cors = "^3.0.10" Flask-SocketIO = "^5.2.0" From 3af2c1b363856c7bc92770861da2d3efc92084e9 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 22 Oct 2022 11:41:45 -0700 Subject: [PATCH 0061/1179] deps(xx): bump onnxoptimizer --- poetry.lock | 27 ++++++++++++--------------- pyproject.toml | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/poetry.lock b/poetry.lock index 41fe2eb18c..2dff4fecf1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2441,7 +2441,7 @@ lint = ["clang-format (==13.0.0)", "flake8", "mypy (==0.782)", "types-protobuf ( [[package]] name = "onnxoptimizer" -version = "0.2.7" +version = "0.3.1" description = "Open Neural Network Exchange" category = "dev" optional = false @@ -4378,7 +4378,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "e596391b3ebe3de6835da44c7a4e9018e5e4c1f5a5450568ebfc156fa2c0ae0c" +content-hash = "76f06d46b1c308e59968994e42193599d8ba3cab6d552460c9c48f282313b64d" [metadata.files] adal = [ @@ -6380,19 +6380,16 @@ onnx = [ {file = "onnx-1.12.0.tar.gz", hash = "sha256:13b3e77d27523b9dbf4f30dfc9c959455859d5e34e921c44f712d69b8369eff9"}, ] onnxoptimizer = [ - {file = "onnxoptimizer-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1aba09d802146bd0e08d9feb83b1e47edc52aa560e48e87451554d436ff07c99"}, - {file = "onnxoptimizer-0.2.7-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:cba1ee65fe5e5752b887138ad805dc5b3845f09921b962a62b4dc9083b486f73"}, - {file = "onnxoptimizer-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f161979d34d9db636c623d0681c73de0cbe349805929cf966f7e657457a20d82"}, - {file = "onnxoptimizer-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:884ac67280d3a4929c7154660105e6ca034d5a222c989864899056225a0aaa61"}, - {file = "onnxoptimizer-0.2.7-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f67e5119419da0f85251d607097fbf486354cc65871caf859acb572526e5d4b0"}, - {file = "onnxoptimizer-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:0b604e402564ae1231e43edbd0ce766256fcd301f63b00ce8abe4e4f5dd23265"}, - {file = "onnxoptimizer-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7cfa72afc54735cf9a66ae7eaca40b6cddf9590e0c63c4f8761e03674b24a53"}, - {file = "onnxoptimizer-0.2.7-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:07b028534dd592eb6d6cc5f95fb0b4cb6d9470ce8846c81d0fb24047af70397d"}, - {file = "onnxoptimizer-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:42247221a35a8cf4cfa9f8f657b0cb234248c4d6ebe54ba03723468449de61c2"}, - {file = "onnxoptimizer-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c139cd3bebc3f3ea7d1386282a4168bd02bf4d15c261d50896ef517858aa8b8d"}, - {file = "onnxoptimizer-0.2.7-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e278c11eae62a631c342d3618bf315017f6fc54b2e3fbe7840b0a1700e722da4"}, - {file = "onnxoptimizer-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:86bdb883f33078d3ed89f2ff452e9b0b37624e332dc7d7aa49a23f0ce11c2478"}, - {file = "onnxoptimizer-0.2.7.tar.gz", hash = "sha256:a9f972b2b68ceb82b1f268042879f807fceb9ad76e38def2a39f102e62216d21"}, + {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, + {file = "onnxoptimizer-0.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bf2bfe0dc43f0776867688e1759122dec049ff4f45f7221931b687fe7e139e"}, + {file = "onnxoptimizer-0.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a9a815bba418abfb23f319838370cfd9450305a2da7d970a2261046889a70730"}, + {file = "onnxoptimizer-0.3.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:60f1d3600f03466a451c05e3d12ce97565bae016e46f70396ba22208cfeae6f6"}, + {file = "onnxoptimizer-0.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:056a765593d197b2b643bfb35520a66eacebfc682583d9ac0389a56c2a259e6f"}, + {file = "onnxoptimizer-0.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:15da6a036df388c3f08c3fc638b4d313ee6a1b96aaaa1c602fd1b424dd7bbc23"}, + {file = "onnxoptimizer-0.3.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5547203ee3392e3dabcea68a3a4d316ee0269ad3cf8a3504d1f68d467f60a06a"}, + {file = "onnxoptimizer-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c773b03313e253a60c7d8fe56ea5bba38fb3442ab84a825468a35a739e8fb20b"}, + {file = "onnxoptimizer-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:aac4d5c4c5f4c471346dfb28356355b0c54c074a1f2fe1fe122b197f68c08a92"}, + {file = "onnxoptimizer-0.3.1.tar.gz", hash = "sha256:0aa2e873a49f3762822e4400e1e8886236156f9d1dbf20319e2c18f7ebfb6a1d"}, ] onnxruntime-gpu = [ {file = "onnxruntime_gpu-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42b0393c5122ed90fa2eb76192a486261d86e9526ccb78b2a98923c22791d2d1"}, diff --git a/pyproject.toml b/pyproject.toml index 30aa1c1747..ebb7954536 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,7 +145,7 @@ mpld3 = "^0.5.8" msgpack-python = "^0.5.6" networkx = "~2.3" nvidia-ml-py3 = "^7.352.0" -onnxoptimizer = "^0.2.6" +onnxoptimizer = "^0.3.1" opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" } osmium = "^3.3.0" pandas = "^1.4.3" From 8a0475bd3bc4c86777be234d393a4e80da1a5fcd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 22 Oct 2022 16:15:03 -0700 Subject: [PATCH 0062/1179] cabana: fix BinaryView byte indices --- tools/cabana/binaryview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index eee3f90986..785e5c4a05 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -212,7 +212,7 @@ void BinaryViewModel::updateState() { 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::DisplayRole: return section; case Qt::SizeHintRole: return QSize(30, CELL_HEIGHT); case Qt::TextAlignmentRole: return Qt::AlignCenter; } From 6d443007bcf47b02972e9b5f0ccc84ba1ff5165d Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 23 Oct 2022 14:03:58 -0400 Subject: [PATCH 0063/1179] VW MQB: Add FW for 2016 Volkswagen Passat (#26212) --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 8c679c7406..695868452d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -555,6 +555,7 @@ FW_VERSIONS = { b'\xf1\x8703N906026E \xf1\x892114', b'\xf1\x8704E906023AH\xf1\x893379', b'\xf1\x8704L906026ET\xf1\x891990', + b'\xf1\x8704L906026FP\xf1\x892012', b'\xf1\x8704L906026GA\xf1\x892013', b'\xf1\x8704L906026KD\xf1\x894798', b'\xf1\x873G0906264 \xf1\x890004', @@ -562,6 +563,7 @@ FW_VERSIONS = { (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870CW300043H \xf1\x891601', b'\xf1\x870CW300048R \xf1\x890610', + b'\xf1\x870D9300013A \xf1\x894905', b'\xf1\x870D9300014L \xf1\x895002', b'\xf1\x870D9300041A \xf1\x894801', b'\xf1\x870DD300045T \xf1\x891601', @@ -579,6 +581,7 @@ FW_VERSIONS = { ], (Ecu.eps, 0x712, None): [ b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00611A1', + b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00711A1', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0060803', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521B00606A1', From 80c565d9fe9b10a05e34ae867f7711389ae240d1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Oct 2022 04:38:38 +0800 Subject: [PATCH 0064/1179] Cabana: no popup when adding a new signal. (#26155) * merge master * GM: make loopback updated check more explicit This previously checked if parser_pyx filled the defaultdict, now it checks the values in the list (same either way) * merge master * continue * continue * check for duplicate name * check duplicate signal name in saveSignal * check signal size * size*8 * cleanup * check size after push_back * install qlog handler at end * remove todo Co-authored-by: Shane Smiskol --- tools/cabana/binaryview.cc | 6 --- tools/cabana/canmessages.cc | 4 +- tools/cabana/dbcmanager.cc | 18 ++++++++ tools/cabana/dbcmanager.h | 2 + tools/cabana/detailwidget.cc | 77 +++++++++++++++++++-------------- tools/cabana/detailwidget.h | 6 +-- tools/cabana/mainwin.cc | 6 +-- tools/cabana/signaledit.cc | 84 +++++++++++++----------------------- tools/cabana/signaledit.h | 23 ++++------ 9 files changed, 109 insertions(+), 117 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 785e5c4a05..915ec8bb8f 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -13,12 +13,6 @@ const int CELL_HEIGHT = 30; -static std::pair getSignalRange(const Signal *s) { - int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit); - int to = from + s->size - 1; - return {from, to}; -} - BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { model = new BinaryViewModel(this); setModel(model); diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index defeacd75a..d88f34801b 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -54,9 +54,9 @@ QList CANMessages::findSignalValues(const QString &id, const Signal *si double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), *signal); if ((flag == EQ && val == value) || (flag == LT && val < value) || (flag == GT && val > value)) { ret.push_back({(evt->mono_time / (double)1e9) - can->routeStartTime(), val}); + if (ret.size() >= max_count) + return ret; } - if (ret.size() >= max_count) - return ret; } } } diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index fc40fc58e4..c3fbab0349 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -121,3 +121,21 @@ double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) { double value = val * sig.factor + sig.offset; return value; } + +void updateSigSizeParamsFromRange(Signal &s, int from, int to) { + s.start_bit = s.is_little_endian ? from : bigEndianBitIndex(from); + s.size = to - from + 1; + if (s.is_little_endian) { + s.lsb = s.start_bit; + s.msb = s.start_bit + s.size - 1; + } else { + s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); + s.msb = s.start_bit; + } +} + +std::pair getSignalRange(const Signal *s) { + int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit); + int to = from + s->size - 1; + return {from, to}; +} diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 74d935119a..9e64c4ed53 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -47,5 +47,7 @@ private: double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig); int bigEndianStartBitsIndex(int start_bit); int bigEndianBitIndex(int index); +void updateSigSizeParamsFromRange(Signal &s, int from, int to); +std::pair getSignalRange(const Signal *s); DBCManager *dbc(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 039a7c4e55..443b33b521 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -48,7 +48,7 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { warning_widget = new QWidget(this); QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); QLabel *warning_icon = new QLabel(this); - warning_icon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap({16, 16})); + warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning)); warning_hlayout->addWidget(warning_icon); warning_label = new QLabel(this); warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); @@ -78,7 +78,7 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); - QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::dbcMsgChanged); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { dbcMsgChanged(); }); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { setMessage(messages[index]); }); QObject::connect(tabbar, &QTabBar::tabCloseRequested, [=](int index) { messages.removeAt(index); @@ -103,7 +103,7 @@ void DetailWidget::setMessage(const QString &message_id) { dbcMsgChanged(); } -void DetailWidget::dbcMsgChanged() { +void DetailWidget::dbcMsgChanged(int show_form_idx) { if (msg_id.isEmpty()) return; warning_widget->hide(); @@ -111,7 +111,7 @@ void DetailWidget::dbcMsgChanged() { 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]); + 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); @@ -119,6 +119,9 @@ void DetailWidget::dbcMsgChanged() { QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); + if (i == show_form_idx) { + QTimer::singleShot(0, [=]() { emit form->showFormClicked(); }); + } } msg_name = msg->name.c_str(); if (msg->size != can->lastMessage(msg_id).dat.size()) { @@ -162,46 +165,54 @@ void DetailWidget::editMsg() { } } -void DetailWidget::addSignal(int start_bit, int to) { - if (dbc()->msg(msg_id)) { - AddSignalDialog dlg(msg_id, start_bit, to - start_bit + 1, this); - if (dlg.exec()) { - dbc()->addSignal(msg_id, dlg.form->getSignal()); - dbcMsgChanged(); +void DetailWidget::addSignal(int from, int to) { + if (auto msg = dbc()->msg(msg_id)) { + Signal sig = {}; + for (int i = 1; /**/; ++i) { + sig.name = "NEW_SIGNAL_" + std::to_string(i); + auto it = std::find_if(msg->sigs.begin(), msg->sigs.end(), [&](auto &s) { return sig.name == s.name; }); + if (it == msg->sigs.end()) break; } + sig.is_little_endian = false, + updateSigSizeParamsFromRange(sig, from, to); + dbc()->addSignal(msg_id, sig); + dbcMsgChanged(msg->sigs.size() - 1); } } void DetailWidget::resizeSignal(const Signal *sig, int from, int to) { - assert(sig != nullptr); Signal s = *sig; - s.start_bit = s.is_little_endian ? from : bigEndianBitIndex(from);; - s.size = to - from + 1; - if (s.is_little_endian) { - s.lsb = s.start_bit; - s.msb = s.start_bit + s.size - 1; - } else { - s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); - s.msb = s.start_bit; + updateSigSizeParamsFromRange(s, from, to); + saveSignal(sig, s); +} + +void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) { + auto msg = dbc()->msg(msg_id); + if (new_sig.name != sig->name) { + auto it = std::find_if(msg->sigs.begin(), msg->sigs.end(), [&](auto &s) { return s.name == new_sig.name; }); + if (it != msg->sigs.end()) { + QString warning_str = tr("There is already a signal with the same name '%1'").arg(new_sig.name.c_str()); + QMessageBox::warning(this, tr("Failed to save signal"), warning_str); + return; + } } - dbc()->updateSignal(msg_id, s.name.c_str(), s); + + auto [start, end] = getSignalRange(&new_sig); + if (start < 0 || end >= msg->size * 8) { + QString warning_str = tr("Signal size [%1] exceed limit").arg(new_sig.size); + QMessageBox::warning(this, tr("Failed to save signal"), warning_str); + return; + } + + dbc()->updateSignal(msg_id, sig->name.c_str(), new_sig); + // update binary view and history log 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); +void DetailWidget::removeSignal(const Signal *sig) { + QString text = tr("Are you sure you want to remove signal '%1'").arg(sig->name.c_str()); if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove signal"), text)) { - dbc()->removeSignal(msg_id, sig_form->sig_name); + dbc()->removeSignal(msg_id, sig->name.c_str()); dbcMsgChanged(); } } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 02bbb2a9e8..5924cdd43f 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -32,7 +32,7 @@ class DetailWidget : public QWidget { public: DetailWidget(QWidget *parent); void setMessage(const QString &message_id); - void dbcMsgChanged(); + void dbcMsgChanged(int show_form_idx = -1); signals: void showChart(const QString &msg_id, const Signal *sig); @@ -41,8 +41,8 @@ signals: private: void addSignal(int start_bit, int to); void resizeSignal(const Signal *sig, int from, int to); - void saveSignal(); - void removeSignal(); + void saveSignal(const Signal *sig, const Signal &new_sig); + void removeSignal(const Signal *sig); void editMsg(); void showForm(); void updateState(); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d0e171c86e..65e7bb1af8 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -14,9 +14,6 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const } MainWindow::MainWindow() : QWidget() { - main_win = this; - qInstallMessageHandler(qLogMessageHandler); - QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(11, 11, 11, 5); main_layout->setSpacing(0); @@ -88,6 +85,9 @@ MainWindow::MainWindow() : QWidget() { QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(settings_btn, &QPushButton::clicked, this, &MainWindow::setOption); QObject::connect(can, &CANMessages::eventsMerged, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); + + main_win = this; + qInstallMessageHandler(qLogMessageHandler); } void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool success) { diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d5dccf0e6d..3926cda01f 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -11,7 +12,7 @@ // SignalForm -SignalForm::SignalForm(const Signal &sig, QWidget *parent) : start_bit(sig.start_bit), QWidget(parent) { +SignalForm::SignalForm(const Signal &sig, QWidget *parent) : QWidget(parent) { QFormLayout *form_layout = new QFormLayout(this); name = new QLineEdit(sig.name.c_str()); @@ -59,30 +60,9 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : start_bit(sig.start form_layout->addRow(tr("Value descriptions"), val_desc); } -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(); - sig.size = size->text().toInt(); - sig.offset = offset->text().toDouble(); - sig.factor = factor->text().toDouble(); - sig.is_signed = sign->currentIndex() == 0; - sig.is_little_endian = endianness->currentIndex() == 0; - if (sig.is_little_endian) { - sig.lsb = sig.start_bit; - sig.msb = sig.start_bit + sig.size - 1; - } else { - sig.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(sig.start_bit) + sig.size - 1); - sig.msb = sig.start_bit; - } - return sig; -} - // SignalEdit -SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWidget *parent) - : sig(&sig), form_idx(index), sig_name(sig.name.c_str()), QWidget(parent) { +SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWidget *parent) : msg_id(msg_id), sig(sig), form_idx(index), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -93,7 +73,7 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWid 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->setText(QString("%1. %2").arg(index + 1).arg(sig->name.c_str())); title->setStyleSheet(QString("font-weight:bold; color:%1").arg(getColor(index))); title_layout->addWidget(title, 1); @@ -113,7 +93,7 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWid // signal form form_container = new QWidget(this); QVBoxLayout *v_layout = new QVBoxLayout(form_container); - form = new SignalForm(sig, this); + form = new SignalForm(*sig, this); v_layout->addWidget(form); QHBoxLayout *h = new QHBoxLayout(); @@ -133,20 +113,34 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal &sig, QWid hline->setFrameShadow(QFrame::Sunken); main_layout->addWidget(hline); - QObject::connect(remove_btn, &QPushButton::clicked, this, &SignalEdit::remove); + QObject::connect(remove_btn, &QPushButton::clicked, [this]() { emit remove(this->sig); }); QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); - 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(seek_btn, &QPushButton::clicked, [this, msg_id, s = &sig]() { - SignalFindDlg dlg(msg_id, s, this); + QObject::connect(save_btn, &QPushButton::clicked, this, &SignalEdit::saveSignal); + QObject::connect(seek_btn, &QPushButton::clicked, [this, msg_id]() { + SignalFindDlg dlg(msg_id, this->sig, this); dlg.exec(); }); } +void SignalEdit::saveSignal() { + Signal s = *sig; + s.name = form->name->text().toStdString(); + s.size = form->size->text().toInt(); + s.offset = form->offset->text().toDouble(); + s.factor = form->factor->text().toDouble(); + s.is_signed = form->sign->currentIndex() == 0; + s.is_little_endian = form->endianness->currentIndex() == 0; + if (s.is_little_endian) { + s.lsb = s.start_bit; + s.msb = s.start_bit + s.size - 1; + } else { + s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); + s.msb = s.start_bit; + } + title->setText(QString("%1. %2").arg(form_idx + 1).arg(form->name->text())); + emit save(this->sig, s); +} + void SignalEdit::setFormVisible(bool visible) { form_container->setVisible(visible); icon->setText(visible ? "▼" : ">"); @@ -167,27 +161,7 @@ void SignalEdit::leaveEvent(QEvent *event) { QWidget::leaveEvent(event); } -// AddSignalDialog - -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", - .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, this, &QDialog::accept); -} +// SignalFindDlg SignalFindDlg::SignalFindDlg(const QString &id, const Signal *signal, QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Find signal values")); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 1213b3ec51..472453d4b1 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -15,48 +15,41 @@ class SignalForm : public QWidget { public: SignalForm(const Signal &sig, QWidget *parent); - Signal getSignal(); QLineEdit *name, *unit, *comment, *val_desc; QSpinBox *size, *offset; QDoubleSpinBox *factor, *min_val, *max_val; QComboBox *sign, *endianness; - int start_bit = 0; }; class SignalEdit : public QWidget { Q_OBJECT public: - SignalEdit(int index, const QString &msg_id, const Signal &sig, QWidget *parent = nullptr); + SignalEdit(int index, const QString &msg_id, const Signal *sig, QWidget *parent = nullptr); void setFormVisible(bool show); void signalHovered(const Signal *sig); inline bool isFormVisible() const { return form_container->isVisible(); } - QString sig_name; - SignalForm *form; - int form_idx = 0; - const Signal *sig = nullptr; signals: void highlight(const Signal *sig); void showChart(); void showFormClicked(); - void remove(); - void save(); + void remove(const Signal *sig); + void save(const Signal *sig, const Signal &new_sig); protected: void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; + void saveSignal(); + SignalForm *form; ElidedLabel *title; QWidget *form_container; QLabel *icon; -}; - -class AddSignalDialog : public QDialog { -public: - AddSignalDialog(const QString &id, int start_bit, int size, QWidget *parent); - SignalForm *form; + int form_idx = 0; + QString msg_id; + const Signal *sig = nullptr; }; class SignalFindDlg : public QDialog { From 64f89beb0d8d594e10876b2df11cfdba42b8c2c1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Oct 2022 04:39:06 +0800 Subject: [PATCH 0065/1179] Cabana: delete all selected cells when shrinking signal (#26211) --- tools/cabana/binaryview.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 915ec8bb8f..ed5f243f08 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -86,7 +86,8 @@ void BinaryView::mouseReleaseEvent(QMouseEvent *event) { if (auto sig = getResizingSignal()) { auto [sig_from, sig_to] = getSignalRange(sig); if (from >= sig_from && to <= sig_to) { // reduce size - emit(from == sig_from ? resizeSignal(sig, to, sig_to) : resizeSignal(sig, sig_from, from)); + emit(from == sig_from ? resizeSignal(sig, std::min(to + 1, sig_to), sig_to) + : resizeSignal(sig, sig_from, std::max(from - 1, sig_from))); } else { // increase size emit resizeSignal(sig, std::min(from, sig_from), std::max(to, sig_to)); } From 0844662f845130bb536d7c8cad093fffbdefd761 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Oct 2022 04:39:38 +0800 Subject: [PATCH 0066/1179] Cabana: use deque::resize() instead of pop_back in loop (#26209) use resize instead of pop_front in loop --- tools/cabana/canmessages.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index d88f34801b..d2141c3630 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -71,8 +71,8 @@ void CANMessages::process(QHash> *messages) { msgs = std::move(new_msgs); } else { msgs.insert(msgs.begin(), std::make_move_iterator(new_msgs.begin()), std::make_move_iterator(new_msgs.end())); - while (msgs.size() >= settings.can_msg_log_size) { - msgs.pop_back(); + if (msgs.size() > settings.can_msg_log_size) { + msgs.resize(settings.can_msg_log_size); } } } From 062267f4696c304b6ed0824a3b1046fecdd07e04 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Oct 2022 04:57:32 +0800 Subject: [PATCH 0067/1179] replay: reduce test running time (#26160) --- tools/replay/tests/test_replay.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/replay/tests/test_replay.cc b/tools/replay/tests/test_replay.cc index 5b61b6b6f2..30e3c811ee 100644 --- a/tools/replay/tests/test_replay.cc +++ b/tools/replay/tests/test_replay.cc @@ -197,8 +197,8 @@ void TestReplay::test_seek() { stream_thread_ = new QThread(this); QEventLoop loop; std::thread thread = std::thread([&]() { - for (int i = 0; i < 50; ++i) { - testSeekTo(random_int(0, 3 * 60)); + for (int i = 0; i < 10; ++i) { + testSeekTo(random_int(0, 1 * 60)); } loop.quit(); }); @@ -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); REQUIRE(replay.load()); replay.test_seek(); } From 60b666fe3b24495b8a6c51dc016988049803bc2d Mon Sep 17 00:00:00 2001 From: Oxygen Date: Mon, 24 Oct 2022 06:25:50 +0800 Subject: [PATCH 0068/1179] Add #include in cabana (#26208) * Add #include * fix import order Co-authored-by: Cameron Clough --- tools/cabana/messageswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index c289f54fc4..9b831ad18c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include From 20dced4edcbebfcf496800fb236f0d6f2be26665 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 24 Oct 2022 06:28:25 +0800 Subject: [PATCH 0069/1179] Cabana: Added ability to highlight and resize overlapped signals (#26210) --- tools/cabana/binaryview.cc | 22 +++++++++++++--------- tools/cabana/binaryview.h | 3 ++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index ed5f243f08..5d191d2ca3 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -70,9 +70,10 @@ void BinaryView::mousePressEvent(QMouseEvent *event) { void BinaryView::mouseMoveEvent(QMouseEvent *event) { if (auto index = indexAt(event->pos()); index.isValid()) { auto item = (BinaryViewModel::Item *)index.internalPointer(); - highlight(item->sig); - item->sig ? QToolTip::showText(event->globalPos(), item->sig->name.c_str(), this, rect()) - : QToolTip::hideText(); + const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); + highlight(sig); + sig ? QToolTip::showText(event->globalPos(), sig->name.c_str(), this, rect()) + : QToolTip::hideText(); } QTableView::mouseMoveEvent(event); } @@ -119,11 +120,13 @@ void BinaryView::updateState() { const Signal *BinaryView::getResizingSignal() const { if (anchor_index.isValid()) { auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); - if (item && item->sig) { + if (item && item->sigs.size() > 0) { int archor_pos = anchor_index.row() * 8 + anchor_index.column(); - auto [sig_from, sig_to] = getSignalRange(item->sig); - if (archor_pos == sig_from || archor_pos == sig_to) - return item->sig; + for (auto s : item->sigs) { + auto [sig_from, sig_to] = getSignalRange(s); + if (archor_pos == sig_from || archor_pos == sig_to) + return s; + } } } return nullptr; @@ -157,7 +160,7 @@ void BinaryViewModel::setMessage(const QString &message_id) { sig.is_little_endian ? items[idx].is_msb = true : items[idx].is_lsb = true; } items[idx].bg_color = getColor(i); - items[idx].sig = &dbc_msg->sigs[i]; + items[idx].sigs.push_back(&dbc_msg->sigs[i]); } } } @@ -235,7 +238,8 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op BinaryView *bin_view = (BinaryView *)parent(); painter->save(); - bool hover = item->sig && bin_view->hoveredSignal() == item->sig; + bool hover = std::find_if(item->sigs.begin(), item->sigs.end(), [=](auto s) { return s == bin_view->hoveredSignal(); }) != + item->sigs.end(); // background QColor bg_color = hover ? hoverColor(item->bg_color) : item->bg_color; if (option.state & QStyle::State_Selected) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 8c1a582014..e57033b797 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -38,7 +39,7 @@ public: bool is_msb = false; bool is_lsb = false; QString val = "0"; - const Signal *sig = nullptr; + QList sigs; }; private: From 1be5cecfa256c16ae8ec9f71bbcd1a57220bf282 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sun, 23 Oct 2022 15:49:32 -0700 Subject: [PATCH 0070/1179] add poetry-dotenv-plugin (#26216) --- update_requirements.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/update_requirements.sh b/update_requirements.sh index 0967e2dc6c..8511a0a4d6 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -60,6 +60,7 @@ if [ -d "./xx" ] || [ -n "$POETRY_VIRTUALENVS_CREATE" ]; then RUN="" else echo "PYTHONPATH=${PWD}" > .env + poetry self add poetry-dotenv-plugin@^0.1.0 RUN="poetry run" fi From c00afb51be233cb507f18021cf5a44eea32e237e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 24 Oct 2022 10:58:00 -0700 Subject: [PATCH 0071/1179] Multilang: remove locations (#26223) remove locations from langs not in UI --- selfdrive/ui/translations/main_ar.ts | 391 +++++++-------------------- selfdrive/ui/translations/main_nl.ts | 391 +++++++-------------------- selfdrive/ui/translations/main_pl.ts | 391 +++++++-------------------- selfdrive/ui/translations/main_th.ts | 391 +++++++-------------------- 4 files changed, 408 insertions(+), 1156 deletions(-) diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index a94d2fbc05..3c47e6e8e8 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -4,17 +4,14 @@ AbstractAlert - Close أغلق - Snooze Update تأخير التحديث - Reboot and Update إعادة التشغيل والتحديث @@ -22,67 +19,84 @@ AdvancedNetworking - Back خلف - Enable Tethering تمكين الربط - Tethering Password كلمة مرور للربط - - EDIT تعديل - Enter new tethering password أدخل كلمة مرور جديدة للربط - IP Address عنوان IP - Enable Roaming تمكين التجوال - APN Setting إعداد APN - Enter APN أدخل APN - leave blank for automatic configuration اتركه فارغا للتكوين التلقائي + + Cellular Metered + + + + Prevent large data uploads when on a metered connection + + + + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + الأعلى + + + SPEED + سرعة + + + LIMIT + حد + ConfirmationDialog - - Ok موافق - Cancel إلغاء @@ -90,17 +104,14 @@ DeclinePage - You must accept the Terms and Conditions in order to use openpilot. يجب عليك قبول الشروط والأحكام من أجل استخدام openpilot. - Back خلف - Decline, uninstall %1 رفض ، قم بإلغاء تثبيت %1 @@ -108,152 +119,122 @@ DevicePanel - Dongle ID معرف دونجل - N/A غير متاح - Serial التسلسلي - Driver Camera كاميرا السائق - PREVIEW لمح - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) قم بمعاينة الكاميرا المواجهة للسائق للتأكد من أن نظام مراقبة السائق يتمتع برؤية جيدة. (يجب أن تكون السيارة معطلة) - Reset Calibration إعادة ضبط المعايرة - RESET إعادة تعيين - Are you sure you want to reset calibration? هل أنت متأكد أنك تريد إعادة ضبط المعايرة؟ - Review Training Guide مراجعة دليل التدريب - REVIEW مراجعة - Review the rules, features, and limitations of openpilot راجع القواعد والميزات والقيود الخاصة بـ openpilot - Are you sure you want to review the training guide? هل أنت متأكد أنك تريد مراجعة دليل التدريب؟ - Regulatory تنظيمية - VIEW عرض - Change Language تغيير اللغة - CHANGE تغيير - Select a language اختر لغة - Reboot اعادة التشغيل - Power Off أطفاء - openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. يتطلب openpilot أن يتم تركيب الجهاز في حدود 4 درجات يسارًا أو يمينًا و 5 درجات لأعلى أو 8 درجات لأسفل. يقوم برنامج openpilot بالمعايرة بشكل مستمر ، ونادراً ما تكون إعادة الضبط مطلوبة. - Your device is pointed %1° %2 and %3° %4. جهازك يشير %1° %2 و %3° %4. - down لأسفل - up إلى أعلى - left إلى اليسار - right إلى اليمين - Are you sure you want to reboot? هل أنت متأكد أنك تريد إعادة التشغيل؟ - Disengage to Reboot فك الارتباط لإعادة التشغيل - Are you sure you want to power off? هل أنت متأكد أنك تريد إيقاف التشغيل؟ - Disengage to Power Off فك الارتباط لإيقاف التشغيل @@ -261,32 +242,26 @@ DriveStats - Drives أرقام القيادة - Hours ساعات - ALL TIME في كل وقت - PAST WEEK الأسبوع الماضي - KM كم - Miles اميال @@ -294,7 +269,6 @@ DriverViewScene - camera starting بدء تشغيل الكاميرا @@ -302,12 +276,10 @@ InputDialog - Cancel إلغاء - Need at least %n character(s)! تحتاج على الأقل %n حرف! @@ -322,22 +294,18 @@ Installer - Installing... جارٍ التثبيت ... - Receiving objects: استقبال الكائنات: - Resolving deltas: حل دلتا: - Updating files: جارٍ تحديث الملفات: @@ -345,27 +313,22 @@ MapETA - eta eta - min دق - hr سع - km كم - mi مل @@ -373,22 +336,18 @@ MapInstructions - km كم - m م - mi مل - ft قد @@ -396,48 +355,40 @@ MapPanel - Current Destination الوجهة الحالية - CLEAR مسح - Recent Destinations الوجهات الأخيرة - Try the Navigation Beta جرب التنقل التجريبي - Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai احصل على الاتجاهات خطوة بخطوة معروضة والمزيد باستخدام comma الاشتراك الرئيسي. اشترك الآن: https://connect.comma.ai - No home location set لم يتم تعيين موقع المنزل - No work location set لم يتم تعيين موقع العمل - no recent destinations لا توجد وجهات حديثة @@ -445,12 +396,10 @@ location set MapWindow - Map Loading تحميل الخريطة - Waiting for GPS في انتظار GPS @@ -458,12 +407,10 @@ location set MultiOptionDialog - Select اختر - Cancel إلغاء @@ -471,72 +418,33 @@ location set Networking - Advanced متقدم - Enter password أدخل كلمة المرور - - for "%1" ل "%1" - Wrong password كلمة مرور خاطئة - - AnnotatedCameraWidget - - - km/h - km/h - - - - mph - mph - - - - - MAX - الأعلى - - - - - SPEED - سرعة - - - - - LIMIT - حد - - OffroadHome - UPDATE تحديث - ALERTS تنبيهات - ALERT تنبيه @@ -544,22 +452,18 @@ location set PairingPopup - Pair your device to your comma account قم بإقران جهازك بحساب comma الخاص بك - Go to https://connect.comma.ai on your phone اذهب إلى https://connect.comma.ai من هاتفك - Click "add new device" and scan the QR code on the right انقر على "إضافة جهاز جديد" وامسح رمز الاستجابة السريعة على اليمين - Bookmark connect.comma.ai to your home screen to use it like an app ضع إشارة مرجعية على connect.comma.ai على شاشتك الرئيسية لاستخدامه مثل أي تطبيق @@ -567,32 +471,26 @@ location set PrimeAdWidget - Upgrade Now قم بالترقية الآن - Become a comma prime member at connect.comma.ai كن عضوًا comme prime في connect.comma.ai - PRIME FEATURES: ميزات PRIME: - Remote access الوصول عن بعد - 1 year of storage سنة واحدة من التخزين - Developer perks امتيازات المطور @@ -600,22 +498,18 @@ location set PrimeUserWidget - ✓ SUBSCRIBED ✓ مشترك - comma prime comma prime - CONNECT.COMMA.AI CONNECT.COMMA.AI - COMMA POINTS COMMA POINTS @@ -623,27 +517,22 @@ location set QObject - Reboot اعادة التشغيل - Exit أغلق - dashcam dashcam - openpilot openpilot - %n minute(s) ago منذ %n دقيقة @@ -655,7 +544,6 @@ location set - %n hour(s) ago منذ %n ساعة @@ -667,7 +555,6 @@ location set - %n day(s) ago منذ %n يوم @@ -682,47 +569,38 @@ location set Reset - Reset failed. Reboot to try again. فشل إعادة التعيين. أعد التشغيل للمحاولة مرة أخرى. - Are you sure you want to reset your device? هل أنت متأكد أنك تريد إعادة ضبط جهازك؟ - Resetting device... جارٍ إعادة ضبط الجهاز ... - System Reset إعادة تعيين النظام - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. تم تشغيل إعادة تعيين النظام. اضغط على تأكيد لمسح كل المحتوى والإعدادات. اضغط على إلغاء لاستئناف التمهيد. - Cancel إلغاء - Reboot اعادة التشغيل - Confirm تأكيد - Unable to mount data partition. Press confirm to reset your device. تعذر تحميل قسم البيانات. اضغط على تأكيد لإعادة ضبط جهازك. @@ -730,7 +608,6 @@ location set RichTextDialog - Ok موافق @@ -738,33 +615,26 @@ location set SettingsWindow - × x - Device جهاز - - Network شبكة الاتصال - Toggles التبديل - Software برمجة - Navigation ملاحة @@ -772,105 +642,82 @@ location set Setup - WARNING: Low Voltage تحذير: الجهد المنخفض - Power your device in a car with a harness or proceed at your own risk. قم بتشغيل جهازك في سيارة باستخدام أداة تثبيت أو المضي قدمًا على مسؤوليتك الخاصة. - Power off اطفئ الجهاز - - - Continue أكمل - Getting Started ابدء - Before we get on the road, let’s finish installation and cover some details. قبل أن ننطلق على الطريق ، دعنا ننتهي من التثبيت ونغطي بعض التفاصيل. - Connect to Wi-Fi اتصل بشبكة Wi-Fi - - Back خلف - Continue without Wi-Fi استمر بدون Wi-Fi - Waiting for internet في انتظار الاتصال بالإنترنت - Choose Software to Install اختر البرنامج المراد تثبيته - Dashcam Dashcam - Custom Software برامج مخصصة - Enter URL إدخال عنوان الموقع - for Custom Software للبرامج المخصصة - Downloading... جارى التحميل... - Download Failed فشل التنزيل - Ensure the entered URL is valid, and the device’s internet connection is good. تأكد من أن عنوان موقع الويب الذي تم إدخاله صالح ، وأن اتصال الجهاز بالإنترنت جيد. - Reboot device إعادة تشغيل الجهاز - Start over ابدأ من جديد @@ -878,17 +725,14 @@ location set SetupWidget - Finish Setup إنهاء الإعداد - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. قم بإقران جهازك بفاصلة connect (connect.comma.ai) واطلب عرض comma prime الخاص بك. - Pair device إقران الجهاز @@ -896,106 +740,82 @@ location set Sidebar - - CONNECT الاتصال - OFFLINE غير متصل - - ONLINE متصل - ERROR خطأ - - - TEMP درجة الحرارة - HIGH عالي - GOOD جيد - OK موافق - VEHICLE مركبة - NO لا - PANDA PANDA - GPS GPS - SEARCH بحث - -- -- - Wi-Fi Wi-Fi - ETH ETH - 2G 2G - 3G 3G - LTE LTE - 5G 5G @@ -1003,138 +823,141 @@ location set SoftwarePanel - Git Branch - Git Branch + Git Branch - Git Commit - Git Commit + Git Commit - OS Version - إصدار نظام التشغيل + إصدار نظام التشغيل - Version - إصدار + إصدار - Last Update Check - التحقق من آخر تحديث + التحقق من آخر تحديث - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - آخر مرة نجح برنامج openpilot في التحقق من التحديث. يعمل المحدث فقط أثناء إيقاف تشغيل السيارة. + آخر مرة نجح برنامج openpilot في التحقق من التحديث. يعمل المحدث فقط أثناء إيقاف تشغيل السيارة. - Check for Update - فحص التحديثات + فحص التحديثات - CHECKING - تدقيق + تدقيق - Switch Branch - تبديل الفرع + تبديل الفرع - ENTER - أدخل + أدخل - - The new branch will be pulled the next time the updater runs. - سيتم سحب الفرع الجديد في المرة التالية التي يتم فيها تشغيل أداة التحديث. + سيتم سحب الفرع الجديد في المرة التالية التي يتم فيها تشغيل أداة التحديث. - Enter branch name - أدخل اسم الفرع + أدخل اسم الفرع - UNINSTALL الغاء التثبيت - Uninstall %1 الغاء التثبيت %1 - Are you sure you want to uninstall? هل أنت متأكد أنك تريد إلغاء التثبيت؟ - failed to fetch update - فشل في جلب التحديث + فشل في جلب التحديث - - CHECK تأكد الان + + Updates are only downloaded while the car is off. + + + + Current Version + + + + Download + + + + Install Update + + + + INSTALL + + + + Target Branch + + + + SELECT + + + + Select a branch + + SshControl - SSH Keys SSH Keys - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. تحذير: هذا يمنح SSH الوصول إلى جميع المفاتيح العامة في إعدادات GitHub. لا تدخل أبدًا اسم مستخدم GitHub بخلاف اسم المستخدم الخاص بك. لن يطلب منك موظف comma أبدًا إضافة اسم مستخدم GitHub الخاص به. - - ADD أضف - Enter your GitHub username أدخل اسم مستخدم GitHub الخاص بك - LOADING جار التحميل - REMOVE نزع - Username '%1' has no keys on GitHub لا يحتوي اسم المستخدم '%1' على مفاتيح على GitHub - Request timed out انتهت مهلة الطلب - Username '%1' doesn't exist on GitHub اسم المستخدم '%1' غير موجود على GitHub @@ -1142,7 +965,6 @@ location set SshToggle - Enable SSH تفعيل SSH @@ -1150,22 +972,18 @@ location set TermsPage - Terms & Conditions البنود و الظروف - Decline انحدار - Scroll to accept قم بالتمرير للقبول - Agree موافق @@ -1173,125 +991,125 @@ location set TogglesPanel - Enable openpilot تمكين openpilot - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. استخدم نظام الطيار المفتوح للتحكم التكيفي في ثبات السرعة والحفاظ على مساعدة السائق. انتباهك مطلوب في جميع الأوقات لاستخدام هذه الميزة. يسري تغيير هذا الإعداد عند إيقاف تشغيل السيارة. - Enable Lane Departure Warnings قم بتمكين تحذيرات مغادرة حارة السير - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). تلقي تنبيهات للتوجه مرة أخرى إلى الحارة عندما تنجرف سيارتك فوق خط المسار المكتشف دون تنشيط إشارة الانعطاف أثناء القيادة لمسافة تزيد عن 31 ميلاً في الساعة (50 كم / ساعة). - Use Metric System استخدم النظام المتري - Display speed in km/h instead of mph. عرض السرعة بالكيلو متر في الساعة بدلاً من ميل في الساعة. - Record and Upload Driver Camera تسجيل وتحميل كاميرا السائق - Upload data from the driver facing camera and help improve the driver monitoring algorithm. قم بتحميل البيانات من الكاميرا المواجهة للسائق وساعد في تحسين خوارزمية مراقبة السائق. - Disengage On Accelerator Pedal فك الارتباط على دواسة التسريع - When enabled, pressing the accelerator pedal will disengage openpilot. عند التمكين ، سيؤدي الضغط على دواسة الوقود إلى فصل الطيار المفتوح. - Show ETA in 24h Format إظهار الوقت المقدر للوصول بتنسيق 24 ساعة - Use 24h format instead of am/pm استخدم تنسيق 24 ساعة بدلاً من صباحًا / مساءً - Show Map on Left Side of UI إظهار الخريطة على الجانب الأيسر من واجهة المستخدم - Show map on left side when in split screen view. إظهار الخريطة على الجانب الأيسر عندما تكون في طريقة عرض الشاشة المنقسمة. - openpilot Longitudinal Control - openpilot التحكم الطولي + openpilot التحكم الطولي - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - سوف يقوم برنامج openpilot بتعطيل رادار السيارة وسيتولى التحكم في الغاز والمكابح. تحذير: هذا يعطل AEB! + سوف يقوم برنامج openpilot بتعطيل رادار السيارة وسيتولى التحكم في الغاز والمكابح. تحذير: هذا يعطل AEB! + + + 🌮 End-to-end longitudinal (extremely alpha) 🌮 + + + + Experimental openpilot longitudinal control + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> + + + + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. + + + + openpilot longitudinal control is not currently available for this car. + + + + Enable experimental longitudinal control to enable this. + Updater - Update Required مطلوب التحديث - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. مطلوب تحديث نظام التشغيل. قم بتوصيل جهازك بشبكة Wi-Fi للحصول على أسرع تجربة تحديث. حجم التنزيل 1 غيغابايت تقريبًا. - Connect to Wi-Fi اتصل بشبكة Wi-Fi - Install ثبيت - Back خلف - Loading... جار التحميل... - Reboot اعادة التشغيل - Update failed فشل التحديث @@ -1299,23 +1117,18 @@ location set WifiUI - - Scanning for networks... جارٍ البحث عن شبكات ... - CONNECTING... جارٍ الاتصال ... - FORGET نزع - Forget Wi-Fi Network "%1"? نزع شبكة اWi-Fi "%1"? diff --git a/selfdrive/ui/translations/main_nl.ts b/selfdrive/ui/translations/main_nl.ts index 21bb66d356..24d2031f31 100644 --- a/selfdrive/ui/translations/main_nl.ts +++ b/selfdrive/ui/translations/main_nl.ts @@ -4,17 +4,14 @@ AbstractAlert - Close Sluit - Snooze Update Update uitstellen - Reboot and Update Opnieuw Opstarten en Updaten @@ -22,67 +19,84 @@ AdvancedNetworking - Back Terug - Enable Tethering Tethering Inschakelen - Tethering Password Tethering Wachtwoord - - EDIT AANPASSEN - Enter new tethering password Voer nieuw tethering wachtwoord in - IP Address IP Adres - Enable Roaming Roaming Inschakelen - APN Setting APN Instelling - Enter APN Voer APN in - leave blank for automatic configuration laat leeg voor automatische configuratie + + Cellular Metered + + + + Prevent large data uploads when on a metered connection + + + + + AnnotatedCameraWidget + + km/h + km/u + + + mph + mph + + + MAX + MAX + + + SPEED + SPEED + + + LIMIT + LIMIT + ConfirmationDialog - - Ok Ok - Cancel Annuleren @@ -90,17 +104,14 @@ DeclinePage - You must accept the Terms and Conditions in order to use openpilot. U moet de Algemene Voorwaarden accepteren om openpilot te gebruiken. - Back Terug - Decline, uninstall %1 Afwijzen, verwijder %1 @@ -108,152 +119,122 @@ DevicePanel - Dongle ID Dongle ID - N/A Nvt - Serial Serienummer - Driver Camera Bestuurders Camera - PREVIEW BEKIJKEN - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) Bekijk de naar de bestuurder gerichte camera om ervoor te zorgen dat het monitoren van de bestuurder goed zicht heeft. (Voertuig moet uitgschakeld zijn) - Reset Calibration Kalibratie Resetten - RESET RESET - Are you sure you want to reset calibration? Weet u zeker dat u de kalibratie wilt resetten? - Review Training Guide Doorloop de Training Opnieuw - REVIEW BEKIJKEN - Review the rules, features, and limitations of openpilot Bekijk de regels, functies en beperkingen van openpilot - Are you sure you want to review the training guide? Weet u zeker dat u de training opnieuw wilt doorlopen? - Regulatory Regelgeving - VIEW BEKIJKEN - Change Language Taal Wijzigen - CHANGE WIJZIGEN - Select a language Selecteer een taal - Reboot Opnieuw Opstarten - Power Off Uitschakelen - openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. openpilot vereist dat het apparaat binnen 4° links of rechts en binnen 5° omhoog of 8° omlaag wordt gemonteerd. openpilot kalibreert continu, resetten is zelden nodig. - Your device is pointed %1° %2 and %3° %4. Uw apparaat is gericht op %1° %2 en %3° %4. - down omlaag - up omhoog - left links - right rechts - Are you sure you want to reboot? Weet u zeker dat u opnieuw wilt opstarten? - Disengage to Reboot Deactiveer openpilot om opnieuw op te starten - Are you sure you want to power off? Weet u zeker dat u wilt uitschakelen? - Disengage to Power Off Deactiveer openpilot om uit te schakelen @@ -261,32 +242,26 @@ DriveStats - Drives Ritten - Hours Uren - ALL TIME TOTAAL - PAST WEEK AFGELOPEN WEEK - KM Km - Miles Mijl @@ -294,7 +269,6 @@ DriverViewScene - camera starting Camera wordt gestart @@ -302,12 +276,10 @@ InputDialog - Cancel Annuleren - Need at least %n character(s)! Heeft minstens %n karakter nodig! @@ -318,22 +290,18 @@ Installer - Installing... Installeren... - Receiving objects: Objecten ontvangen: - Resolving deltas: Deltas verwerken: - Updating files: Bestanden bijwerken: @@ -341,27 +309,22 @@ MapETA - eta eta - min min - hr uur - km km - mi mi @@ -369,22 +332,18 @@ MapInstructions - km km - m m - mi mi - ft ft @@ -392,48 +351,40 @@ MapPanel - Current Destination Huidige Bestemming - CLEAR LEEGMAKEN - Recent Destinations Recente Bestemmingen - Try the Navigation Beta Probeer de Navigatie Bèta - Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai Krijg stapsgewijze routebeschrijving en meer met een comma prime abonnement. Meld u nu aan: https://connect.comma.ai - No home location set Geen thuislocatie ingesteld - No work location set Geen werklocatie ingesteld - no recent destinations geen recente bestemmingen @@ -441,12 +392,10 @@ ingesteld MapWindow - Map Loading Kaart wordt geladen - Waiting for GPS Wachten op GPS @@ -454,12 +403,10 @@ ingesteld MultiOptionDialog - Select Selecteer - Cancel Annuleren @@ -467,72 +414,33 @@ ingesteld Networking - Advanced Geavanceerd - Enter password Voer wachtwoord in - - for "%1" voor "%1" - Wrong password Verkeerd wachtwoord - - AnnotatedCameraWidget - - - km/h - km/u - - - - mph - mph - - - - - MAX - MAX - - - - - SPEED - SPEED - - - - - LIMIT - LIMIT - - OffroadHome - UPDATE UPDATE - ALERTS WAARSCHUWINGEN - ALERT WAARSCHUWING @@ -540,22 +448,18 @@ ingesteld PairingPopup - Pair your device to your comma account Koppel uw apparaat aan uw comma-account - Go to https://connect.comma.ai on your phone Ga naar https://connect.comma.ai op uw telefoon - Click "add new device" and scan the QR code on the right Klik op "add new device" en scan de QR-code aan de rechterkant - Bookmark connect.comma.ai to your home screen to use it like an app Voeg connect.comma.ai toe op uw startscherm om het als een app te gebruiken @@ -563,32 +467,26 @@ ingesteld PrimeAdWidget - Upgrade Now Upgrade nu - Become a comma prime member at connect.comma.ai Word een comma prime lid op connect.comma.ai - PRIME FEATURES: PRIME BEVAT: - Remote access Toegang op afstand - 1 year of storage 1 jaar lang opslag - Developer perks Voordelen voor ontwikkelaars @@ -596,22 +494,18 @@ ingesteld PrimeUserWidget - ✓ SUBSCRIBED ✓ GEABONNEERD - comma prime comma prime - CONNECT.COMMA.AI CONNECT.COMMA.AI - COMMA POINTS COMMA PUNTEN @@ -619,27 +513,22 @@ ingesteld QObject - Reboot Opnieuw Opstarten - Exit Afsluiten - dashcam dashcam - openpilot openpilot - %n minute(s) ago %n minuut geleden @@ -647,7 +536,6 @@ ingesteld - %n hour(s) ago %n uur geleden @@ -655,7 +543,6 @@ ingesteld - %n day(s) ago %n dag geleden @@ -666,47 +553,38 @@ ingesteld Reset - Reset failed. Reboot to try again. Opnieuw instellen mislukt. Start opnieuw op om opnieuw te proberen. - Are you sure you want to reset your device? Weet u zeker dat u uw apparaat opnieuw wilt instellen? - Resetting device... Apparaat opnieuw instellen... - System Reset Systeemreset - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. Systeemreset geactiveerd. Druk op bevestigen om alle inhoud en instellingen te wissen. Druk op Annuleren om het opstarten te hervatten. - Cancel Annuleren - Reboot Opnieuw Opstarten - Confirm Bevestigen - Unable to mount data partition. Press confirm to reset your device. Kan gegevenspartitie niet koppelen. Druk op bevestigen om uw apparaat te resetten. @@ -714,7 +592,6 @@ ingesteld RichTextDialog - Ok Ok @@ -722,33 +599,26 @@ ingesteld SettingsWindow - × × - Device Apparaat - - Network Netwerk - Toggles Opties - Software Software - Navigation Navigatie @@ -756,105 +626,82 @@ ingesteld Setup - WARNING: Low Voltage WAARCHUWING: Lage Spanning - Power your device in a car with a harness or proceed at your own risk. Voorzie uw apparaat van stroom in een auto met een harnas (car harness) of ga op eigen risico verder. - Power off Uitschakelen - - - Continue Doorgaan - Getting Started Aan de slag - Before we get on the road, let’s finish installation and cover some details. Laten we, voordat we op pad gaan, de installatie afronden en enkele details bespreken. - Connect to Wi-Fi Maak verbinding met Wi-Fi - - Back Terug - Continue without Wi-Fi Doorgaan zonder Wi-Fi - Waiting for internet Wachten op internet - Choose Software to Install Kies Software om te Installeren - Dashcam Dashcam - Custom Software Andere Software - Enter URL Voer URL in - for Custom Software voor Andere Software - Downloading... Downloaden... - Download Failed Downloaden Mislukt - Ensure the entered URL is valid, and the device’s internet connection is good. Zorg ervoor dat de ingevoerde URL geldig is en dat de internetverbinding van het apparaat goed is. - Reboot device Apparaat opnieuw opstarten - Start over Begin opnieuw @@ -862,17 +709,14 @@ ingesteld SetupWidget - Finish Setup Installatie voltooien - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. Koppel uw apparaat met comma connect (connect.comma.ai) en claim uw comma prime-aanbieding. - Pair device Apparaat koppelen @@ -880,106 +724,82 @@ ingesteld Sidebar - - CONNECT VERBINDING - OFFLINE OFFLINE - - ONLINE ONLINE - ERROR FOUT - - - TEMP TEMP - HIGH HOOG - GOOD GOED - OK OK - VEHICLE VOERTUIG - NO GEEN - PANDA PANDA - GPS GPS - SEARCH ZOEKEN - -- -- - Wi-Fi Wi-Fi - ETH ETH - 2G 2G - 3G 3G - LTE 4G - 5G 5G @@ -987,138 +807,141 @@ ingesteld SoftwarePanel - Git Branch - Git Branch + Git Branch - Git Commit - Git Commit + Git Commit - OS Version - OS Versie + OS Versie - Version - Versie + Versie - Last Update Check - Laatste Updatecontrole + Laatste Updatecontrole - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - De laatste keer dat openpilot met succes heeft gecontroleerd op een update. De updater werkt alleen als de auto is uitgeschakeld. + De laatste keer dat openpilot met succes heeft gecontroleerd op een update. De updater werkt alleen als de auto is uitgeschakeld. - Check for Update - Controleer op Updates + Controleer op Updates - CHECKING - CONTROLEER + CONTROLEER - Switch Branch - Branch Verwisselen + Branch Verwisselen - ENTER - INVOEREN + INVOEREN - - The new branch will be pulled the next time the updater runs. - Tijdens de volgende update wordt de nieuwe branch opgehaald. + Tijdens de volgende update wordt de nieuwe branch opgehaald. - Enter branch name - Voer branch naam in + Voer branch naam in - Uninstall %1 Verwijder %1 - UNINSTALL VERWIJDER - Are you sure you want to uninstall? Weet u zeker dat u de installatie ongedaan wilt maken? - failed to fetch update - ophalen van update mislukt + ophalen van update mislukt - - CHECK CONTROLEER + + Updates are only downloaded while the car is off. + + + + Current Version + + + + Download + + + + Install Update + + + + INSTALL + + + + Target Branch + + + + SELECT + + + + Select a branch + + SshControl - SSH Keys SSH Sleutels - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. Waarschuwing: dit geeft SSH toegang tot alle openbare sleutels in uw GitHub-instellingen. Voer nooit een andere GitHub-gebruikersnaam in dan die van uzelf. Een medewerker van comma zal u NOOIT vragen om zijn GitHub-gebruikersnaam toe te voegen. - - ADD TOEVOEGEN - Enter your GitHub username Voer uw GitHub gebruikersnaam in - LOADING LADEN - REMOVE VERWIJDEREN - Username '%1' has no keys on GitHub Gebruikersnaam '%1' heeft geen SSH sleutels op GitHub - Request timed out Time-out van aanvraag - Username '%1' doesn't exist on GitHub Gebruikersnaam '%1' bestaat niet op GitHub @@ -1126,7 +949,6 @@ ingesteld SshToggle - Enable SSH SSH Inschakelen @@ -1134,22 +956,18 @@ ingesteld TermsPage - Terms & Conditions Algemene Voorwaarden - Decline Afwijzen - Scroll to accept Scroll om te accepteren - Agree Akkoord @@ -1157,125 +975,125 @@ ingesteld TogglesPanel - Enable openpilot openpilot Inschakelen - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. Gebruik het openpilot-systeem voor adaptieve cruisecontrol en rijstrookassistentie. Uw aandacht is te allen tijde vereist om deze functie te gebruiken. Het wijzigen van deze instelling wordt van kracht wanneer de auto wordt uitgeschakeld. - Enable Lane Departure Warnings Waarschuwingen bij Verlaten Rijstrook Inschakelen - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). Ontvang waarschuwingen om terug naar de rijstrook te sturen wanneer uw voertuig over een gedetecteerde rijstrookstreep drijft zonder dat de richtingaanwijzer wordt geactiveerd terwijl u harder rijdt dan 50 km/u (31 mph). - Use Metric System Gebruik Metrisch Systeem - Display speed in km/h instead of mph. Geef snelheid weer in km/u in plaats van mph. - Record and Upload Driver Camera Opnemen en Uploaden van de Bestuurders Camera - Upload data from the driver facing camera and help improve the driver monitoring algorithm. Upload gegevens van de bestuurders camera en help het algoritme voor het monitoren van de bestuurder te verbeteren. - Disengage On Accelerator Pedal Deactiveren Met Gaspedaal - When enabled, pressing the accelerator pedal will disengage openpilot. Indien ingeschakeld, zal het indrukken van het gaspedaal openpilot deactiveren. - Show ETA in 24h Format Toon verwachte aankomsttijd in 24-uurs formaat - Use 24h format instead of am/pm Gebruik 24-uurs formaat in plaats van AM en PM - Show Map on Left Side of UI Toon kaart aan linkerkant van het scherm - Show map on left side when in split screen view. Toon kaart links in gesplitste schermweergave. - openpilot Longitudinal Control - openpilot Longitudinale Controle + openpilot Longitudinale Controle - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - openpilot zal de radar van de auto uitschakelen en de controle over gas en remmen overnemen. Waarschuwing: hierdoor wordt AEB (automatische noodrem) uitgeschakeld! + openpilot zal de radar van de auto uitschakelen en de controle over gas en remmen overnemen. Waarschuwing: hierdoor wordt AEB (automatische noodrem) uitgeschakeld! + + + 🌮 End-to-end longitudinal (extremely alpha) 🌮 + + + + Experimental openpilot longitudinal control + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> + + + + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. + + + + openpilot longitudinal control is not currently available for this car. + + + + Enable experimental longitudinal control to enable this. + Updater - Update Required Update Vereist - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. Een update van het besturingssysteem is vereist. Verbind je apparaat met Wi-Fi voor de snelste update-ervaring. De downloadgrootte is ongeveer 1 GB. - Connect to Wi-Fi Maak verbinding met Wi-Fi - Install Installeer - Back Terug - Loading... Aan het laden... - Reboot Opnieuw Opstarten - Update failed Update mislukt @@ -1283,23 +1101,18 @@ ingesteld WifiUI - - Scanning for networks... Scannen naar netwerken... - CONNECTING... VERBINDEN... - FORGET VERGETEN - Forget Wi-Fi Network "%1"? Vergeet Wi-Fi Netwerk "%1"? diff --git a/selfdrive/ui/translations/main_pl.ts b/selfdrive/ui/translations/main_pl.ts index 92902d04a9..bdce181375 100644 --- a/selfdrive/ui/translations/main_pl.ts +++ b/selfdrive/ui/translations/main_pl.ts @@ -4,17 +4,14 @@ AbstractAlert - Close Zamknij - Snooze Update Zaktualizuj później - Reboot and Update Uruchom ponownie i zaktualizuj @@ -22,67 +19,84 @@ AdvancedNetworking - Back Wróć - Enable Tethering Włącz hotspot osobisty - Tethering Password Hasło do hotspotu - - EDIT EDYTUJ - Enter new tethering password Wprowadź nowe hasło do hotspotu - IP Address Adres IP - Enable Roaming Włącz roaming danych - APN Setting Ustawienia APN - Enter APN Wprowadź APN - leave blank for automatic configuration Pozostaw puste, aby użyć domyślnej konfiguracji + + Cellular Metered + + + + Prevent large data uploads when on a metered connection + + + + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + MAX + + + SPEED + PRĘDKOŚĆ + + + LIMIT + OGRANICZENIE + ConfirmationDialog - - Ok Ok - Cancel Anuluj @@ -90,17 +104,14 @@ DeclinePage - You must accept the Terms and Conditions in order to use openpilot. Aby korzystać z openpilota musisz zaakceptować regulamin. - Back Wróć - Decline, uninstall %1 Odrzuć, odinstaluj %1 @@ -108,152 +119,122 @@ DevicePanel - Dongle ID ID adaptera - N/A N/A - Serial Numer seryjny - Driver Camera Kamera kierowcy - PREVIEW PODGLĄD - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) Wyświetl podgląd z kamery skierowanej na kierowcę, aby upewnić się, że monitoring kierowcy ma dobry zakres widzenia. (pojazd musi być wyłączony) - Reset Calibration Zresetuj kalibrację - RESET ZRESETUJ - Are you sure you want to reset calibration? Czy na pewno chcesz zresetować kalibrację? - Review Training Guide Zapoznaj się z samouczkiem - REVIEW ZAPOZNAJ SIĘ - Review the rules, features, and limitations of openpilot Zapoznaj się z zasadami, funkcjami i ograniczeniami openpilota - Are you sure you want to review the training guide? Czy na pewno chcesz się zapoznać z samouczkiem? - Regulatory Regulacja - VIEW WIDOK - Change Language Zmień język - CHANGE ZMIEŃ - Select a language Wybierz język - Reboot Uruchom ponownie - Power Off Wyłącz - openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. openpilot wymaga, aby urządzenie było zamontowane z maksymalnym odchyłem 4° poziomo, 5° w górę oraz 8° w dół. openpilot jest ciągle kalibrowany, rzadko konieczne jest resetowania urządzenia. - Your device is pointed %1° %2 and %3° %4. Twoje urządzenie jest skierowane %1° %2 oraz %3° %4. - down w dół - up w górę - left w lewo - right w prawo - Are you sure you want to reboot? Czy na pewno chcesz uruchomić ponownie urządzenie? - Disengage to Reboot Aby uruchomić ponownie, odłącz sterowanie - Are you sure you want to power off? Czy na pewno chcesz wyłączyć urządzenie? - Disengage to Power Off Aby wyłączyć urządzenie, odłącz sterowanie @@ -261,32 +242,26 @@ DriveStats - Drives Przejazdy - Hours Godziny - ALL TIME CAŁKOWICIE - PAST WEEK OSTATNI TYDZIEŃ - KM KM - Miles Mile @@ -294,7 +269,6 @@ DriverViewScene - camera starting uruchamianie kamery @@ -302,12 +276,10 @@ InputDialog - Cancel Anuluj - Need at least %n character(s)! Wpisana wartość powinna składać się przynajmniej z %n znaku! @@ -319,22 +291,18 @@ Installer - Installing... Instalowanie... - Receiving objects: Odbieranie obiektów: - Resolving deltas: Rozwiązywanie różnic: - Updating files: Aktualizacja plików: @@ -342,27 +310,22 @@ MapETA - eta przewidywany czas - min min - hr godz - km km - mi mi @@ -370,22 +333,18 @@ MapInstructions - km km - m m - mi mi - ft ft @@ -393,48 +352,40 @@ MapPanel - Current Destination Miejsce docelowe - CLEAR WYCZYŚĆ - Recent Destinations Ostatnie miejsca docelowe - Try the Navigation Beta Wypróbuj nawigację w wersji beta - Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai Odblokuj nawigację zakręt po zakęcie i wiele więcej subskrybując comma prime. Zarejestruj się teraz: https://connect.comma.ai - No home location set Lokalizacja domu nie została ustawiona - No work location set Miejsce pracy nie zostało ustawione - no recent destinations brak ostatnich miejsc docelowych @@ -442,12 +393,10 @@ nie zostało ustawione MapWindow - Map Loading Ładowanie Mapy - Waiting for GPS Oczekiwanie na sygnał GPS @@ -455,12 +404,10 @@ nie zostało ustawione MultiOptionDialog - Select Wybierz - Cancel Anuluj @@ -468,72 +415,33 @@ nie zostało ustawione Networking - Advanced Zaawansowane - Enter password Wprowadź hasło - - for "%1" do "%1" - Wrong password Niepoprawne hasło - - AnnotatedCameraWidget - - - km/h - km/h - - - - mph - mph - - - - - MAX - MAX - - - - - SPEED - PRĘDKOŚĆ - - - - - LIMIT - OGRANICZENIE - - OffroadHome - UPDATE UAKTUALNIJ - ALERTS ALERTY - ALERT ALERT @@ -541,22 +449,18 @@ nie zostało ustawione PairingPopup - Pair your device to your comma account Sparuj swoje urzadzenie ze swoim kontem comma - Go to https://connect.comma.ai on your phone Wejdź na stronę https://connect.comma.ai na swoim telefonie - Click "add new device" and scan the QR code on the right Kliknij "add new device" i zeskanuj kod QR znajdujący się po prawej stronie - Bookmark connect.comma.ai to your home screen to use it like an app Dodaj connect.comma.ai do zakładek na swoim ekranie początkowym, aby korzystać z niej jak z aplikacji @@ -564,32 +468,26 @@ nie zostało ustawione PrimeAdWidget - Upgrade Now Uaktualnij teraz - Become a comma prime member at connect.comma.ai Zostań członkiem comma prime na connect.comma.ai - PRIME FEATURES: FUNKCJE PRIME: - Remote access Zdalny dostęp - 1 year of storage 1 rok przechowywania danych - Developer perks Udogodnienia dla programistów @@ -597,22 +495,18 @@ nie zostało ustawione PrimeUserWidget - ✓ SUBSCRIBED ✓ ZASUBSKRYBOWANO - comma prime comma prime - CONNECT.COMMA.AI CONNECT.COMMA.AI - COMMA POINTS COMMA POINTS @@ -620,27 +514,22 @@ nie zostało ustawione QObject - Reboot Uruchom Ponownie - Exit Wyjdź - dashcam wideorejestrator - openpilot openpilot - %n minute(s) ago %n minutę temu @@ -649,7 +538,6 @@ nie zostało ustawione - %n hour(s) ago % godzinę temu @@ -658,7 +546,6 @@ nie zostało ustawione - %n day(s) ago %n dzień temu @@ -670,47 +557,38 @@ nie zostało ustawione Reset - Reset failed. Reboot to try again. Wymazywanie zakończone niepowodzeniem. Aby spróbować ponownie, uruchom ponownie urządzenie. - Are you sure you want to reset your device? Czy na pewno chcesz wymazać urządzenie? - Resetting device... Wymazywanie urządzenia... - System Reset Przywróć do ustawień fabrycznych - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. Przywracanie do ustawień fabrycznych. Wciśnij potwierdź, aby usunąć wszystkie dane oraz ustawienia. Wciśnij anuluj, aby wznowić uruchamianie. - Cancel Anuluj - Reboot Uruchom ponownie - Confirm Potwiedź - Unable to mount data partition. Press confirm to reset your device. Partycja nie została zamontowana poprawnie. Wciśnij potwierdź, aby uruchomić ponownie urządzenie. @@ -718,7 +596,6 @@ nie zostało ustawione RichTextDialog - Ok Ok @@ -726,33 +603,26 @@ nie zostało ustawione SettingsWindow - × x - Device Urządzenie - - Network Sieć - Toggles Przełączniki - Software Oprogramowanie - Navigation Nawigacja @@ -760,105 +630,82 @@ nie zostało ustawione Setup - WARNING: Low Voltage OSTRZEŻENIE: Niskie Napięcie - Power your device in a car with a harness or proceed at your own risk. Podłącz swoje urządzenie do zasilania poprzez podłączenienie go do pojazdu lub kontynuuj na własną odpowiedzialność. - Power off Wyłącz - - - Continue Kontynuuj - Getting Started Zacznij - Before we get on the road, let’s finish installation and cover some details. Zanim ruszysz w drogę, dokończ instalację i podaj kilka szczegółów. - Connect to Wi-Fi Połącz z Wi-Fi - - Back Wróć - Continue without Wi-Fi Kontynuuj bez połączenia z Wif-Fi - Waiting for internet Oczekiwanie na połączenie sieciowe - Choose Software to Install Wybierz oprogramowanie do instalacji - Dashcam Wideorejestrator - Custom Software Własne oprogramowanie - Enter URL Wprowadź adres URL - for Custom Software do własnego oprogramowania - Downloading... Pobieranie... - Download Failed Pobieranie nie powiodło się - Ensure the entered URL is valid, and the device’s internet connection is good. Upewnij się, że wpisany adres URL jest poprawny, a połączenie internetowe działa poprawnie. - Reboot device Uruchom ponownie - Start over Zacznij od początku @@ -866,17 +713,14 @@ nie zostało ustawione SetupWidget - Finish Setup Zakończ konfigurację - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. Sparuj swoje urządzenie z comma connect (connect.comma.ai) i wybierz swoją ofertę comma prime. - Pair device Sparuj urządzenie @@ -884,106 +728,82 @@ nie zostało ustawione Sidebar - - CONNECT POŁĄCZENIE - OFFLINE OFFLINE - - ONLINE ONLINE - ERROR BŁĄD - - - TEMP TEMP - HIGH WYSOKA - GOOD DOBRA - OK OK - VEHICLE POJAZD - NO BRAK - PANDA PANDA - GPS GPS - SEARCH SZUKAJ - -- -- - Wi-Fi Wi-FI - ETH ETH - 2G 2G - 3G 3G - LTE LTE - 5G 5G @@ -991,138 +811,141 @@ nie zostało ustawione SoftwarePanel - Git Branch - Gałąź Git + Gałąź Git - Git Commit - Git commit + Git commit - OS Version - Wersja systemu + Wersja systemu - Version - Wersja + Wersja - Last Update Check - Ostatnie sprawdzenie aktualizacji + Ostatnie sprawdzenie aktualizacji - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - Ostatni raz kiedy openpilot znalazł aktualizację. Aktualizator może być uruchomiony wyłącznie wtedy, kiedy pojazd jest wyłączony. + Ostatni raz kiedy openpilot znalazł aktualizację. Aktualizator może być uruchomiony wyłącznie wtedy, kiedy pojazd jest wyłączony. - Check for Update - Sprawdź uaktualnienia + Sprawdź uaktualnienia - CHECKING - SPRAWDZANIE + SPRAWDZANIE - Switch Branch - Zmień gąłąź + Zmień gąłąź - ENTER - WPROWADŹ + WPROWADŹ - - The new branch will be pulled the next time the updater runs. - Nowa gałąź będzie pobrana przy następnym uruchomieniu aktualizatora. + Nowa gałąź będzie pobrana przy następnym uruchomieniu aktualizatora. - Enter branch name - Wprowadź nazwę gałęzi + Wprowadź nazwę gałęzi - Uninstall %1 Odinstaluj %1 - UNINSTALL ODINSTALUJ - Are you sure you want to uninstall? Czy na pewno chcesz odinstalować? - failed to fetch update - pobieranie aktualizacji zakończone niepowodzeniem + pobieranie aktualizacji zakończone niepowodzeniem - - CHECK SPRAWDŹ + + Updates are only downloaded while the car is off. + + + + Current Version + + + + Download + + + + Install Update + + + + INSTALL + + + + Target Branch + + + + SELECT + + + + Select a branch + + SshControl - SSH Keys Klucze SSH - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. Ostrzeżenie: To spowoduje przekazanie dostępu do wszystkich Twoich publicznych kuczy z ustawień GitHuba. Nigdy nie wprowadzaj nazwy użytkownika innej niż swoja. Pracownik comma NIGDY nie poprosi o dodanie swojej nazwy uzytkownika. - - ADD DODAJ - Enter your GitHub username Wpisz swoją nazwę użytkownika GitHub - LOADING ŁADOWANIE - REMOVE USUŃ - Username '%1' has no keys on GitHub Użytkownik '%1' nie posiada żadnych kluczy na GitHubie - Request timed out Limit czasu rządania - Username '%1' doesn't exist on GitHub Użytkownik '%1' nie istnieje na GitHubie @@ -1130,7 +953,6 @@ nie zostało ustawione SshToggle - Enable SSH Włącz SSH @@ -1138,22 +960,18 @@ nie zostało ustawione TermsPage - Terms & Conditions Regulamin - Decline Odrzuć - Scroll to accept Przewiń w dół, aby zaakceptować - Agree Zaakceptuj @@ -1161,125 +979,125 @@ nie zostało ustawione TogglesPanel - Enable openpilot Włącz openpilota - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. Użyj openpilota do zachowania bezpiecznego odstępu między pojazdami i do asystowania w utrzymywaniu pasa ruchu. Twoja pełna uwaga jest wymagana przez cały czas korzystania z tej funkcji. Ustawienie to może być wdrożone wyłącznie wtedy, gdy pojazd jest wyłączony. - Enable Lane Departure Warnings Włącz ostrzeganie przed zmianą pasa ruchu - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). Otrzymuj alerty o powrocie na właściwy pas, kiedy Twój pojazd przekroczy linię bez włączonego kierunkowskazu jadąc powyżej 50 km/h (31 mph). - Use Metric System Korzystaj z systemu metrycznego - Display speed in km/h instead of mph. Wyświetl prędkość w km/h zamiast mph. - Record and Upload Driver Camera Nagraj i prześlij nagranie z kamery kierowcy - Upload data from the driver facing camera and help improve the driver monitoring algorithm. Prześlij dane z kamery skierowanej na kierowcę i pomóż poprawiać algorytm monitorowania kierowcy. - Disengage On Accelerator Pedal Odłącz poprzez naciśnięcie gazu - When enabled, pressing the accelerator pedal will disengage openpilot. Po włączeniu, naciśnięcie na pedał gazu odłączy openpilota. - Show ETA in 24h Format Pokaż oczekiwany czas dojazdu w formacie 24-godzinnym - Use 24h format instead of am/pm Korzystaj z formatu 24-godzinnego zamiast 12-godzinnego - Show Map on Left Side of UI Pokaż mapę po lewej stronie ekranu - Show map on left side when in split screen view. Pokaż mapę po lewej stronie kiedy ekran jest podzielony. - openpilot Longitudinal Control - Kontrola wzdłużna openpilota + Kontrola wzdłużna openpilota - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - openpilot wyłączy radar samochodu i przejmie kontrolę nad gazem i hamulcem. Ostrzeżenie: wyłączony zostanie system AEB! + openpilot wyłączy radar samochodu i przejmie kontrolę nad gazem i hamulcem. Ostrzeżenie: wyłączony zostanie system AEB! + + + 🌮 End-to-end longitudinal (extremely alpha) 🌮 + + + + Experimental openpilot longitudinal control + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> + + + + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. + + + + openpilot longitudinal control is not currently available for this car. + + + + Enable experimental longitudinal control to enable this. + Updater - Update Required Wymagana Aktualizacja - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. Wymagana aktualizacja systemu operacyjnego. Aby przyspieszyć proces aktualizacji połącz swoje urzeądzenie do Wi-Fi. Rozmiar pobieranej paczki wynosi około 1GB. - Connect to Wi-Fi Połącz się z Wi-Fi - Install Zainstaluj - Back Wróć - Loading... Ładowanie... - Reboot Uruchom ponownie - Update failed Aktualizacja nie powiodła się @@ -1287,23 +1105,18 @@ nie zostało ustawione WifiUI - - Scanning for networks... Wyszukiwanie sieci... - CONNECTING... ŁĄCZENIE... - FORGET ZAPOMNIJ - Forget Wi-Fi Network "%1"? Czy chcesz zapomnieć sieć "%1"? diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index d502c3fce1..5a8bf861df 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -4,17 +4,14 @@ AbstractAlert - Close ปิด - Snooze Update เลื่อนการอัปเดต - Reboot and Update รีบูตและอัปเดต @@ -22,67 +19,84 @@ AdvancedNetworking - Back ย้อนกลับ - Enable Tethering ปล่อยฮอตสปอต - Tethering Password รหัสผ่านฮอตสปอต - - EDIT แก้ไข - Enter new tethering password ป้อนรหัสผ่านฮอตสปอตใหม่ - IP Address หมายเลขไอพี - Enable Roaming เปิดใช้งานโรมมิ่ง - APN Setting ตั้งค่า APN - Enter APN ป้อนค่า APN - leave blank for automatic configuration เว้นว่างเพื่อตั้งค่าอัตโนมัติ + + Cellular Metered + + + + Prevent large data uploads when on a metered connection + + + + + AnnotatedCameraWidget + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + + MAX + สูงสุด + + + SPEED + ความเร็ว + + + LIMIT + จำกัด + ConfirmationDialog - - Ok ตกลง - Cancel ยกเลิก @@ -90,17 +104,14 @@ DeclinePage - You must accept the Terms and Conditions in order to use openpilot. คุณต้องยอมรับเงื่อนไขและข้อตกลง เพื่อใช้งาน openpilot - Back ย้อนกลับ - Decline, uninstall %1 ปฏิเสธ และถอนการติดตั้ง %1 @@ -108,152 +119,122 @@ DevicePanel - Dongle ID Dongle ID - N/A ไม่มี - Serial ซีเรียล - Driver Camera กล้องฝั่งคนขับ - PREVIEW แสดงภาพ - Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) ดูภาพตัวอย่างกล้องที่หันเข้าหาคนขับเพื่อให้แน่ใจว่าการตรวจสอบคนขับมีทัศนวิสัยที่ดี (รถต้องดับเครื่องยนต์) - Reset Calibration รีเซ็ตการคาลิเบรท - RESET รีเซ็ต - Are you sure you want to reset calibration? คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตการคาลิเบรท? - Review Training Guide ทบทวนคู่มือการใช้งาน - REVIEW ทบทวน - Review the rules, features, and limitations of openpilot ตรวจสอบกฎ คุณสมบัติ และข้อจำกัดของ openpilot - Are you sure you want to review the training guide? คุณแน่ใจหรือไม่ว่าต้องการทบทวนคู่มือการใช้งาน? - Regulatory ระเบียบข้อบังคับ - VIEW ดู - Change Language เปลี่ยนภาษา - CHANGE เปลี่ยน - Select a language เลือกภาษา - Reboot รีบูต - Power Off ปิดเครื่อง - openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. openpilot กำหนดให้ติดตั้งอุปกรณ์ โดยสามารถเอียงด้านซ้ายหรือขวาไม่เกิน 4° และเอียงขึ้นด้านบนไม่เกิน 5° หรือเอียงลงด้านล่างไม่เกิน 8° openpilot ทำการคาลิเบรทอย่างต่อเนื่อง แทบจะไม่จำเป็นต้องทำการรีเซ็ตการคาลิเบรท - Your device is pointed %1° %2 and %3° %4. อุปกรณ์ของคุณเอียงไปทาง %2 %1° และ %4 %3° - down ด้านล่าง - up ด้านบน - left ด้านซ้าย - right ด้านขวา - Are you sure you want to reboot? คุณแน่ใจหรือไม่ว่าต้องการรีบูต? - Disengage to Reboot ยกเลิกระบบช่วยขับเพื่อรีบูต - Are you sure you want to power off? คุณแน่ใจหรือไม่ว่าต้องการปิดเครื่อง? - Disengage to Power Off ยกเลิกระบบช่วยขับเพื่อปิดเครื่อง @@ -261,32 +242,26 @@ DriveStats - Drives การขับขี่ - Hours ชั่วโมง - ALL TIME ทั้งหมด - PAST WEEK สัปดาห์ที่ผ่านมา - KM กิโลเมตร - Miles ไมล์ @@ -294,7 +269,6 @@ DriverViewScene - camera starting กำลังเปิดกล้อง @@ -302,12 +276,10 @@ InputDialog - Cancel ยกเลิก - Need at least %n character(s)! ต้องการอย่างน้อย %n ตัวอักษร! @@ -317,22 +289,18 @@ Installer - Installing... กำลังติดตั้ง... - Receiving objects: กำลังรับข้อมูล: - Resolving deltas: การแก้ไขเดลต้า: - Updating files: กำลังอัปเดตไฟล์: @@ -340,27 +308,22 @@ MapETA - eta eta - min นาที - hr ชม. - km กม. - mi ไมล์ @@ -368,22 +331,18 @@ MapInstructions - km กม. - m ม. - mi ไมล์ - ft ฟุต @@ -391,48 +350,40 @@ MapPanel - Current Destination ปลายทางปัจจุบัน - CLEAR ล้างข้อมูล - Recent Destinations ปลายทางล่าสุด - Try the Navigation Beta ลองใช้ระบบนำทาง (เบต้า) - Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai รับการแสดงเส้นทางแบบเลี้ยวต่อเลี้ยว และอื่นๆ ด้วยการสมัครบริการ comma prime สมัครเลย: https://connect.comma.ai - No home location set ยังไม่ได้กำหนด ตำแหน่งของบ้าน - No work location set ยังไม่ได้กำหนด ตำแหน่งของที่ทำงาน - no recent destinations ไม่พบปลายทางล่าสุด @@ -440,12 +391,10 @@ location set MapWindow - Map Loading กำลังโหลดแผนที่ - Waiting for GPS กำลังรอสัญญาณ GPS @@ -453,12 +402,10 @@ location set MultiOptionDialog - Select เลือก - Cancel ยกเลิก @@ -466,72 +413,33 @@ location set Networking - Advanced ขั้นสูง - Enter password ใส่รหัสผ่าน - - for "%1" สำหรับ "%1" - Wrong password รหัสผ่านผิด - - AnnotatedCameraWidget - - - km/h - กม./ชม. - - - - mph - ไมล์/ชม. - - - - - MAX - สูงสุด - - - - - SPEED - ความเร็ว - - - - - LIMIT - จำกัด - - OffroadHome - UPDATE อัปเดต - ALERTS การแจ้งเตือน - ALERT การแจ้งเตือน @@ -539,22 +447,18 @@ location set PairingPopup - Pair your device to your comma account จับคู่อุปกรณ์ของคุณกับบัญชี comma ของคุณ - Go to https://connect.comma.ai on your phone ไปที่ https://connect.comma.ai ด้วยโทรศัพท์ของคุณ - Click "add new device" and scan the QR code on the right กดที่ "add new device" และสแกนคิวอาร์โค้ดทางด้านขวา - Bookmark connect.comma.ai to your home screen to use it like an app จดจำ connect.comma.ai โดยการเพิ่มไปยังหน้าจอโฮม เพื่อใช้งานเหมือนเป็นแอปพลิเคชัน @@ -562,32 +466,26 @@ location set PrimeAdWidget - Upgrade Now อัพเกรดเดี๋ยวนี้ - Become a comma prime member at connect.comma.ai สมัครสมาชิก comma prime ได้ที่ connect.comma.ai - PRIME FEATURES: คุณสมบัติของ PRIME: - Remote access การเข้าถึงระยะไกล - 1 year of storage จัดเก็บข้อมูลนาน 1 ปี - Developer perks สิทธิพิเศษสำหรับนักพัฒนา @@ -595,22 +493,18 @@ location set PrimeUserWidget - ✓ SUBSCRIBED ✓ สมัครสำเร็จ - comma prime comma prime - CONNECT.COMMA.AI CONNECT.COMMA.AI - COMMA POINTS คะแนน COMMA @@ -618,41 +512,34 @@ location set QObject - Reboot รีบูต - Exit ปิด - dashcam กล้องติดรถยนต์ - openpilot openpilot - %n minute(s) ago %n นาทีที่แล้ว - %n hour(s) ago %n ชั่วโมงที่แล้ว - %n day(s) ago %n วันที่แล้ว @@ -662,47 +549,38 @@ location set Reset - Reset failed. Reboot to try again. การรีเซ็ตล้มเหลว รีบูตเพื่อลองอีกครั้ง - Are you sure you want to reset your device? คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตอุปกรณ์? - Resetting device... กำลังรีเซ็ตอุปกรณ์... - System Reset รีเซ็ตระบบ - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. มีการสั่งรีเซ็ตระบบ กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตเข้าระบบตามปกติ - Cancel ยกเลิก - Reboot รีบูต - Confirm ยืนยัน - Unable to mount data partition. Press confirm to reset your device. ไม่สามารถเมานต์พาร์ติชั่นข้อมูล กดยืนยันเพื่อรีเซ็ตอุปกรณ์ของคุณ @@ -710,7 +588,6 @@ location set RichTextDialog - Ok ตกลง @@ -718,33 +595,26 @@ location set SettingsWindow - × × - Device อุปกรณ์ - - Network เครือข่าย - Toggles ตัวเลือก - Software ซอฟต์แวร์ - Navigation การนำทาง @@ -752,105 +622,82 @@ location set Setup - WARNING: Low Voltage คำเตือน: แรงดันแบตเตอรี่ต่ำ - Power your device in a car with a harness or proceed at your own risk. โปรดต่ออุปกรณ์ของคุณเข้ากับสายควบคุมในรถยนต์ หรือดำเนินการด้วยความเสี่ยงของคุณเอง - Power off ปิดเครื่อง - - - Continue ดำเนินการต่อ - Getting Started เริ่มกันเลย - Before we get on the road, let’s finish installation and cover some details. ก่อนออกเดินทาง เรามาทำการติดตั้งซอฟต์แวร์ และตรวจสอบการตั้งค่า - Connect to Wi-Fi เชื่อมต่อ Wi-Fi - - Back ย้อนกลับ - Continue without Wi-Fi ดำเนินการต่อโดยไม่ใช้ Wi-Fi - Waiting for internet กำลังรอสัญญาณอินเตอร์เน็ต - Choose Software to Install เลือกซอฟต์แวร์ที่จะติดตั้ง - Dashcam กล้องติดรถยนต์ - Custom Software ซอฟต์แวร์ที่กำหนดเอง - Enter URL ป้อน URL - for Custom Software สำหรับซอฟต์แวร์ที่กำหนดเอง - Downloading... กำลังดาวน์โหลด... - Download Failed ดาวน์โหลดล้มเหลว - Ensure the entered URL is valid, and the device’s internet connection is good. ตรวจสอบให้แน่ใจว่า URL ที่ป้อนนั้นถูกต้อง และอุปกรณ์เชื่อมต่ออินเทอร์เน็ตอยู่ - Reboot device รีบูตอุปกรณ์ - Start over เริ่มต้นใหม่ @@ -858,17 +705,14 @@ location set SetupWidget - Finish Setup ตั้งค่าเสร็จสิ้น - Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. จับคู่อุปกรณ์ของคุณกับ comma connect (connect.comma.ai) และรับข้อเสนอ comma prime ของคุณ - Pair device จับคู่อุปกรณ์ @@ -876,106 +720,82 @@ location set Sidebar - - CONNECT เชื่อมต่อ - OFFLINE ออฟไลน์ - - ONLINE ออนไลน์ - ERROR เกิดข้อผิดพลาด - - - TEMP อุณหภูมิ - HIGH สูง - GOOD ดี - OK พอใช้ - VEHICLE รถยนต์ - NO ไม่พบ - PANDA PANDA - GPS จีพีเอส - SEARCH ค้นหา - -- -- - Wi-Fi Wi-Fi - ETH ETH - 2G 2G - 3G 3G - LTE LTE - 5G 5G @@ -983,138 +803,141 @@ location set SoftwarePanel - Git Branch - Git Branch + Git Branch - Git Commit - Git Commit + Git Commit - OS Version - เวอร์ชันระบบปฏิบัติการ + เวอร์ชันระบบปฏิบัติการ - Version - เวอร์ชั่น + เวอร์ชั่น - Last Update Check - ตรวจสอบการอัปเดตล่าสุด + ตรวจสอบการอัปเดตล่าสุด - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - ครั้งสุดท้ายที่ openpilot ตรวจสอบการอัปเดตสำเร็จ ตัวอัปเดตจะทำงานในขณะที่รถดับเครื่องอยู่เท่านั้น + ครั้งสุดท้ายที่ openpilot ตรวจสอบการอัปเดตสำเร็จ ตัวอัปเดตจะทำงานในขณะที่รถดับเครื่องอยู่เท่านั้น - Check for Update - ตรวจสอบการอัปเดต + ตรวจสอบการอัปเดต - CHECKING - กำลังตรวจสอบ + กำลังตรวจสอบ - Switch Branch - เปลี่ยน Branch + เปลี่ยน Branch - ENTER - เปลี่ยน + เปลี่ยน - - The new branch will be pulled the next time the updater runs. - Branch ใหม่จะถูกติดตั้งในครั้งต่อไปที่ตัวอัปเดตทำงาน + Branch ใหม่จะถูกติดตั้งในครั้งต่อไปที่ตัวอัปเดตทำงาน - Enter branch name - ใส่ชื่อ Branch + ใส่ชื่อ Branch - Uninstall %1 ถอนการติดตั้ง %1 - UNINSTALL ถอนการติดตั้ง - Are you sure you want to uninstall? คุณแน่ใจหรือไม่ว่าต้องการถอนการติดตั้ง? - failed to fetch update - โหลดข้อมูลอัปเดตไม่สำเร็จ + โหลดข้อมูลอัปเดตไม่สำเร็จ - - CHECK ตรวจสอบ + + Updates are only downloaded while the car is off. + + + + Current Version + + + + Download + + + + Install Update + + + + INSTALL + + + + Target Branch + + + + SELECT + + + + Select a branch + + SshControl - SSH Keys คีย์ SSH - Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. คำเตือน: สิ่งนี้ให้สิทธิ์ SSH เข้าถึงคีย์สาธารณะทั้งหมดใน GitHub ของคุณ อย่าป้อนชื่อผู้ใช้ GitHub อื่นนอกเหนือจากของคุณเอง พนักงาน comma จะไม่ขอให้คุณเพิ่มชื่อผู้ใช้ GitHub ของพวกเขา - - ADD เพิ่ม - Enter your GitHub username ป้อนชื่อผู้ใช้ GitHub ของคุณ - LOADING กำลังโหลด - REMOVE ลบ - Username '%1' has no keys on GitHub ชื่อผู้ใช้ '%1' ไม่มีคีย์บน GitHub - Request timed out ตรวจสอบไม่สำเร็จ เนื่องจากใช้เวลามากเกินไป - Username '%1' doesn't exist on GitHub ไม่พบชื่อผู้ใช้ '%1' บน GitHub @@ -1122,7 +945,6 @@ location set SshToggle - Enable SSH เปิดใช้งาน SSH @@ -1130,22 +952,18 @@ location set TermsPage - Terms & Conditions ข้อตกลงและเงื่อนไข - Decline ปฏิเสธ - Scroll to accept เลื่อนเพื่อตอบรับข้อตกลง - Agree ยอมรับ @@ -1153,125 +971,125 @@ location set TogglesPanel - Enable openpilot เปิดใช้งาน openpilot - Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. ใช้ระบบ openpilot สำหรับระบบควบคุมความเร็วอัตโนมัติ และระบบช่วยควบคุมรถให้อยู่ในเลน คุณจำเป็นต้องให้ความสนใจตลอดเวลาที่ใช้คุณสมบัตินี้ การเปลี่ยนการตั้งค่านี้จะมีผลเมื่อคุณดับเครื่องยนต์ - Enable Lane Departure Warnings เปิดใช้งานการเตือนการออกนอกเลน - Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). รับการแจ้งเตือนให้เลี้ยวกลับเข้าเลนเมื่อรถของคุณตรวจพบการข้ามช่องจราจรโดยไม่เปิดสัญญาณไฟเลี้ยวในขณะขับขี่ที่ความเร็วเกิน 31 ไมล์ต่อชั่วโมง (50 กม./ชม) - Use Metric System ใช้ระบบเมตริก - Display speed in km/h instead of mph. แสดงความเร็วเป็น กม./ชม. แทน ไมล์/ชั่วโมง - Record and Upload Driver Camera บันทึกและอัปโหลดภาพจากกล้องคนขับ - Upload data from the driver facing camera and help improve the driver monitoring algorithm. อัปโหลดข้อมูลจากกล้องที่หันหน้าไปทางคนขับ และช่วยปรับปรุงอัลกอริธึมการตรวจสอบผู้ขับขี่ - Disengage On Accelerator Pedal ยกเลิกระบบช่วยขับเมื่อเหยียบคันเร่ง - When enabled, pressing the accelerator pedal will disengage openpilot. เมื่อเปิดใช้งาน การกดแป้นคันเร่งจะเป็นการยกเลิกระบบช่วยขับโดย openpilot - Show ETA in 24h Format แสดงเวลา ETA ในรูปแบบ 24 ชั่วโมง - Use 24h format instead of am/pm ใช้รูปแบบเวลา 24 ชั่วโมง แทน am/pm - Show Map on Left Side of UI แสดงแผนที่ที่ด้านซ้ายของหน้าจอ - Show map on left side when in split screen view. แสดงแผนที่ด้านซ้ายของหน้าจอเมื่ออยู่ในโหมดแบ่งหน้าจอ - openpilot Longitudinal Control - openpilot การควบคุมการเร่งและลดความเร็ว + openpilot การควบคุมการเร่งและลดความเร็ว - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - openpilot จะปิดการใช้งานเรดาร์ของรถ และจะเข้าควบคุมการเร่งและเบรก คำเตือน: สิ่งนี้จะปิดระบบ AEB! + openpilot จะปิดการใช้งานเรดาร์ของรถ และจะเข้าควบคุมการเร่งและเบรก คำเตือน: สิ่งนี้จะปิดระบบ AEB! + + + 🌮 End-to-end longitudinal (extremely alpha) 🌮 + + + + Experimental openpilot longitudinal control + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> + + + + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. + + + + openpilot longitudinal control is not currently available for this car. + + + + Enable experimental longitudinal control to enable this. + Updater - Update Required จำเป็นต้องอัปเดต - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. จำเป็นต้องมีการอัปเดตระบบปฏิบัติการ เชื่อมต่ออุปกรณ์ของคุณกับ Wi-Fi เพื่อประสบการณ์การอัปเดตที่เร็วที่สุด ขนาดดาวน์โหลดประมาณ 1GB - Connect to Wi-Fi เชื่อมต่อกับ Wi-Fi - Install ติดตั้ง - Back ย้อนกลับ - Loading... กำลังโหลด... - Reboot รีบูต - Update failed การอัปเดตล้มเหลว @@ -1279,23 +1097,18 @@ location set WifiUI - - Scanning for networks... กำลังสแกนหาเครือข่าย... - CONNECTING... กำลังเชื่อมต่อ... - FORGET เลิกใช้ - Forget Wi-Fi Network "%1"? เลิกใช้เครือข่าย Wi-Fi "%1"? From 686506f4003964e230550e100d6a841c2ff5d3ac Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 25 Oct 2022 02:46:07 +0800 Subject: [PATCH 0072/1179] cabana: stable FPS (#26120) * stable FPS * fix --- tools/cabana/canmessages.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index d2141c3630..1b46bd9da7 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -87,7 +87,7 @@ void CANMessages::process(QHash> *messages) { } bool CANMessages::eventFilter(const Event *event) { - static double prev_update_sec = 0; + static double prev_update_ts = 0; // drop packets when the GUI thread is calling seekTo. to make sure the current_sec is accurate. if (!seeking && event->which == cereal::Event::Which::CAN) { if (!received_msgs) { @@ -121,8 +121,9 @@ bool CANMessages::eventFilter(const Event *event) { } } - if (current_sec < prev_update_sec || (current_sec - prev_update_sec) > 1.0 / settings.fps) { - prev_update_sec = current_sec; + double ts = millis_since_boot(); + if ((ts - prev_update_ts) > (1000.0 / settings.fps)) { + prev_update_ts = ts; // use pointer to avoid data copy in queued connection. emit received(received_msgs.release()); } From 87e0a5dd1a0f58ce119d652808df8888e85ced2a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 25 Oct 2022 02:46:40 +0800 Subject: [PATCH 0073/1179] Cabana: display overlapping bits warning (#26219) display overlapping bits warning --- tools/cabana/binaryview.cc | 14 ++++++++++++++ tools/cabana/binaryview.h | 2 ++ tools/cabana/detailwidget.cc | 21 ++++++++++++++++----- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 5d191d2ca3..26fecd8c38 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -132,6 +132,20 @@ const Signal *BinaryView::getResizingSignal() const { return nullptr; } +QSet BinaryView::getOverlappingSignals() const { + QSet overlapping; + for (int i = 0; i < model->rowCount(); ++i) { + for (int j = 0; j < model->columnCount() - 1; ++j) { + auto item = (const BinaryViewModel::Item *)model->index(i, j).internalPointer(); + if (item && item->sigs.size() > 1) { + for (auto s : item->sigs) + overlapping.insert(s); + } + } + } + return overlapping; +} + // BinaryViewModel void BinaryViewModel::setMessage(const QString &message_id) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index e57033b797..0f58e9ed20 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -59,6 +60,7 @@ public: void updateState(); void highlight(const Signal *sig); const Signal *hoveredSignal() const { return hovered_sig; } + QSet getOverlappingSignals() const; signals: void signalHovered(const Signal *sig); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 443b33b521..7290e4e6ff 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -49,7 +49,7 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); QLabel *warning_icon = new QLabel(this); warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning)); - warning_hlayout->addWidget(warning_icon); + warning_hlayout->addWidget(warning_icon, 0, Qt::AlignTop); warning_label = new QLabel(this); warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); warning_widget->hide(); @@ -107,6 +107,8 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { if (msg_id.isEmpty()) return; warning_widget->hide(); + QStringList warnings; + clearLayout(signals_container->layout()); QString msg_name = tr("untitled"); if (auto msg = dbc()->msg(msg_id)) { @@ -124,16 +126,25 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { } } msg_name = msg->name.c_str(); - if (msg->size != can->lastMessage(msg_id).dat.size()) { - warning_label->setText(tr("Message size (%1) is incorrect!").arg(msg->size)); - warning_widget->show(); - } + if (msg->size != can->lastMessage(msg_id).dat.size()) + warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } edit_btn->setVisible(true); name_label->setText(msg_name); binary_view->setMessage(msg_id); history_log->setMessage(msg_id); + + // Check overlapping bits + if (auto overlapping = binary_view->getOverlappingSignals(); !overlapping.isEmpty()) { + for (auto s : overlapping) + warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); + } + + if (!warnings.isEmpty()) { + warning_label->setText(warnings.join('\n')); + warning_widget->show(); + } } void DetailWidget::updateState() { From 3df83a7809d60cb25122881aadbcbe050374d7c7 Mon Sep 17 00:00:00 2001 From: d3v1n11 <115375208+d3v1n11@users.noreply.github.com> Date: Mon, 24 Oct 2022 14:57:13 -0500 Subject: [PATCH 0074/1179] Hyundai: add 2020 Palisade FW versions (#26085) * Update values.py * Remove unknown versions Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1eed03923c..96c4201773 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -791,6 +791,7 @@ FW_VERSIONS = { }, CAR.PALISADE: { (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00LX2_ SCC F-CUP 1.00 1.04 99110-S8100 ', b'\xf1\x00LX2_ SCC F-CUP 1.00 1.05 99110-S8100 ', b'\xf1\x00LX2 SCC FHCUP 1.00 1.04 99110-S8100 ', b'\xf1\x00LX2_ SCC FHCU- 1.00 1.05 99110-S8100 ', @@ -804,6 +805,7 @@ FW_VERSIONS = { b'\xf1\x00LX ESC \x01 1031\t\x10 58910-S8360', b'\xf1\x00LX ESC \x0b 101\x19\x03\x17 58910-S8330', b'\xf1\x00LX ESC \x0b 102\x19\x05\x07 58910-S8330', + b'\xf1\x00LX ESC \x0b 103\x19\t\t 58910-S8350', b'\xf1\x00LX ESC \x0b 103\x19\t\x07 58910-S8330', b'\xf1\x00LX ESC \x0b 103\x19\t\x10 58910-S8360', b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360', @@ -818,6 +820,7 @@ FW_VERSIONS = { ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00LX2 MDPS C 1,00 1,03 56310-S8020 4LXDC103', + b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8000 4LXDC103', b'\xf1\x00LX2 MDPS C 1.00 1.03 56310-S8020 4LXDC103', b'\xf1\x00LX2 MDPS C 1.00 1.04 56310-S8020 4LXDC104', b'\xf1\x00ON MDPS C 1.00 1.00 56340-S9000 8B13', @@ -834,6 +837,7 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28', + b'\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6', b'\xf1\x87LBLUFN591307KF25vgvw\x97wwwy\x99\xa7\x99\x99\xaa\xa9\x9af\x88\x96h\x95o\xf7\xff\x99f/\xff\xe4c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB2\xd7\xc1/\xd1', b'\xf1\x87LBLUFN650868KF36\xa9\x98\x89\x88\xa8\x88\x88\x88h\x99\xa6\x89fw\x86gw\x88\x97x\xaa\x7f\xf6\xff\xbb\xbb\x8f\xff+\x82\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', From 92b458c70990572dfefcf29e78c04bac822be56e Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 24 Oct 2022 21:40:01 -0400 Subject: [PATCH 0075/1179] HKG: Add FW and Remove from dashcamOnly for 2019 Elantra GT i30 (#25951) * HKG: Add FW for 2019 Elantra GT i30 * Add test route * remove can fp * revert that * actually shares the same platform with the ceed * marketed as Elantra i30 * stash * Revert "stash" This reverts commit 03b164c9dbad53ff22a961d7a93848b8c91d1722. * add car infos * gen docs * combine with elantra * legacy again * update docs Co-authored-by: Adeeb Shihadeh Co-authored-by: Shane Smiskol --- docs/CARS.md | 4 ++- selfdrive/car/hyundai/interface.py | 4 +-- selfdrive/car/hyundai/values.py | 42 +++++++++++++---------- selfdrive/car/tests/routes.py | 2 +- selfdrive/car/torque_data/substitute.yaml | 1 - 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a03da5ca6a..13ac13fe66 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 209 Supported Cars +# 211 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -55,8 +55,10 @@ A supported vehicle is one that just works when you install a comma three. All s |Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| |Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| +|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| +|Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Ioniq 5 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Ioniq 5 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index b1fa8d9e1d..114d124a38 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -31,7 +31,7 @@ class CarInterface(CarInterfaceBase): # These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars likely still work fine. Once a user confirms each car works and a test route is # added to selfdrive/car/tests/routes.py, we can remove it from this list. - ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30} + ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, } if candidate in CANFD_CAR: # detect HDA2 with ADAS Driving ECU @@ -75,7 +75,7 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 15.6 * 1.15 tire_stiffness_factor = 0.63 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30): + elif candidate == CAR.ELANTRA: ret.lateralTuning.pid.kf = 0.00006 ret.mass = 1275. + STD_CARGO_KG ret.wheelbase = 2.7 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 96c4201773..29d0cb3dce 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -34,7 +34,7 @@ class CarControllerParams: # To determine the limit for your car, find the maximum value that the stock LKAS will request. # If the max stock LKAS request is <384, add your car to this list. - elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.ELANTRA_GT_I30, CAR.IONIQ, + elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV, CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO): self.STEER_MAX = 255 @@ -54,7 +54,6 @@ class CAR: ELANTRA = "HYUNDAI ELANTRA 2017" ELANTRA_2021 = "HYUNDAI ELANTRA 2021" ELANTRA_HEV_2021 = "HYUNDAI ELANTRA HYBRID 2021" - ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT" HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016" IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019" IONIQ_HEV_2022 = "HYUNDAI IONIQ HYBRID 2020-2022" @@ -108,13 +107,13 @@ class HyundaiCarInfo(CarInfo): CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { - CAR.ELANTRA: HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_b), - CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), - CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), - CAR.ELANTRA_GT_I30: [ + CAR.ELANTRA: [ + HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_b), HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e), HyundaiCarInfo("Hyundai i30 2019", harness=Harness.hyundai_e), ], + CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), + CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c), CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness @@ -199,15 +198,6 @@ FINGERPRINTS = { CAR.ELANTRA: [{ 66: 8, 67: 8, 68: 8, 127: 8, 273: 8, 274: 8, 275: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 897: 8, 832: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1314: 8, 1322: 8, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1415: 8, 1419: 8, 1425: 2, 1427: 6, 1440: 8, 1456: 4, 1472: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1532: 5, 2001: 8, 2003: 8, 2004: 8, 2009: 8, 2012: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 }], - CAR.ELANTRA_GT_I30: [{ - 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1193: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1365: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8, 1952: 8, 1960: 8, 1988: 8, 2000: 8, 2001: 8, 2005: 8, 2008: 8, 2009: 8, 2013: 8, 2017: 8, 2025: 8 - }, - { - 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1415: 8, 1419: 8, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1530: 8 - }, - { - 66: 8, 67: 8, 68: 8, 127: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 339: 8, 354: 3, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 688: 5, 790: 8, 809: 8, 832: 8, 897: 8, 899: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1151: 6, 1168: 7, 1170: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1349: 8, 1351: 8, 1353: 8, 1356: 8, 1363: 8, 1366: 8, 1367: 8, 1369: 8, 1407: 8, 1414: 3, 1419: 8, 1427: 6, 1440: 8, 1456: 4, 1470: 8, 1486: 8, 1487: 8, 1491: 8, 1960: 8, 1990: 8, 1998: 8, 2000: 8, 2001: 8, 2004: 8, 2005: 8, 2008: 8, 2009: 8, 2012: 8, 2013: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 - }], CAR.HYUNDAI_GENESIS: [{ 67: 8, 68: 8, 304: 8, 320: 8, 339: 8, 356: 4, 544: 7, 593: 8, 608: 8, 688: 5, 809: 8, 832: 8, 854: 7, 870: 7, 871: 8, 872: 5, 897: 8, 902: 8, 903: 6, 916: 8, 1024: 2, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1287: 4, 1292: 8, 1312: 8, 1322: 8, 1331: 8, 1332: 8, 1333: 8, 1334: 8, 1335: 8, 1342: 6, 1345: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 5, 1407: 8, 1419: 8, 1427: 6, 1434: 2, 1456: 4 }, @@ -1214,6 +1204,23 @@ FW_VERSIONS = { b'\xf1\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf1\x816T6B8051\x00\x00\xf1\x006T6H0_C2\x00\x006T6B8051\x00\x00TJFSG24NH27\xa7\xc2\xb4', ], }, + CAR.ELANTRA: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00PD LKAS AT USA LHD 1.01 1.01 95740-G3100 A54', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DPD0H16NS0e\x0e\xcd\x8e', + ], + (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00PD MDPS C 1.00 1.04 56310/G3300 4PDDC104', + ], + (Ecu.abs, 0x7d1, None): [ + b'\xf1\x00PD ESC \x0b 104\x18\t\x03 58920-G3350', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00PD__ SCC F-CUP 1.00 1.00 96400-G3300 ', + ], + }, CAR.ELANTRA_2021: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', @@ -1394,12 +1401,12 @@ CHECKSUM = { FEATURES = { # which message has the gear - "use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA}, + "use_cluster_gears": {CAR.ELANTRA, CAR.KONA}, "use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON}, "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022}, # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.ELANTRA_GT_I30, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, + "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN} @@ -1419,7 +1426,6 @@ DBC = { CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None), CAR.ELANTRA_2021: dbc_dict('hyundai_kia_generic', None), CAR.ELANTRA_HEV_2021: dbc_dict('hyundai_kia_generic', None), - CAR.ELANTRA_GT_I30: dbc_dict('hyundai_kia_generic', None), CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None), CAR.GENESIS_G70_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None), diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 8c4efe3061..326d80b822 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -23,7 +23,6 @@ non_tested_cars = [ GM.MALIBU, GM.EQUINOX, GM.BOLT_EV, - HYUNDAI.ELANTRA_GT_I30, HYUNDAI.GENESIS_G90, HYUNDAI.KIA_OPTIMA_H, ] @@ -119,6 +118,7 @@ routes = [ CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE), CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA), + CarTestRoute("734ef96182ddf940|2022-10-02--16-41-44", HYUNDAI.ELANTRA), # 2019 Elantra GT CarTestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.ELANTRA_2021), CarTestRoute("715ac05b594e9c59|2021-06-20--16-21-07", HYUNDAI.ELANTRA_HEV_2021), CarTestRoute("7120aa90bbc3add7|2021-08-02--07-12-31", HYUNDAI.SONATA_HYBRID), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index f5e3d1d61d..acd7526003 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -26,7 +26,6 @@ KIA SELTOS 2021: HYUNDAI SONATA 2020 KIA NIRO HYBRID 2019: KIA NIRO EV 2020 KIA NIRO HYBRID 2021: KIA NIRO EV 2020 HYUNDAI VELOSTER 2019: HYUNDAI SONATA 2019 -HYUNDAI I30 N LINE 2019 & GT 2018 DCT: HYUNDAI SONATA 2019 HYUNDAI KONA 2020: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA HYBRID 2020: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA ELECTRIC 2022: HYUNDAI KONA ELECTRIC 2019 From e9fcef99e1edace1d4950c9ac58de0b535926709 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 24 Oct 2022 19:08:20 -0700 Subject: [PATCH 0076/1179] FPv2 tests: test all addrs map to one ECU (#26151) * add test * fix mapping --- selfdrive/car/honda/values.py | 10 +++++----- selfdrive/car/tests/test_fw_fingerprint.py | 11 +++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 638008934a..e0810e0bbb 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -446,7 +446,7 @@ FW_VERSIONS = { b'78109-TED-Q510\x00\x00', b'78109-TEG-A310\x00\x00', ], - (Ecu.fwdCamera, 0x18dab0f1, None): [ + (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-TBA-A020\x00\x00', b'36161-TBA-A030\x00\x00', b'36161-TBA-A040\x00\x00', @@ -964,7 +964,7 @@ FW_VERSIONS = { b'77959-THR-A110\x00\x00', b'77959-THR-X010\x00\x00', ], - (Ecu.fwdCamera, 0x18dab0f1, None): [ + (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-THR-A020\x00\x00', b'36161-THR-A030\x00\x00', b'36161-THR-A110\x00\x00', @@ -1068,7 +1068,7 @@ FW_VERSIONS = { b'39990-TG7-A070\x00\x00', b'39990-TGS-A230\x00\x00', ], - (Ecu.fwdCamera, 0x18dab0f1, None): [ + (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-TG7-A310\x00\x00', b'36161-TG7-A520\x00\x00', b'36161-TG7-A630\x00\x00', @@ -1176,7 +1176,7 @@ FW_VERSIONS = { b'57114-TX5-A220\x00\x00', b'57114-TX4-A220\x00\x00', ], - (Ecu.fwdCamera, 0x18dab0f1, None): [ + (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-TX5-A030\x00\x00', b'36161-TX4-A030\x00\x00', ], @@ -1273,7 +1273,7 @@ FW_VERSIONS = { b'39990-T6Z-A030\x00\x00', b'39990-T6Z-A050\x00\x00', ], - (Ecu.fwdCamera, 0x18dab0f1, None): [ + (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-T6Z-A020\x00\x00', b'36161-T6Z-A310\x00\x00', b'36161-T6Z-A420\x00\x00', diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index b9926301f1..2e43103852 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import random import unittest +from collections import defaultdict from parameterized import parameterized from cereal import car @@ -44,6 +45,16 @@ class TestFwFingerprint(unittest.TestCase): duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1} self.assertFalse(len(duplicates), f"{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}") + def test_all_addrs_map_to_one_ecu(self): + for brand, cars in VERSIONS.items(): + addr_to_ecu = defaultdict(set) + for ecus in cars.values(): + for ecu_type, addr, sub_addr in ecus.keys(): + addr_to_ecu[(addr, sub_addr)].add(ecu_type) + ecus_for_addr = addr_to_ecu[(addr, sub_addr)] + ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_for_addr]) + self.assertLessEqual(len(ecus_for_addr), 1, f"{brand} has multiple ECUs that map to one address: {ecu_strings} -> ({hex(addr)}, {sub_addr})") + def test_data_collection_ecus(self): # Asserts no extra ECUs are in the fingerprinting database for brand, config in FW_QUERY_CONFIGS.items(): From a22ce68699ef4d6714a2921f19ed7d793ea619a5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 24 Oct 2022 19:37:18 -0700 Subject: [PATCH 0077/1179] jenkins: disable camerad while new box is built --- Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index b9b9eda667..85b4880463 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -137,6 +137,7 @@ pipeline { } } + /* stage('camerad') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { @@ -147,6 +148,7 @@ pipeline { ]) } } + */ stage('replay') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } From 506a150e735e72b5af53d800260a65a821b95949 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 24 Oct 2022 19:37:52 -0700 Subject: [PATCH 0078/1179] bump cereal --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 38133307b2..1d25fc3f20 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 38133307b2e6036e76684b39878e79212e545e06 +Subproject commit 1d25fc3f202d5ddeee97848480323e9b14f9bdfa From 15595fc8599f0ddf1e72ed02422e9f6d266db1f6 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Mon, 24 Oct 2022 20:17:05 -0700 Subject: [PATCH 0079/1179] Calibrationd: Calibrate wide from device (#26204) * Use calibrator to stabilize wide transform * Need array * Needs init * Needs to be arr * publish mshg * Check size * Update ref * fix calibration param read when no wide calib * need self! --- selfdrive/locationd/calibrationd.py | 34 +++++++++++++++++++++--- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 9e6536f9b5..4e996bc3b9 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -31,6 +31,7 @@ INPUTS_NEEDED = 5 # Minimum blocks needed for valid calibration INPUTS_WANTED = 50 # We want a little bit more than we need for stability MAX_ALLOWED_SPREAD = np.radians(2) RPY_INIT = np.array([0.0,0.0,0.0]) +WIDE_FROM_DEVICE_EULER_INIT = np.array([0.0, 0.0, 0.0]) # These values are needed to accommodate biggest modelframe PITCH_LIMITS = np.array([-0.09074112085129739, 0.14907572052989657]) @@ -67,6 +68,7 @@ class Calibrator: calibration_params = params.get("CalibrationParams") self.wide_camera = params.get_bool('WideCameraOnly') rpy_init = RPY_INIT + wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT valid_blocks = 0 if param_put and calibration_params: @@ -74,24 +76,34 @@ class Calibrator: msg = log.Event.from_bytes(calibration_params) rpy_init = np.array(msg.liveCalibration.rpyCalib) valid_blocks = msg.liveCalibration.validBlocks + wide_from_device_euler = np.array(msg.liveCalibration.wideFromDeviceEuler) except Exception: cloudlog.exception("Error reading cached CalibrationParams") - self.reset(rpy_init, valid_blocks) + self.reset(rpy_init, valid_blocks, wide_from_device_euler) self.update_status() - def reset(self, rpy_init: np.ndarray = RPY_INIT, valid_blocks: int = 0, smooth_from: Optional[np.ndarray] = None) -> None: + def reset(self, rpy_init: np.ndarray = RPY_INIT, + valid_blocks: int = 0, + wide_from_device_euler_init: np.ndarray = WIDE_FROM_DEVICE_EULER_INIT, + smooth_from: Optional[np.ndarray] = None) -> None: if not np.isfinite(rpy_init).all(): self.rpy = RPY_INIT.copy() else: self.rpy = rpy_init.copy() + if not np.isfinite(wide_from_device_euler_init).all() or len(wide_from_device_euler_init) != 3: + self.wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT.copy() + else: + self.wide_from_device_euler = wide_from_device_euler_init.copy() + if not np.isfinite(valid_blocks) or valid_blocks < 0: self.valid_blocks = 0 else: self.valid_blocks = valid_blocks self.rpys = np.tile(self.rpy, (INPUTS_WANTED, 1)) + self.wide_from_device_eulers = np.tile(self.wide_from_device_euler, (INPUTS_WANTED, 1)) self.idx = 0 self.block_idx = 0 @@ -113,6 +125,7 @@ class Calibrator: def update_status(self) -> None: valid_idxs = self.get_valid_idxs() if valid_idxs: + self.wide_from_device_euler = np.mean(self.wide_from_device_eulers[valid_idxs], axis=0) rpys = self.rpys[valid_idxs] self.rpy = np.mean(rpys, axis=0) max_rpy_calib = np.array(np.max(rpys, axis=0)) @@ -146,7 +159,10 @@ class Calibrator: else: return self.rpy - def handle_cam_odom(self, trans: List[float], rot: List[float], trans_std: List[float]) -> Optional[np.ndarray]: + def handle_cam_odom(self, trans: List[float], + rot: List[float], + wide_from_device_euler: List[float], + trans_std: List[float]) -> Optional[np.ndarray]: self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) @@ -165,7 +181,15 @@ class Calibrator: new_rpy = euler_from_rot(rot_from_euler(self.get_smooth_rpy()).dot(rot_from_euler(observed_rpy))) new_rpy = sanity_clip(new_rpy) - self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) + if len(wide_from_device_euler) == 3: + new_wide_from_device_euler = np.array(wide_from_device_euler) + else: + new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT + + self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) + self.wide_from_device_eulers[self.block_idx] = (self.idx*self.wide_from_device_eulers[self.block_idx] + + (BLOCK_SIZE - self.idx) * new_wide_from_device_euler) / float(BLOCK_SIZE) self.idx = (self.idx + 1) % BLOCK_SIZE if self.idx == 0: self.block_idx += 1 @@ -187,6 +211,7 @@ class Calibrator: liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100) liveCalibration.rpyCalib = smooth_rpy.tolist() liveCalibration.rpyCalibSpread = self.calib_spread.tolist() + liveCalibration.wideFromDeviceEuler = self.wide_from_device_euler.tolist() if self.not_car: liveCalibration.validBlocks = INPUTS_NEEDED @@ -223,6 +248,7 @@ def calibrationd_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[m calibrator.handle_v_ego(sm['carState'].vEgo) new_rpy = calibrator.handle_cam_odom(sm['cameraOdometry'].trans, sm['cameraOdometry'].rot, + sm['cameraOdometry'].wideFromDeviceEuler, sm['cameraOdometry'].transStd) if DEBUG and new_rpy is not None: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 230e81d949..d03b897f9d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f5a352666728344ca5065bb44c47c1f5650b4243 +a5c77655fba5563e8128fb655f69b1bbd02198aa From 27e315e58f5273da79803ad95737fc15483fef21 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 25 Oct 2022 00:12:49 -0700 Subject: [PATCH 0080/1179] GM: reduce LKAS faults while inactive (#26196) * send at 10hz when inactive * try to make it fine to switch rates * fix rate * todododo * fine if we skip, we usually send too early * clean up * this may be required, 50Hz is not really needed to sync/initialize * preserves previous behavior (not sure if this makes sense) * Revert "preserves previous behavior (not sure if this makes sense)" This reverts commit 3b297bca72307b5cba09bec4e2cd8e0f2761af42. * Revert "this may be required, 50Hz is not really needed to sync/initialize" This reverts commit a6b4693814214d3f508db922f3b371c402a13995. * rm com * Update ref_commit * gate behind GM Cam * common logic * bet * update refs --- selfdrive/car/gm/carcontroller.py | 16 ++++++++++++---- selfdrive/car/gm/values.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index b56b3bfca6..a75eb89f25 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -22,6 +22,7 @@ class CarController: self.apply_gas = 0 self.apply_brake = 0 self.frame = 0 + self.last_steer_frame = 0 self.last_button_frame = 0 self.cancel_counter = 0 @@ -46,15 +47,21 @@ class CarController: # Send CAN commands. can_sends = [] - # Steering (50Hz) + # Steering (Active: 50Hz, inactive: 10Hz) + # Attempt to sync with camera on startup at 50Hz, first few msgs are blocked + init_lka_counter = not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera + steer_step = self.params.INACTIVE_STEER_STEP + if CC.latActive or init_lka_counter: + steer_step = self.params.ACTIVE_STEER_STEP + # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the # next Panda loopback confirmation in the current CS frame. if CS.loopback_lka_steering_cmd_updated: self.lka_steering_cmd_counter += 1 self.sent_lka_steering_cmd = True - elif (self.frame % self.params.STEER_STEP) == 0: - # Initialize ASCMLKASteeringCmd counter using the camera - if not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera: + elif (self.frame - self.last_steer_frame) >= steer_step: + # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus + if init_lka_counter: self.lka_steering_cmd_counter = CS.camera_lka_steering_cmd_counter + 1 if CC.latActive: @@ -63,6 +70,7 @@ class CarController: else: apply_steer = 0 + self.last_steer_frame = self.frame self.apply_steer_last = apply_steer idx = self.lka_steering_cmd_counter % 4 can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, CC.latActive)) diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index f8f9e7f043..85e291aaf6 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -11,7 +11,8 @@ Ecu = car.CarParams.Ecu class CarControllerParams: STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output - STEER_STEP = 2 # Control frames per command (50hz) + ACTIVE_STEER_STEP = 2 # Active control frames per command (50hz) + INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) STEER_DELTA_UP = 7 # Delta rates require review due to observed EPS weakness STEER_DELTA_DOWN = 17 STEER_DRIVER_ALLOWANCE = 50 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d03b897f9d..604abd666c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a5c77655fba5563e8128fb655f69b1bbd02198aa +9d042d06f61c8f48e8c7a4e30001630c14712272 \ No newline at end of file From bc7fc481d57cbdfb8c727a38ba5a32e856315df0 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 25 Oct 2022 11:33:02 -0700 Subject: [PATCH 0081/1179] pj: update thermal layout + layout test (#26224) --- tools/plotjuggler/layouts/thermal_debug.xml | 93 +++++++++++---------- tools/plotjuggler/test_plotjuggler.py | 22 ++++- 2 files changed, 68 insertions(+), 47 deletions(-) diff --git a/tools/plotjuggler/layouts/thermal_debug.xml b/tools/plotjuggler/layouts/thermal_debug.xml index cebda81753..c10b78f1c5 100644 --- a/tools/plotjuggler/layouts/thermal_debug.xml +++ b/tools/plotjuggler/layouts/thermal_debug.xml @@ -1,82 +1,83 @@ - + - + - - + + - - - - - - - - + + + + + + + + - - + + - - - - + + + + - - + + - + - + - - + + - + - - + + - + + - - + + - + - + - - + + - - - - + + + + - - + + - - - - + + + + @@ -92,8 +93,8 @@ - - + + diff --git a/tools/plotjuggler/test_plotjuggler.py b/tools/plotjuggler/test_plotjuggler.py index edaec9c80a..8fc032042a 100755 --- a/tools/plotjuggler/test_plotjuggler.py +++ b/tools/plotjuggler/test_plotjuggler.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +import glob import signal import subprocess import time @@ -9,12 +10,14 @@ from common.basedir import BASEDIR from common.timeout import Timeout from tools.plotjuggler.juggle import install +PJ_DIR = os.path.join(BASEDIR, "tools/plotjuggler") + class TestPlotJuggler(unittest.TestCase): def test_demo(self): install() - pj = os.path.join(BASEDIR, "tools/plotjuggler/juggle.py") + pj = os.path.join(PJ_DIR, "juggle.py") p = subprocess.Popen(f'QT_QPA_PLATFORM=offscreen {pj} --demo None 1 --qlog', stderr=subprocess.PIPE, shell=True, start_new_session=True) @@ -29,5 +32,22 @@ class TestPlotJuggler(unittest.TestCase): self.assertEqual(p.poll(), None) os.killpg(os.getpgid(p.pid), signal.SIGTERM) + # TODO: also test that layouts successfully load + def test_layouts(self): + bad_strings = ( + # if a previously loaded file is defined, + # PJ will throw a warning when loading the layout + "fileInfo", + "previouslyLoaded_Datafiles", + ) + for fn in glob.glob(os.path.join(PJ_DIR, "layouts/*")): + name = os.path.basename(fn) + with self.subTest(layout=name): + with open(fn) as f: + layout = f.read() + violations = [s for s in bad_strings if s in layout] + assert len(violations) == 0, f"These should be stripped out of the layout: {str(violations)}" + + if __name__ == "__main__": unittest.main() From 6d30b1ee8314539f66eee000ac7a13ac7ccb506c Mon Sep 17 00:00:00 2001 From: Rewat S <76684800+taperec@users.noreply.github.com> Date: Wed, 26 Oct 2022 02:50:50 +0700 Subject: [PATCH 0082/1179] Multilang: add missing Thai translations (#26234) --- selfdrive/ui/translations/main_th.ts | 92 +++++----------------------- 1 file changed, 16 insertions(+), 76 deletions(-) diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 5a8bf861df..95880e69c9 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -60,11 +60,11 @@ Cellular Metered - + ลดการส่งข้อมูลผ่านเซลลูล่าร์ Prevent large data uploads when on a metered connection - + ปิดการอัพโหลดข้อมูลขนาดใหญ่เมื่อเชื่อมต่อผ่านเซลลูล่าร์ @@ -802,54 +802,6 @@ location set SoftwarePanel - - Git Branch - Git Branch - - - Git Commit - Git Commit - - - OS Version - เวอร์ชันระบบปฏิบัติการ - - - Version - เวอร์ชั่น - - - Last Update Check - ตรวจสอบการอัปเดตล่าสุด - - - The last time openpilot successfully checked for an update. The updater only runs while the car is off. - ครั้งสุดท้ายที่ openpilot ตรวจสอบการอัปเดตสำเร็จ ตัวอัปเดตจะทำงานในขณะที่รถดับเครื่องอยู่เท่านั้น - - - Check for Update - ตรวจสอบการอัปเดต - - - CHECKING - กำลังตรวจสอบ - - - Switch Branch - เปลี่ยน Branch - - - ENTER - เปลี่ยน - - - The new branch will be pulled the next time the updater runs. - Branch ใหม่จะถูกติดตั้งในครั้งต่อไปที่ตัวอัปเดตทำงาน - - - Enter branch name - ใส่ชื่อ Branch - Uninstall %1 ถอนการติดตั้ง %1 @@ -862,45 +814,41 @@ location set Are you sure you want to uninstall? คุณแน่ใจหรือไม่ว่าต้องการถอนการติดตั้ง? - - failed to fetch update - โหลดข้อมูลอัปเดตไม่สำเร็จ - CHECK ตรวจสอบ Updates are only downloaded while the car is off. - + ตัวอัปเดตจะดำเนินการดาวน์โหลดเมื่อรถดับเครื่องยนต์อยู่เท่านั้น Current Version - + เวอร์ชั่นปัจจุบัน Download - + ดาวน์โหลด Install Update - + ติดตั้งตัวอัปเดต INSTALL - + ติดตั้ง Target Branch - + Branch ที่เลือก SELECT - + เลือก Select a branch - + เลือก Branch @@ -1026,37 +974,29 @@ location set Show map on left side when in split screen view. แสดงแผนที่ด้านซ้ายของหน้าจอเมื่ออยู่ในโหมดแบ่งหน้าจอ - - openpilot Longitudinal Control - openpilot การควบคุมการเร่งและลดความเร็ว - - - openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! - openpilot จะปิดการใช้งานเรดาร์ของรถ และจะเข้าควบคุมการเร่งและเบรก คำเตือน: สิ่งนี้จะปิดระบบ AEB! - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - + 🌮 ควบคุมเร่ง/เบรคแบบ End-to-end (อยู่ขั้นพัฒนา) 🌮 Experimental openpilot longitudinal control - + ทดลองใช้ระบบควบคุมการเร่ง/เบรคโดย openpilot <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - + <b>คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในขั้นทดลอง และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด</b> Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - + ให้ openpilot ควบคุมการเร่ง/เบรคแบบ end-to-end โดย openpilot จะขับอย่างที่มนุษย์คิด ระบบยังอยู่ในขั้นทดลอง openpilot longitudinal control is not currently available for this car. - + ขณะนี้ยังไม่มีระบบควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ Enable experimental longitudinal control to enable this. - + เปิดใช้งานระบบควบคุมการเร่ง/เบรคขั้นทดลอง เพื่อเปิดใช้งานสิ่งนี้ From 339253bc05179530e47509e548c482495fbc6e82 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 25 Oct 2022 13:51:23 -0700 Subject: [PATCH 0083/1179] Hyundai: CAN-FD blindspot signals (#26229) * Hyundai: CAN-FD blindspot signals * fix that * update refs --- opendbc | 2 +- selfdrive/car/hyundai/carstate.py | 12 ++++++++++++ selfdrive/car/hyundai/interface.py | 9 +++++++-- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/opendbc b/opendbc index 7bd94e3ff4..a95b0ae8a5 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 7bd94e3ff4a2890eb69118f0dfadb64f9d32d618 +Subproject commit a95b0ae8a5244a9d6311bf72aa2a7d63d41b4a9f diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index e27432e23b..ec2b3059a3 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -187,6 +187,9 @@ class CarState(CarStateBase): ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"]["LEFT_LAMP"], cp.vl["BLINKERS"]["RIGHT_LAMP"]) + if self.CP.enableBsm: + ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0 + ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0 ret.cruiseState.available = True self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1 @@ -450,6 +453,15 @@ class CarState(CarStateBase): ("DOORS_SEATBELTS", 4), ] + if CP.enableBsm: + signals += [ + ("FL_INDICATOR", "BLINDSPOTS_REAR_CORNERS"), + ("FR_INDICATOR", "BLINDSPOTS_REAR_CORNERS"), + ] + checks += [ + ("BLINDSPOTS_REAR_CORNERS", 20), + ] + if CP.flags & HyundaiFlags.CANFD_HDA2 and not CP.openpilotLongitudinalControl: signals += [ ("CRUISE_STATUS", "CRUISE_INFO"), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 114d124a38..147c766008 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -311,6 +311,13 @@ class CarInterface(CarInterfaceBase): ret.vEgoStarting = 0.1 ret.startAccel = 2.0 + # *** feature detection *** + if candidate in CANFD_CAR: + bus = 5 if ret.flags & HyundaiFlags.CANFD_HDA2 else 4 + ret.enableBsm = 0x1e5 in fingerprint[bus] + else: + ret.enableBsm = 0x58b in fingerprint[0] + # *** panda safety config *** if candidate in CANFD_CAR: ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput), @@ -321,8 +328,6 @@ class CarInterface(CarInterfaceBase): if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS: ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS else: - ret.enableBsm = 0x58b in fingerprint[0] - if candidate in LEGACY_SAFETY_MODE_CAR: # these cars require a special panda safety mode due to missing counters and checksums in the messages ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 604abd666c..44eed18493 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -9d042d06f61c8f48e8c7a4e30001630c14712272 \ No newline at end of file +68457035e9223fcbd70bd40966d5a1d9fe4f1567 \ No newline at end of file From 4639862baecfc8ed708827580f441a34731ba137 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 25 Oct 2022 15:21:43 -0700 Subject: [PATCH 0084/1179] UI: show git commit date (#26240) * show version description while offroad * ui fixups * parse date * cleanup --- selfdrive/ui/qt/home.cc | 16 +++++----------- selfdrive/ui/qt/home.h | 6 +++++- selfdrive/ui/qt/offroad/software_settings.cc | 4 ++-- selfdrive/ui/qt/util.cc | 4 ---- selfdrive/ui/qt/util.h | 1 - selfdrive/ui/qt/widgets/controls.cc | 4 ++-- selfdrive/ui/qt/widgets/controls.h | 2 +- selfdrive/ui/qt/widgets/scrollview.cc | 2 ++ selfdrive/updated.py | 14 +++++++++++--- 9 files changed, 28 insertions(+), 25 deletions(-) diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 78bc6aab40..3fe00e6ed9 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -1,11 +1,9 @@ #include "selfdrive/ui/qt/home.h" -#include #include #include #include -#include "common/params.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/widgets/drive_stats.h" #include "selfdrive/ui/qt/widgets/prime.h" @@ -109,22 +107,20 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { header_layout->setContentsMargins(15, 15, 15, 0); header_layout->setSpacing(16); - date = new QLabel(); - header_layout->addWidget(date, 1, Qt::AlignHCenter | Qt::AlignLeft); - update_notif = new QPushButton(tr("UPDATE")); update_notif->setVisible(false); update_notif->setStyleSheet("background-color: #364DEF;"); QObject::connect(update_notif, &QPushButton::clicked, [=]() { center_layout->setCurrentIndex(1); }); - header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignRight); + header_layout->addWidget(update_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); alert_notif = new QPushButton(); alert_notif->setVisible(false); alert_notif->setStyleSheet("background-color: #E22C2C;"); QObject::connect(alert_notif, &QPushButton::clicked, [=] { center_layout->setCurrentIndex(2); }); - header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignRight); + header_layout->addWidget(alert_notif, 0, Qt::AlignHCenter | Qt::AlignLeft); - header_layout->addWidget(new QLabel(getBrandVersion()), 0, Qt::AlignHCenter | Qt::AlignRight); + version = new ElidedLabel(); + header_layout->addWidget(version, 0, Qt::AlignHCenter | Qt::AlignRight); main_layout->addLayout(header_layout); @@ -184,9 +180,7 @@ void OffroadHome::hideEvent(QHideEvent *event) { } void OffroadHome::refresh() { - QString locale_name = QString(uiState()->language).replace("main_", ""); - QString dateString = QLocale(locale_name).toString(QDateTime::currentDateTime(), "dddd, MMMM d"); - date->setText(dateString); + version->setText(getBrand() + " " + QString::fromStdString(params.get("UpdaterCurrentDescription"))); bool updateAvailable = update_widget->refresh(); int alerts = alerts_widget->refresh(); diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h index 94f1330109..6636da56ec 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -7,10 +7,12 @@ #include #include +#include "common/params.h" #include "selfdrive/ui/qt/offroad/driverview.h" #include "selfdrive/ui/qt/body.h" #include "selfdrive/ui/qt/onroad.h" #include "selfdrive/ui/qt/sidebar.h" +#include "selfdrive/ui/qt/widgets/controls.h" #include "selfdrive/ui/qt/widgets/offroad_alerts.h" #include "selfdrive/ui/ui.h" @@ -25,8 +27,10 @@ private: void hideEvent(QHideEvent *event) override; void refresh(); + Params params; + QTimer* timer; - QLabel* date; + ElidedLabel* version; QStackedLayout* center_layout; UpdateAlert *update_widget; OffroadAlert* alerts_widget; diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 4f048241c3..e08a02a4d6 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -145,11 +145,11 @@ void SoftwarePanel::updateLabels() { targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); // current + new versions - versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription")).left(40)); + versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription"))); versionLbl->setDescription(QString::fromStdString(params.get("UpdaterCurrentReleaseNotes"))); installBtn->setVisible(!is_onroad && params.getBool("UpdateAvailable")); - installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription")).left(35)); + installBtn->setValue(QString::fromStdString(params.get("UpdaterNewDescription"))); installBtn->setDescription(QString::fromStdString(params.get("UpdaterNewReleaseNotes"))); update(); diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index c5697c1045..59903e3376 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -21,10 +21,6 @@ QString getBrand() { return Params().getBool("Passive") ? QObject::tr("dashcam") : QObject::tr("openpilot"); } -QString getBrandVersion() { - return getBrand() + " v" + getVersion().left(14).trimmed(); -} - QString getUserAgent() { return "openpilot-" + getVersion(); } diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h index 209f051963..61a27a8669 100644 --- a/selfdrive/ui/qt/util.h +++ b/selfdrive/ui/qt/util.h @@ -11,7 +11,6 @@ QString getVersion(); QString getBrand(); -QString getBrandVersion(); QString getUserAgent(); std::optional getDongleId(); QMap getSupportedLanguages(); diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index a1ebf57b07..d3b77935df 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -41,7 +41,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons hlayout->addWidget(title_label); // value next to control button - value = new QLabel(); + value = new ElidedLabel(); value->setAlignment(Qt::AlignRight | Qt::AlignVCenter); value->setStyleSheet("color: #aaaaaa"); hlayout->addWidget(value); @@ -70,7 +70,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons } void AbstractControl::hideEvent(QHideEvent *e) { - if(description != nullptr) { + if (description != nullptr) { description->hide(); } } diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index c42716828f..f11f9baf59 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -65,7 +65,7 @@ protected: QPushButton *title_label; private: - QLabel *value; + ElidedLabel *value; QLabel *description = nullptr; }; diff --git a/selfdrive/ui/qt/widgets/scrollview.cc b/selfdrive/ui/qt/widgets/scrollview.cc index bd4309d8d0..5536593016 100644 --- a/selfdrive/ui/qt/widgets/scrollview.cc +++ b/selfdrive/ui/qt/widgets/scrollview.cc @@ -3,6 +3,8 @@ #include #include +// TODO: disable horizontal scrolling and resize + ScrollView::ScrollView(QWidget *w, QWidget *parent) : QScrollArea(parent) { setWidget(w); setWidgetResizable(true); diff --git a/selfdrive/updated.py b/selfdrive/updated.py index 57f957cfff..c261a92a84 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -280,17 +280,25 @@ class Updater: # Write out current and new version info def get_description(basedir: str) -> str: + if not os.path.exists(basedir): + return "" + version = "" branch = "" commit = "" + commit_date = "" try: branch = self.get_branch(basedir) - commit = self.get_commit_hash(basedir) + commit = self.get_commit_hash(basedir)[:7] with open(os.path.join(basedir, "common", "version.h")) as f: version = f.read().split('"')[1] + + commit_unix_ts = run(["git", "show", "-s", "--format=%ct", "HEAD"], basedir).rstrip() + dt = datetime.datetime.fromtimestamp(int(commit_unix_ts)) + commit_date = dt.strftime("%b %d") except Exception: - pass - return f"{version} / {branch} / {commit[:7]}" + cloudlog.exception("updater.get_description") + return f"{version} / {branch} / {commit} / {commit_date}" self.params.put("UpdaterCurrentDescription", get_description(BASEDIR)) self.params.put("UpdaterCurrentReleaseNotes", parse_release_notes(BASEDIR)) self.params.put("UpdaterNewDescription", get_description(FINALIZED)) From 1be4150089a4ac9281879ddfaccd0f9447c14f3d Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Tue, 25 Oct 2022 17:32:49 -0500 Subject: [PATCH 0085/1179] Mazda: Add CX-5 2023 to supported cars (#26182) * Mazda: Add CX-5 2023 to supported cars Signed-off-by: Jafar Al-Gharaibeh * add missing cam fw Signed-off-by: Jafar Al-Gharaibeh Co-authored-by: Adeeb Shihadeh --- selfdrive/car/mazda/values.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 921dc7a634..129273efee 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -43,7 +43,7 @@ CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = { CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"), CAR.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"), CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-22", video_link="https://youtu.be/dA3duO4a0O4"), - CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022"), + CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022-23"), } @@ -89,6 +89,7 @@ FW_VERSIONS = { ], (Ecu.fwdCamera, 0x706, None): [ b'GSH7-67XK2-S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'GSH7-67XK2-T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.transmission, 0x7e1, None): [ b'PYB2-21PS1-H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From 9091e737c8fea44158570e6e15668e30d518d4d3 Mon Sep 17 00:00:00 2001 From: Greg Hogan Date: Tue, 25 Oct 2022 15:51:39 -0700 Subject: [PATCH 0086/1179] controlsd: update is_metric live (#26228) * fix speed increment if units changed while driving * don't recreate params Co-authored-by: Adeeb Shihadeh --- selfdrive/controls/controlsd.py | 40 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index cbc54eadb8..5172cc4044 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -82,13 +82,13 @@ class Controls: self.log_sock = messaging.sub_sock('androidLog') - params = Params() + self.params = Params() self.sm = sm if self.sm is None: ignore = ['testJoystick'] if SIMULATION: ignore += ['driverCameraState', 'managerState'] - if params.get_bool('WideCameraOnly'): + if self.params.get_bool('WideCameraOnly'): ignore += ['roadCameraState'] self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', @@ -105,22 +105,22 @@ class Controls: else: self.CI, self.CP = CI, CI.CP - self.joystick_mode = params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None) + self.joystick_mode = self.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") + self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") self.CP.alternativeExperience = 0 if not self.disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS - if self.CP.dashcamOnly and params.get_bool("DashcamOverride"): + if self.CP.dashcamOnly and self.params.get_bool("DashcamOverride"): self.CP.dashcamOnly = False # read params - self.is_metric = params.get_bool("IsMetric") - self.is_ldw_enabled = params.get_bool("IsLdwEnabled") - openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle") - passive = params.get_bool("Passive") or not openpilot_enabled_toggle + self.is_metric = self.params.get_bool("IsMetric") + self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled") + openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle") + passive = self.params.get_bool("Passive") or not openpilot_enabled_toggle # detect sound card presence and ensure successful init sounds_available = HARDWARE.get_sound_card_online() @@ -139,15 +139,15 @@ class Controls: # Write CarParams for radard cp_bytes = self.CP.to_bytes() - params.put("CarParams", cp_bytes) + self.params.put("CarParams", cp_bytes) put_nonblocking("CarParamsCache", cp_bytes) put_nonblocking("CarParamsPersistent", cp_bytes) # cleanup old params if not self.CP.experimentalLongitudinalAvailable: - params.remove("ExperimentalLongitudinalEnabled") + self.params.remove("ExperimentalLongitudinalEnabled") if not self.CP.openpilotLongitudinalControl: - params.remove("EndToEndLong") + self.params.remove("EndToEndLong") self.CC = car.CarControl.new_message() self.CS_prev = car.CarState.new_message() @@ -583,9 +583,9 @@ class Controls: """Given the state, this function returns a CarControl packet""" # Update VehicleModel - params = self.sm['liveParameters'] - x = max(params.stiffnessFactor, 0.1) - sr = max(params.steerRatio, 0.1) + lp = self.sm['liveParameters'] + x = max(lp.stiffnessFactor, 0.1) + sr = max(lp.steerRatio, 0.1) self.VM.update_params(x, sr) # Update Torque Params @@ -628,7 +628,7 @@ class Controls: lat_plan.psis, lat_plan.curvatures, lat_plan.curvatureRates) - actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, params, + actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp, self.last_actuators, self.steer_limited, self.desired_curvature, self.desired_curvature_rate, self.sm['liveLocationKalman']) else: @@ -768,10 +768,10 @@ class Controls: (self.state == State.softDisabling) # Curvature & Steering angle - params = self.sm['liveParameters'] + lp = self.sm['liveParameters'] - steer_angle_without_offset = math.radians(CS.steeringAngleDeg - params.angleOffsetDeg) - curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, params.roll) + steer_angle_without_offset = math.radians(CS.steeringAngleDeg - lp.angleOffsetDeg) + curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll) # controlsState dat = messaging.new_message('controlsState') @@ -856,6 +856,8 @@ class Controls: start_time = sec_since_boot() self.prof.checkpoint("Ratekeeper", ignore=True) + self.is_metric = self.params.get_bool("IsMetric") + # Sample data from sockets and get a carState CS = self.data_sample() cloudlog.timestamp("Data sampled") From 87e26b09c17ba029b2054c256acae1c2413a3bd1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 25 Oct 2022 15:57:29 -0700 Subject: [PATCH 0087/1179] update car docs --- docs/CARS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index 13ac13fe66..2df2b96e24 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -122,7 +122,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX Hybrid 2017-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Mazda|CX-5 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| +|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Mazda|CX-9 2021-22|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B| |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| From f6bab0cd678e3020c7b0e2257309df69f83de0f0 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 25 Oct 2022 16:09:36 -0700 Subject: [PATCH 0088/1179] [torqued] Extend to all Toyota and Hyundai cars (#26238) * extend to toyota and hyundai * remove all pid control in hyundai * remove indi tunes * remove toyota lat tunes * release notes * rm tunes.py Co-authored-by: Adeeb Shihadeh --- RELEASES.md | 1 + selfdrive/car/hyundai/interface.py | 94 +------------------------- selfdrive/car/toyota/interface.py | 38 ++++------- selfdrive/car/toyota/tunes.py | 102 ----------------------------- 4 files changed, 15 insertions(+), 220 deletions(-) delete mode 100644 selfdrive/car/toyota/tunes.py diff --git a/RELEASES.md b/RELEASES.md index b424259581..744168c8fb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,6 +6,7 @@ Version 0.8.17 (2022-XX-XX) * New end-to-end distracted trigger * Self-tuning torque lateral controller parameters * Parameters learned live for each car +* Torque controller used on all Toyota, Lexus, Hyundai, Kia, and Genesis models * UI updates * Multi-language in navigation * Matched speeds shown on car's dash diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 147c766008..6a1d741dec 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -45,141 +45,92 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.1 # Default delay ret.steerLimitTimer = 0.4 tire_stiffness_factor = 1. + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) if candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022): - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 3982. * CV.LB_TO_KG + STD_CARGO_KG ret.wheelbase = 2.766 # Values from optimizer ret.steerRatio = 16.55 # 13.8 is spec end-to-end tire_stiffness_factor = 0.82 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[9., 22.], [9., 22.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2, 0.35], [0.05, 0.09]] elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID): ret.mass = 1513. + STD_CARGO_KG ret.wheelbase = 2.84 ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable tire_stiffness_factor = 0.65 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.SONATA_LF: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 4497. * CV.LB_TO_KG ret.wheelbase = 2.804 ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.PALISADE: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 1999. + STD_CARGO_KG ret.wheelbase = 2.90 ret.steerRatio = 15.6 * 1.15 tire_stiffness_factor = 0.63 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.ELANTRA: - ret.lateralTuning.pid.kf = 0.00006 ret.mass = 1275. + STD_CARGO_KG ret.wheelbase = 2.7 ret.steerRatio = 15.4 # 14 is Stock | Settled Params Learner values are steerRatio: 15.401566348670535 tire_stiffness_factor = 0.385 # stiffnessFactor settled on 1.0081302973865127 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] ret.minSteerSpeed = 32 * CV.MPH_TO_MS elif candidate == CAR.ELANTRA_2021: ret.mass = (2800. * CV.LB_TO_KG) + STD_CARGO_KG ret.wheelbase = 2.72 ret.steerRatio = 12.9 tire_stiffness_factor = 0.65 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.ELANTRA_HEV_2021: ret.mass = (3017. * CV.LB_TO_KG) + STD_CARGO_KG ret.wheelbase = 2.72 ret.steerRatio = 12.9 tire_stiffness_factor = 0.65 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.HYUNDAI_GENESIS: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 2060. + STD_CARGO_KG ret.wheelbase = 3.01 ret.steerRatio = 16.5 - ret.lateralTuning.init('indi') - ret.lateralTuning.indi.innerLoopGainBP = [0.] - ret.lateralTuning.indi.innerLoopGainV = [3.5] - ret.lateralTuning.indi.outerLoopGainBP = [0.] - ret.lateralTuning.indi.outerLoopGainV = [2.0] - ret.lateralTuning.indi.timeConstantBP = [0.] - ret.lateralTuning.indi.timeConstantV = [1.4] - ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] - ret.lateralTuning.indi.actuatorEffectivenessV = [2.3] ret.minSteerSpeed = 60 * CV.KPH_TO_MS elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022): ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743.}.get(candidate, 1275.) + STD_CARGO_KG ret.wheelbase = 2.6 ret.steerRatio = 13.42 # Spec tire_stiffness_factor = 0.385 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): - ret.lateralTuning.pid.kf = 0.00006 ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx ret.wheelbase = 2.7 ret.steerRatio = 13.73 # Spec tire_stiffness_factor = 0.385 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): ret.minSteerSpeed = 32 * CV.MPH_TO_MS elif candidate == CAR.IONIQ_PHEV_2019: ret.mass = 1550. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/us/en/vehicles/2019-ioniq-plug-in-hybrid/compare-specs ret.wheelbase = 2.7 ret.steerRatio = 13.73 - ret.lateralTuning.init('indi') - ret.lateralTuning.indi.innerLoopGainBP = [0.] - ret.lateralTuning.indi.innerLoopGainV = [2.5] - ret.lateralTuning.indi.outerLoopGainBP = [0.] - ret.lateralTuning.indi.outerLoopGainV = [3.5] - ret.lateralTuning.indi.timeConstantBP = [0.] - ret.lateralTuning.indi.timeConstantV = [1.4] - ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] - ret.lateralTuning.indi.actuatorEffectivenessV = [1.8] ret.minSteerSpeed = 32 * CV.MPH_TO_MS elif candidate == CAR.VELOSTER: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 3558. * CV.LB_TO_KG ret.wheelbase = 2.80 ret.steerRatio = 13.75 * 1.15 tire_stiffness_factor = 0.5 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.TUCSON: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 3520. * CV.LB_TO_KG ret.wheelbase = 2.67 ret.steerRatio = 14.00 * 1.15 tire_stiffness_factor = 0.385 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.TUCSON_HYBRID_4TH_GEN: ret.mass = 1680. + STD_CARGO_KG # average of all 3 trims ret.wheelbase = 2.756 ret.steerRatio = 16. tire_stiffness_factor = 0.385 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) # Kia elif candidate == CAR.KIA_SORENTO: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 1985. + STD_CARGO_KG ret.wheelbase = 2.78 ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021): - ret.lateralTuning.pid.kf = 0.00006 ret.mass = 1737. + STD_CARGO_KG ret.wheelbase = 2.7 ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec tire_stiffness_factor = 0.385 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] if candidate == CAR.KIA_NIRO_PHEV: ret.minSteerSpeed = 32 * CV.MPH_TO_MS elif candidate == CAR.KIA_SELTOS: @@ -187,15 +138,6 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.63 ret.steerRatio = 14.56 tire_stiffness_factor = 1 - ret.lateralTuning.init('indi') - ret.lateralTuning.indi.innerLoopGainBP = [0.] - ret.lateralTuning.indi.innerLoopGainV = [4.] - ret.lateralTuning.indi.outerLoopGainBP = [0.] - ret.lateralTuning.indi.outerLoopGainV = [3.] - ret.lateralTuning.indi.timeConstantBP = [0.] - ret.lateralTuning.indi.timeConstantV = [1.4] - ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] - ret.lateralTuning.indi.actuatorEffectivenessV = [1.8] elif candidate in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H): ret.mass = 3558. * CV.LB_TO_KG ret.wheelbase = 2.80 @@ -203,92 +145,58 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.5 if candidate == CAR.KIA_OPTIMA_G4: ret.minSteerSpeed = 32 * CV.MPH_TO_MS - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.KIA_STINGER: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 1825. + STD_CARGO_KG ret.wheelbase = 2.78 ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.KIA_FORTE: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 3558. * CV.LB_TO_KG ret.wheelbase = 2.80 ret.steerRatio = 13.75 tire_stiffness_factor = 0.5 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.KIA_CEED: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 1450. + STD_CARGO_KG ret.wheelbase = 2.65 ret.steerRatio = 13.75 tire_stiffness_factor = 0.5 - ret.lateralTuning.pid.kf = 0.00005 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.KIA_K5_2021: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 3228. * CV.LB_TO_KG ret.wheelbase = 2.85 ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims) tire_stiffness_factor = 0.5 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.25], [0.05]] elif candidate == CAR.KIA_EV6: ret.mass = 2055 + STD_CARGO_KG ret.wheelbase = 2.9 ret.steerRatio = 16. tire_stiffness_factor = 0.65 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.IONIQ_5: ret.mass = 2012 + STD_CARGO_KG ret.wheelbase = 3.0 ret.steerRatio = 16. tire_stiffness_factor = 0.65 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only ret.wheelbase = 2.756 ret.steerRatio = 13.6 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) # Genesis elif candidate == CAR.GENESIS_G70: - ret.lateralTuning.init('indi') - ret.lateralTuning.indi.innerLoopGainBP = [0.] - ret.lateralTuning.indi.innerLoopGainV = [2.5] - ret.lateralTuning.indi.outerLoopGainBP = [0.] - ret.lateralTuning.indi.outerLoopGainV = [3.5] - ret.lateralTuning.indi.timeConstantBP = [0.] - ret.lateralTuning.indi.timeConstantV = [1.4] - ret.lateralTuning.indi.actuatorEffectivenessBP = [0.] - ret.lateralTuning.indi.actuatorEffectivenessV = [1.8] ret.steerActuatorDelay = 0.1 ret.mass = 1640.0 + STD_CARGO_KG ret.wheelbase = 2.84 ret.steerRatio = 13.56 elif candidate == CAR.GENESIS_G70_2020: - ret.lateralTuning.pid.kf = 0. - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.112], [0.004]] ret.mass = 3673.0 * CV.LB_TO_KG + STD_CARGO_KG ret.wheelbase = 2.83 ret.steerRatio = 12.9 elif candidate == CAR.GENESIS_G80: - ret.lateralTuning.pid.kf = 0.00005 ret.mass = 2060. + STD_CARGO_KG ret.wheelbase = 3.01 ret.steerRatio = 16.5 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]] elif candidate == CAR.GENESIS_G90: ret.mass = 2200 ret.wheelbase = 3.15 ret.steerRatio = 12.069 - ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16], [0.01]] # *** longitudinal control *** if candidate in CANFD_CAR: diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 28912645ac..0d5acbfff4 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,6 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.tunes import LatTunes, LongTunes, set_long_tune, set_lat_tune from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -74,7 +73,6 @@ class CarInterface(CarInterfaceBase): ret.wheelSpeedFactor = 1.035 tire_stiffness_factor = 0.5533 ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max - set_lat_tune(ret.lateralTuning, LatTunes.PID_C) elif candidate in (CAR.CHR, CAR.CHRH): stop_and_go = True @@ -82,7 +80,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 13.6 tire_stiffness_factor = 0.7933 ret.mass = 3300. * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_F) elif candidate in (CAR.CAMRY, CAR.CAMRYH, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2): stop_and_go = True @@ -90,8 +87,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 13.7 tire_stiffness_factor = 0.7933 ret.mass = 3400. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid - if candidate not in (CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2): - set_lat_tune(ret.lateralTuning, LatTunes.PID_C) elif candidate in (CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2): stop_and_go = True @@ -99,7 +94,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.0 tire_stiffness_factor = 0.8 ret.mass = 4516. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid - set_lat_tune(ret.lateralTuning, LatTunes.PID_G) elif candidate in (CAR.AVALON, CAR.AVALON_2019, CAR.AVALONH_2019, CAR.AVALON_TSS2, CAR.AVALONH_TSS2): # starting from 2019, all Avalon variants have stop and go @@ -109,7 +103,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download tire_stiffness_factor = 0.7983 ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid - set_lat_tune(ret.lateralTuning, LatTunes.PID_H) elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022): stop_and_go = True @@ -117,14 +110,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.3 tire_stiffness_factor = 0.7933 ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid - set_lat_tune(ret.lateralTuning, LatTunes.PID_D) - - # 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary. - # See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891 - for fw in car_fw: - if fw.ecu == "eps" and (fw.fwVersion.startswith(b'\x02') or fw.fwVersion in [b'8965B42181\x00\x00\x00\x00\x00\x00']): - set_lat_tune(ret.lateralTuning, LatTunes.PID_I) - break elif candidate in (CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2): stop_and_go = True @@ -139,7 +124,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.0 # not optimized tire_stiffness_factor = 0.444 # not optimized yet ret.mass = 3677. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max - set_lat_tune(ret.lateralTuning, LatTunes.PID_D) elif candidate == CAR.SIENNA: stop_and_go = True @@ -147,14 +131,12 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 15.5 tire_stiffness_factor = 0.444 ret.mass = 4590. * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_J) elif candidate in (CAR.LEXUS_IS, CAR.LEXUS_RC): ret.wheelbase = 2.79908 ret.steerRatio = 13.3 tire_stiffness_factor = 0.444 ret.mass = 3736.8 * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_L) elif candidate == CAR.LEXUS_CTH: stop_and_go = True @@ -162,7 +144,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 18.6 tire_stiffness_factor = 0.517 ret.mass = 3108 * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max - set_lat_tune(ret.lateralTuning, LatTunes.PID_M) elif candidate in (CAR.LEXUS_NX, CAR.LEXUS_NXH, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2): stop_and_go = True @@ -170,7 +151,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.7 tire_stiffness_factor = 0.444 # not optimized yet ret.mass = 4070 * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_C) elif candidate == CAR.PRIUS_TSS2: stop_and_go = True @@ -178,7 +158,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 13.4 # True steerRatio from older prius tire_stiffness_factor = 0.6371 # hand-tune ret.mass = 3115. * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_N) elif candidate == CAR.MIRAI: stop_and_go = True @@ -186,7 +165,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.8 tire_stiffness_factor = 0.8 ret.mass = 4300. * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_C) elif candidate in (CAR.ALPHARD_TSS2, CAR.ALPHARDH_TSS2): stop_and_go = True @@ -194,7 +172,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.2 tire_stiffness_factor = 0.444 ret.mass = 4305. * CV.LB_TO_KG + STD_CARGO_KG - set_lat_tune(ret.lateralTuning, LatTunes.PID_J) ret.centerToFront = ret.wheelbase * 0.44 @@ -230,12 +207,23 @@ class CarInterface(CarInterfaceBase): # to a negative value, so it won't matter. ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else MIN_ACC_SPEED + tune = ret.longitudinalTuning if candidate in TSS2_CAR or ret.enableGasInterceptor: - set_long_tune(ret.longitudinalTuning, LongTunes.TSS2) + tune.deadzoneBP = [0., 8.05] + tune.deadzoneV = [.0, .14] + tune.kpBP = [0., 5., 20.] + tune.kpV = [1.3, 1.0, 0.7] + tune.kiBP = [0., 5., 12., 20., 27.] + tune.kiV = [.35, .23, .20, .17, .1] if candidate in TSS2_CAR: ret.stoppingDecelRate = 0.3 # reach stopping target smoothly else: - set_long_tune(ret.longitudinalTuning, LongTunes.TSS) + tune.deadzoneBP = [0., 9.] + tune.deadzoneV = [.0, .15] + tune.kpBP = [0., 5., 35.] + tune.kiBP = [0., 35.] + tune.kpV = [3.6, 2.4, 1.5] + tune.kiV = [0.54, 0.36] return ret diff --git a/selfdrive/car/toyota/tunes.py b/selfdrive/car/toyota/tunes.py deleted file mode 100644 index b73ab4c8c9..0000000000 --- a/selfdrive/car/toyota/tunes.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -from enum import Enum - -class LongTunes(Enum): - TSS2 = 0 - TSS = 1 - -class LatTunes(Enum): - INDI_PRIUS = 0 - LQR_RAV4 = 1 - PID_A = 2 - PID_B = 3 - PID_C = 4 - PID_D = 5 - PID_E = 6 - PID_F = 7 - PID_G = 8 - PID_I = 9 - PID_H = 10 - PID_J = 11 - PID_K = 12 - PID_L = 13 - PID_M = 14 - PID_N = 15 - - -###### LONG ###### -def set_long_tune(tune, name): - # Improved longitudinal tune - if name == LongTunes.TSS2: - tune.deadzoneBP = [0., 8.05] - tune.deadzoneV = [.0, .14] - tune.kpBP = [0., 5., 20.] - tune.kpV = [1.3, 1.0, 0.7] - tune.kiBP = [0., 5., 12., 20., 27.] - tune.kiV = [.35, .23, .20, .17, .1] - # Default longitudinal tune - elif name == LongTunes.TSS: - tune.deadzoneBP = [0., 9.] - tune.deadzoneV = [.0, .15] - tune.kpBP = [0., 5., 35.] - tune.kiBP = [0., 35.] - tune.kpV = [3.6, 2.4, 1.5] - tune.kiV = [0.54, 0.36] - else: - raise NotImplementedError('This longitudinal tune does not exist') - - -###### LAT ###### -def set_lat_tune(tune, name, MAX_LAT_ACCEL=2.5, FRICTION=0.01, steering_angle_deadzone_deg=0.0, use_steering_angle=True): - if 'PID' in str(name): - tune.init('pid') - tune.pid.kiBP = [0.0] - tune.pid.kpBP = [0.0] - if name == LatTunes.PID_A: - tune.pid.kpV = [0.2] - tune.pid.kiV = [0.05] - tune.pid.kf = 0.00003 - elif name == LatTunes.PID_C: - tune.pid.kpV = [0.6] - tune.pid.kiV = [0.1] - tune.pid.kf = 0.00006 - elif name == LatTunes.PID_D: - tune.pid.kpV = [0.6] - tune.pid.kiV = [0.1] - tune.pid.kf = 0.00007818594 - elif name == LatTunes.PID_F: - tune.pid.kpV = [0.723] - tune.pid.kiV = [0.0428] - tune.pid.kf = 0.00006 - elif name == LatTunes.PID_G: - tune.pid.kpV = [0.18] - tune.pid.kiV = [0.015] - tune.pid.kf = 0.00012 - elif name == LatTunes.PID_H: - tune.pid.kpV = [0.17] - tune.pid.kiV = [0.03] - tune.pid.kf = 0.00006 - elif name == LatTunes.PID_I: - tune.pid.kpV = [0.15] - tune.pid.kiV = [0.05] - tune.pid.kf = 0.00004 - elif name == LatTunes.PID_J: - tune.pid.kpV = [0.19] - tune.pid.kiV = [0.02] - tune.pid.kf = 0.00007818594 - elif name == LatTunes.PID_L: - tune.pid.kpV = [0.3] - tune.pid.kiV = [0.05] - tune.pid.kf = 0.00006 - elif name == LatTunes.PID_M: - tune.pid.kpV = [0.3] - tune.pid.kiV = [0.05] - tune.pid.kf = 0.00007 - elif name == LatTunes.PID_N: - tune.pid.kpV = [0.35] - tune.pid.kiV = [0.15] - tune.pid.kf = 0.00007818594 - else: - raise NotImplementedError('This PID tune does not exist') - else: - raise NotImplementedError('This lateral tune does not exist') From dcde942d9fb05575dcc70f0b24f9c3c6b7c220ab Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Tue, 25 Oct 2022 16:53:24 -0700 Subject: [PATCH 0089/1179] Long control: add a_change cost in e2e mode (#26237) Add e2e cost --- selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 2aab4b71af..49eb5988e2 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -253,7 +253,8 @@ class LongitudinalMpc: cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, J_EGO_COST] constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, DANGER_ZONE_COST] elif self.mode == 'blended': - cost_weights = [0., 0.1, 0.2, 5.0, 0.0, 1.0] + a_change_cost = 40.0 if prev_accel_constraint else 0 + cost_weights = [0., 0.1, 0.2, 5.0, a_change_cost, 1.0] constraint_cost_weights = [LIMIT_COST, LIMIT_COST, LIMIT_COST, 50.0] else: raise NotImplementedError(f'Planner mode {self.mode} not recognized in planner cost set') From 45b16570cfca88cef9f9cb82e6376527de786188 Mon Sep 17 00:00:00 2001 From: Igor Biletskyy Date: Tue, 25 Oct 2022 22:43:57 -0700 Subject: [PATCH 0090/1179] bump panda (#26244) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 2db69bc941..bd8d2481dd 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2db69bc94120a3c10f39cdedc9d83315f9ba801e +Subproject commit bd8d2481dd071df62263e093b2e332a2a404dc87 From 2b7290a14261ca0a745f4cd537de7cc9d11ccb12 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Wed, 26 Oct 2022 00:20:30 -0700 Subject: [PATCH 0091/1179] Model trained with more long noise (#26241) * d8501d20-bb59-4193-aa82-82b2737dedd6/449 d37d320d-7d78-479a-9be2-d58c75284307/700 * Update model ref --- 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 21602ea70a..49a1c3a3b8 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:9c119aa811a929b3a442dbe8e462a9d88e8bfb9f5809a4e737687fb7380d7e05 -size 45922882 +oid sha256:a41d42f92913e6cc3909e505b1220b16d31f7cfca5f8a4e82109577b4151b645 +size 45922983 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index b5fd11fee8..5843a1e174 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -46cb9c522e942d8b25deac90ffdee89efff60ce9 +d2f1711fd58d4f2c25b81bd332270da60ff9636d From b3e0a8c4e05f0c657d63d4825d50d43877b72768 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 26 Oct 2022 14:26:41 -0400 Subject: [PATCH 0092/1179] Hyundai: Add FW for 2022 Tucson Hybrid (#26239) * Hyundai: Add FW for 2022 Tucson Hybrid * Duplicated FW * Add cornerRadar FW (in a non-HDA too?) * Update selfdrive/car/hyundai/values.py Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 29d0cb3dce..98cb72293f 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1379,6 +1379,7 @@ FW_VERSIONS = { CAR.TUCSON_HYBRID_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q', + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9220 14K', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', From 03ebc3bff57627843bde8b5ea758a54e8b96cb4e Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 26 Oct 2022 11:45:21 -0700 Subject: [PATCH 0093/1179] [torqued] Update offline values (#26243) * update offline vals * update refs --- selfdrive/car/torque_data/params.yaml | 6 +++--- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 160f605488..60b1662cee 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -35,7 +35,7 @@ HYUNDAI SANTA FE 2019: [3.0787027729757632, 2.6173437483495565, 0.12070193418239 HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963] HYUNDAI SANTA FE PlUG-IN HYBRID 2022: [1.6953050513611045, 1.5837614296206861, 0.12672855941458458] HYUNDAI SONATA 2019: [2.2200457811703953, 1.2967330275895228, 0.14039920986586393] -HYUNDAI SONATA 2020: [3.284505627881726, 2.1259108157250735, 0.08452048323586728] +HYUNDAI SONATA 2020: [2.9638737459977467, 2.1259108157250735, 0.07813665616927593] HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488717382] JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185] JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003] @@ -67,8 +67,8 @@ TOYOTA CAMRY 2021: [2.6922769557433055, 2.3476510120007434, 0.1450430192989234] TOYOTA CAMRY HYBRID 2018: [2.0974120828287774, 1.7996193116697359, 0.13823613467632756] TOYOTA CAMRY HYBRID 2021: [2.6426668350384457, 2.3901492458927986, 0.16103875108816076] TOYOTA COROLLA 2017: [3.117154369115421, 1.8438132575043773, 0.12289685869250652] -TOYOTA COROLLA HYBRID TSS2 2019: [2.3287672277252005, 1.8118712531729109, 0.2215868445753317] -TOYOTA COROLLA TSS2 2019: [2.4204464833010175, 1.9258612322678952, 0.20670411068012526] +TOYOTA COROLLA HYBRID TSS2 2019: [1.9079729107361805, 1.8118712531729109, 0.22251440891543514] +TOYOTA COROLLA TSS2 2019: [2.0742917676766712, 1.9258612322678952, 0.16888685704519352] TOYOTA HIGHLANDER 2017: [1.8696367437248915, 1.626293990451463, 0.17485372210240796] TOYOTA HIGHLANDER 2020: [2.022340166827233, 1.6183134804881791, 0.14592306380054457] TOYOTA HIGHLANDER HYBRID 2018: [1.9421825202382728, 1.6433903296845025, 0.16928956792275918] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 44eed18493..ba0f30e5c3 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -68457035e9223fcbd70bd40966d5a1d9fe4f1567 \ No newline at end of file +8f2919ba4d8509432e93ff0a44f951254c1ff3fe \ No newline at end of file From d549e1899dbc7f28e0f27db51d875b30caa12ab0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 27 Oct 2022 03:59:16 +0800 Subject: [PATCH 0094/1179] Cabana: use QLineEdit for double value (#26247) --- tools/cabana/signaledit.cc | 22 +++++++++++++--------- tools/cabana/signaledit.h | 5 ++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 3926cda01f..1bb5e9e533 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,6 +1,7 @@ #include "tools/cabana/signaledit.h" #include +#include #include #include #include @@ -36,13 +37,16 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : QWidget(parent) { sign->setCurrentIndex(sig.is_signed ? 0 : 1); form_layout->addRow(tr("sign"), sign); - factor = new QDoubleSpinBox(); - factor->setDecimals(3); - factor->setValue(sig.factor); + auto double_validator = new QDoubleValidator(this); + + factor = new QLineEdit(); + factor->setValidator(double_validator); + factor->setText(QString::number(sig.factor)); form_layout->addRow(tr("Factor"), factor); - offset = new QSpinBox(); - offset->setValue(sig.offset); + offset = new QLineEdit(); + offset->setValidator(double_validator); + offset->setText(QString::number(sig.offset)); form_layout->addRow(tr("Offset"), offset); // TODO: parse the following parameters in opendbc @@ -50,11 +54,11 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : QWidget(parent) { form_layout->addRow(tr("Unit"), unit); comment = new QLineEdit(); form_layout->addRow(tr("Comment"), comment); - min_val = new QDoubleSpinBox(); - factor->setDecimals(3); + min_val = new QLineEdit(); + min_val->setValidator(double_validator); form_layout->addRow(tr("Minimum value"), min_val); - max_val = new QDoubleSpinBox(); - factor->setDecimals(3); + max_val = new QLineEdit(); + max_val->setValidator(double_validator); form_layout->addRow(tr("Maximum value"), max_val); val_desc = new QLineEdit(); form_layout->addRow(tr("Value descriptions"), val_desc); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 472453d4b1..71719852f1 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -16,9 +16,8 @@ class SignalForm : public QWidget { public: SignalForm(const Signal &sig, QWidget *parent); - QLineEdit *name, *unit, *comment, *val_desc; - QSpinBox *size, *offset; - QDoubleSpinBox *factor, *min_val, *max_val; + QLineEdit *name, *unit, *comment, *val_desc, *offset, *factor, *min_val, *max_val; + QSpinBox *size; QComboBox *sign, *endianness; }; From 728d96924924dd8d4e899ccaba0ed6bcc4a23417 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 27 Oct 2022 03:59:37 +0800 Subject: [PATCH 0095/1179] Cabana: limit X-axis range from settings (#26213) * limit X-axis range from settings * continue * update range if events merged * update line series by range * cleanup removeChart * cleanup updateAxisy --- tools/cabana/canmessages.cc | 83 ++++-------- tools/cabana/canmessages.h | 33 ++--- tools/cabana/chartswidget.cc | 256 +++++++++++++++++++---------------- tools/cabana/chartswidget.h | 28 +++- tools/cabana/historylog.cc | 5 +- tools/cabana/historylog.h | 1 + tools/cabana/mainwin.cc | 1 + tools/cabana/settings.cc | 15 +- tools/cabana/settings.h | 2 + tools/cabana/videowidget.cc | 5 +- tools/cabana/videowidget.h | 2 +- 11 files changed, 217 insertions(+), 214 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 1b46bd9da7..3ffc29916f 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -28,7 +28,7 @@ bool CANMessages::loadRoute(const QString &route, const QString &data_dir, bool replay = new Replay(route, {"can", "roadEncodeIdx", "carParams"}, {}, nullptr, use_qcam ? REPLAY_FLAG_QCAMERA : 0, data_dir, this); replay->setSegmentCacheLimit(settings.cached_segment_limit); replay->installEventFilter(event_filter, this); - QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::segmentsMerged); + QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); if (replay->load()) { replay->start(); return true; @@ -63,41 +63,26 @@ QList CANMessages::findSignalValues(const QString &id, const Signal *si return ret; } -void CANMessages::process(QHash> *messages) { +void CANMessages::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { - auto &msgs = can_msgs[it.key()]; - const auto &new_msgs = it.value(); - if (new_msgs.size() == settings.can_msg_log_size || msgs.empty()) { - msgs = std::move(new_msgs); - } else { - msgs.insert(msgs.begin(), std::make_move_iterator(new_msgs.begin()), std::make_move_iterator(new_msgs.end())); - if (msgs.size() > settings.can_msg_log_size) { - msgs.resize(settings.can_msg_log_size); - } - } + can_msgs[it.key()] = it.value(); } delete messages; - - if (current_sec < begin_sec || current_sec > end_sec) { - // loop replay in selected range. - seekTo(begin_sec); - } else { - emit updated(); - } + emit updated(); } bool CANMessages::eventFilter(const Event *event) { + static std::unique_ptr> new_msgs; static double prev_update_ts = 0; - // drop packets when the GUI thread is calling seekTo. to make sure the current_sec is accurate. - if (!seeking && event->which == cereal::Event::Which::CAN) { - if (!received_msgs) { - received_msgs.reset(new QHash>); - received_msgs->reserve(1000); + + if (event->which == cereal::Event::Which::CAN) { + if (!new_msgs) { + new_msgs.reset(new QHash); + new_msgs->reserve(1000); } - current_sec = (event->mono_time - replay->routeStartTime()) / (double)1e9; - if (counters_begin_sec > current_sec) { - // clear counters + double current_sec = replay->currentSeconds(); + if (counters_begin_sec == 0) { counters.clear(); counters_begin_sec = current_sec; } @@ -105,8 +90,10 @@ bool CANMessages::eventFilter(const Event *event) { auto can_events = event->event.getCan(); for (const auto &c : can_events) { QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); - auto &list = (*received_msgs)[id]; - while (list.size() >= settings.can_msg_log_size) { + + std::lock_guard lk(lock); + auto &list = received_msgs[id]; + while (list.size() > settings.can_msg_log_size) { list.pop_back(); } CanData &data = list.emplace_front(); @@ -119,49 +106,27 @@ bool CANMessages::eventFilter(const Event *event) { if (double delta = (current_sec - counters_begin_sec); delta > 0) { data.freq = count / delta; } + (*new_msgs)[id] = data; } double ts = millis_since_boot(); if ((ts - prev_update_ts) > (1000.0 / settings.fps)) { prev_update_ts = ts; // use pointer to avoid data copy in queued connection. - emit received(received_msgs.release()); + emit received(new_msgs.release()); } } return true; } +const std::deque CANMessages::messages(const QString &id) { + std::lock_guard lk(lock); + return received_msgs[id]; +} + void CANMessages::seekTo(double ts) { - seeking = true; replay->seekTo(ts, false); - seeking = false; -} - -void CANMessages::setRange(double min, double max) { - if (begin_sec != min || end_sec != max) { - begin_sec = min; - end_sec = max; - is_zoomed = begin_sec != event_begin_sec || end_sec != event_end_sec; - emit rangeChanged(min, max); - } -} - -void CANMessages::segmentsMerged() { - auto events = replay->events(); - if (!events || events->empty()) return; - - auto it = std::find_if(events->begin(), events->end(), [=](const Event *e) { return e->which == cereal::Event::Which::CAN; }); - event_begin_sec = it == events->end() ? 0 : ((*it)->mono_time - replay->routeStartTime()) / (double)1e9; - event_end_sec = double(events->back()->mono_time - replay->routeStartTime()) / 1e9; - if (!is_zoomed) { - begin_sec = event_begin_sec; - end_sec = event_end_sec; - } - emit eventsMerged(); -} - -void CANMessages::resetRange() { - setRange(event_begin_sec, event_end_sec); + counters_begin_sec = 0; } void CANMessages::settingChanged() { diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index d1bb1b73b6..5fbccdbe12 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -29,20 +29,16 @@ public: ~CANMessages(); bool loadRoute(const QString &route, const QString &data_dir, bool use_qcam); void seekTo(double ts); - void resetRange(); - void setRange(double min, double max); QList findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); bool eventFilter(const Event *event); - inline std::pair range() const { return {begin_sec, end_sec}; } inline QString route() const { return routeName; } inline QString carFingerprint() const { return replay->carFingerprint().c_str(); } inline double totalSeconds() const { return replay->totalSeconds(); } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } - inline double currentSec() const { return current_sec; } - inline bool isZoomed() const { return is_zoomed; } - inline const std::deque &messages(const QString &id) { return can_msgs[id]; } - inline const CanData &lastMessage(const QString &id) { return can_msgs[id].front(); } + inline double currentSec() const { return replay->currentSeconds(); } + const std::deque messages(const QString &id); + inline const CanData &lastMessage(const QString &id) { return can_msgs[id]; } inline const std::vector *events() const { return replay->events(); } inline void setSpeed(float speed) { replay->setSpeed(speed); } @@ -52,32 +48,23 @@ public: signals: void eventsMerged(); - void rangeChanged(double min, double max); void updated(); - void received(QHash> *); + void received(QHash *); public: - QMap> can_msgs; - std::unique_ptr>> received_msgs = nullptr; + QMap can_msgs; protected: - void process(QHash> *); - void segmentsMerged(); + void process(QHash *); void settingChanged(); - std::atomic current_sec = 0.; - std::atomic seeking = false; - - double begin_sec = 0; - double end_sec = 0; - double event_begin_sec = 0; - double event_end_sec = 0; - bool is_zoomed = false; QString routeName; Replay *replay = nullptr; - double counters_begin_sec = std::numeric_limits::max(); + std::mutex lock; + std::atomic counters_begin_sec = 0; QHash counters; + QHash> received_msgs; }; inline QString toHex(const QByteArray &dat) { diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index f0bef36f4a..ea44a4033c 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,6 +1,7 @@ #include "tools/cabana/chartswidget.h" #include +#include #include #include #include @@ -57,47 +58,85 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { removeAll(nullptr); }); QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartsWidget::removeAll); - QObject::connect(dbc(), &DBCManager::signalUpdated, [this](const Signal *sig) { - for (auto chart : charts) { - if (chart->signal == sig) { - chart->chart_view->updateSeries(); - } + QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartsWidget::signalUpdated); + QObject::connect(dbc(), &DBCManager::msgUpdated, [this](const QString &msg_id) { + for (auto c : charts) { + if (c->id == msg_id) c->updateTitle(); } }); - 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(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); + QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState); QObject::connect(remove_all_btn, &QPushButton::clicked, [this]() { removeAll(); }); + QObject::connect(reset_zoom_btn, &QPushButton::clicked, this, &ChartsWidget::zoomReset); QObject::connect(dock_btn, &QPushButton::clicked, [this]() { emit dock(!docking); docking = !docking; updateTitleBar(); }); - QObject::connect(&settings, &Settings::changed, [this]() { - for (auto chart : charts) { - chart->setHeight(settings.chart_height); +} + +void ChartsWidget::eventsMerged() { + if (auto events = can->events(); events && !events->empty()) { + auto it = std::find_if(events->begin(), events->end(), [=](const Event *e) { return e->which == cereal::Event::Which::CAN; }); + event_range.first = it == events->end() ? 0 : (*it)->mono_time / (double)1e9 - can->routeStartTime(); + event_range.second = it == events->end() ? 0 : events->back()->mono_time / (double)1e9 - can->routeStartTime(); + if (display_range.first == 0 && event_range.second == 0) { + display_range.first = event_range.first; + display_range.second = std::min(event_range.first + settings.max_chart_x_range, event_range.second); } - }); + } +} + +void ChartsWidget::zoomIn(double min, double max) { + zoomed_range = {min, max}; + is_zoomed = zoomed_range != display_range; + updateTitleBar(); + emit rangeChanged(min, max, is_zoomed); + updateState(); +} + +void ChartsWidget::zoomReset() { + zoomIn(display_range.first, display_range.second); +} + +void ChartsWidget::updateState() { + if (charts.isEmpty()) return; + + const double current_sec = can->currentSec(); + if (is_zoomed) { + if (current_sec < zoomed_range.first || current_sec >= zoomed_range.second) { + can->seekTo(zoomed_range.first); + } + } else { + auto prev_range = display_range; + if (current_sec < display_range.first || current_sec >= (display_range.second - 5)) { + // line marker reached the end, or seeked to a timestamp out of range. + display_range.first = current_sec - 5; + } + display_range.first = std::max(display_range.first, event_range.first); + display_range.second = std::min(display_range.first + settings.max_chart_x_range, event_range.second); + if (prev_range != display_range) { + for (auto c : charts) + c->chart_view->updateSeries(display_range); + } + } + + const auto &range = is_zoomed ? zoomed_range : display_range; + for (auto c : charts) { + c->chart_view->setRange(range.first, range.second); + c->chart_view->updateLineMarker(current_sec); + } } void ChartsWidget::updateTitleBar() { 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(is_zoomed); + reset_zoom_btn->setEnabled(is_zoomed); + if (is_zoomed) { + range_label->setText(tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2)); } - title_label->setText(tr("Charts (%1)").arg(charts.size())); dock_btn->setText(docking ? "⬈" : "⬋"); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); @@ -107,23 +146,19 @@ void ChartsWidget::addChart(const QString &id, const Signal *sig) { auto it = std::find_if(charts.begin(), charts.end(), [=](auto c) { return c->id == id && c->signal == sig; }); if (it == charts.end()) { auto chart = new ChartWidget(id, sig, this); - QObject::connect(chart, &ChartWidget::remove, this, &ChartsWidget::removeChart); + chart->chart_view->updateSeries(display_range); + QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(chart); });; + QObject::connect(chart->chart_view, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); + QObject::connect(chart->chart_view, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); charts_layout->insertWidget(0, chart); charts.push_back(chart); } updateTitleBar(); } -void ChartsWidget::removeChart(const QString &msg_id, const Signal *sig) { - QMutableListIterator it(charts); - while (it.hasNext()) { - auto c = it.next(); - if (c->id == msg_id && c->signal == sig) { - c->deleteLater(); - it.remove(); - break; - } - } +void ChartsWidget::removeChart(ChartWidget *chart) { + charts.removeOne(chart); + chart->deleteLater(); updateTitleBar(); } @@ -139,6 +174,17 @@ void ChartsWidget::removeAll(const Signal *sig) { updateTitleBar(); } +void ChartsWidget::signalUpdated(const Signal *sig) { + for (auto c : charts) { + if (c->signal == sig) { + c->updateTitle(); + c->chart_view->updateSeries(display_range); + c->chart_view->setRange(display_range.first, display_range.second, true); + } + } +} + + bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { if (obj != this && event->type() == QEvent::Close) { emit dock_btn->clicked(); @@ -156,17 +202,19 @@ ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) QWidget *header = new QWidget(this); header->setStyleSheet("background-color:white"); - QHBoxLayout *header_layout = new QHBoxLayout(header); + QGridLayout *header_layout = new QGridLayout(header); header_layout->setContentsMargins(11, 11, 11, 0); - title = new QLabel(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); - header_layout->addWidget(title); - header_layout->addStretch(); + msg_name_label = new QLabel(this); + msg_name_label->setTextFormat(Qt::RichText); + header_layout->addWidget(msg_name_label, 0, 0, Qt::AlignLeft); + sig_name_label = new QLabel(this); + sig_name_label->setStyleSheet("font-weight:bold"); + header_layout->addWidget(sig_name_label, 0, 1, Qt::AlignCenter); //, 0, Qt::AlignCenter); QPushButton *remove_btn = new QPushButton("✖", this); - remove_btn->setFixedSize(30, 30); + remove_btn->setFixedSize(20, 20); remove_btn->setToolTip(tr("Remove chart")); - QObject::connect(remove_btn, &QPushButton::clicked, [=]() { emit remove(id, sig); }); - header_layout->addWidget(remove_btn); + header_layout->addWidget(remove_btn, 0, 2, Qt::AlignRight); main_layout->addWidget(header); chart_view = new ChartView(id, sig, this); @@ -175,10 +223,15 @@ ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) main_layout->addStretch(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + updateTitle(); + + QObject::connect(remove_btn, &QPushButton::clicked, [=]() { emit remove(id, sig); }); + QObject::connect(&settings, &Settings::changed, [this]() { chart_view->setFixedHeight(settings.chart_height); }); } void ChartWidget::updateTitle() { - title->setText(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); + msg_name_label->setText(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); + sig_name_label->setText(signal->name.c_str()); } // ChartView @@ -186,15 +239,10 @@ void ChartWidget::updateTitle() { 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.c_str()); chart->addSeries(series); chart->createDefaultAxes(); chart->legend()->hide(); - QFont font; - font.setBold(true); - chart->setTitleFont(font); chart->setMargins({0, 0, 0, 0}); chart->layout()->setContentsMargins(0, 0, 0, 0); @@ -220,16 +268,18 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) 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::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())) { + axis_x->setRange(min, max); + updateAxisY(); + } } void ChartView::adjustChartMargins() { @@ -241,18 +291,17 @@ void ChartView::adjustChartMargins() { } } -void ChartWidget::setHeight(int height) { - chart_view->setFixedHeight(height); -} - -void ChartView::updateState() { +void ChartView::updateLineMarker(double current_sec) { 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()); - line_marker->setLine(x, 0, x, height()); + 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, 0, x, height()); + chart()->update(); + } } -void ChartView::updateSeries() { - chart()->setTitle(signal->name.c_str()); +void ChartView::updateSeries(const std::pair &range) { auto events = can->events(); if (!events) return; @@ -261,15 +310,18 @@ void ChartView::updateSeries() { uint32_t address = l[1].toUInt(nullptr, 16); vals.clear(); - vals.reserve(3 * 60 * 100); - uint64_t route_start_time = can->routeStartTime(); - for (auto &evt : *events) { - if (evt->which == cereal::Event::Which::CAN) { - for (auto c : evt->event.getCan()) { + vals.reserve((range.second - range.first) * 100); // [n]minutes * 100hz + 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 (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 = (evt->mono_time / (double)1e9) - route_start_time; // seconds + double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds vals.push_back({ts, value}); } } @@ -277,40 +329,20 @@ void ChartView::updateSeries() { } QLineSeries *series = (QLineSeries *)chart()->series()[0]; series->replace(vals); - series->setPointLabelsColor(Qt::black); - auto [begin, end] = can->range(); - chart()->axisX()->setRange(begin, end); - updateAxisY(); -} - -void ChartView::rangeChanged(qreal min, qreal max) { - auto axis_x = dynamic_cast(chart()->axisX()); - if (axis_x->min() != min || axis_x->max() != max) { - axis_x->setRange(min, max); - } - updateAxisY(); } // auto zoom on yaxis void ChartView::updateAxisY() { const auto axis_x = dynamic_cast(chart()->axisX()); const auto axis_y = dynamic_cast(chart()->axisY()); - // vals is a sorted list 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 (min->y() == max->y()) { - if (max->y() < 0) { - axis_y->setRange(max->y(), 0); - } else { - axis_y->setRange(0, max->y() == 0 ? 1 : max->y()); - } - } else { - axis_y->setRange(min->y(), max->y()); - } + (min->y() == max->y()) ? axis_y->setRange(min->y() - 1, max->y() + 1) + : axis_y->setRange(min->y(), max->y()); } void ChartView::enterEvent(QEvent *event) { @@ -328,39 +360,35 @@ void ChartView::leaveEvent(QEvent *event) { void ChartView::mouseReleaseEvent(QMouseEvent *event) { auto rubber = findChild(); if (event->button() == Qt::LeftButton && rubber && rubber->isVisible()) { - auto [begin, end] = can->range(); + 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) { - double seek_to = begin + ((event->pos().x() - chart()->plotArea().x()) / chart()->plotArea().width()) * (end - begin); - can->seekTo(seek_to); - } else if (((double)rubber->width() / chart()->plotArea().width()) * (end - begin) < 0.5) { - // don't zoom if selected range is less than 0.5s - rubber->hide(); - event->accept(); - return; + // no rubber dragged, seek to mouse position + can->seekTo(min); + } else if ((max - min) >= 0.5) { + // zoom in if selected range is greater than 0.5s + emit zoomIn(min, max); } } else if (event->button() == Qt::RightButton) { - // reset zoom - if (can->isZoomed()) { - can->resetRange(); - event->accept(); - return; - } + emit zoomReset(); } - QChartView::mouseReleaseEvent(event); - line_marker->setVisible(true); + event->accept(); } void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); - bool show = !(rubber && rubber->isVisible()); - - if (show) { + bool dragging = rubber && rubber->isVisible(); + if (!dragging) { const auto plot_area = chart()->plotArea(); float x = std::clamp((float)ev->pos().x(), (float)plot_area.left(), (float)plot_area.right()); track_line->setLine(x, plot_area.top(), x, plot_area.bottom()); - auto [begin, end] = can->range(); - double sec = begin + ((x - plot_area.x()) / plot_area.width()) * (end - begin); + auto axis_x = dynamic_cast(chart()->axisX()); + double sec = axis_x->min() + ((x - plot_area.x()) / plot_area.width()) * (axis_x->max() - axis_x->min()); auto value = std::lower_bound(vals.begin(), vals.end(), sec, [](auto &p, double x) { return p.x() < x; }); value_text->setPos(x + 6, plot_area.bottom() - 25); if (value != vals.end()) { @@ -369,9 +397,5 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { value_text->setText("(--, --)"); } } - - value_text->setVisible(show); - track_line->setVisible(show); - line_marker->setVisible(show); QChartView::mouseMoveEvent(ev); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 5adbdfcd04..a7c6f4bbd3 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -20,7 +20,13 @@ class ChartView : public QChartView { public: ChartView(const QString &id, const Signal *sig, QWidget *parent = nullptr); - void updateSeries(); + void updateSeries(const std::pair &range); + void setRange(double min, double max, bool force_update = false); + void updateLineMarker(double current_sec); + +signals: + void zoomIn(double min, double max); + void zoomReset(); private: void mouseReleaseEvent(QMouseEvent *event) override; @@ -29,9 +35,7 @@ private: void leaveEvent(QEvent *event) override; void adjustChartMargins(); - void rangeChanged(qreal min, qreal max); void updateAxisY(); - void updateState(); QGraphicsLineItem *track_line; QGraphicsSimpleTextItem *value_text; @@ -47,7 +51,6 @@ Q_OBJECT public: ChartWidget(const QString &id, const Signal *sig, QWidget *parent); void updateTitle(); - void setHeight(int height); signals: void remove(const QString &msg_id, const Signal *sig); @@ -55,7 +58,8 @@ signals: public: QString id; const Signal *signal; - QLabel *title; + QLabel *msg_name_label; + QLabel *sig_name_label; ChartView *chart_view = nullptr; }; @@ -65,16 +69,21 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); void addChart(const QString &id, const Signal *sig); - void removeChart(const QString &id, const Signal *sig); + void removeChart(ChartWidget *chart); signals: void dock(bool floating); + void rangeChanged(double min, double max, bool is_zommed); private: + void eventsMerged(); void updateState(); + void zoomIn(double min, double max); + void zoomReset(); + void signalUpdated(const Signal *sig); void updateTitleBar(); void removeAll(const Signal *sig = nullptr); - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) override; QWidget *title_bar; QLabel *title_label; @@ -85,4 +94,9 @@ private: QPushButton *remove_all_btn; QVBoxLayout *charts_layout; QList charts; + + bool is_zoomed = false; + std::pair event_range; + std::pair display_range; + std::pair zoomed_range; }; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index a20845f15f..8136d0577c 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -7,7 +7,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); if (role == Qt::DisplayRole) { - const auto &m = can->messages(msg_id)[index.row()]; + const auto &m = messages[index.row()]; if (index.column() == 0) { return QString::number(m.ts, 'f', 2); } @@ -49,7 +49,8 @@ void HistoryLogModel::updateState() { if (msg_id.isEmpty()) return; int prev_row_count = row_count; - row_count = can->messages(msg_id).size(); + messages = can->messages(msg_id); + row_count = messages.size(); int delta = row_count - prev_row_count; if (delta > 0) { beginInsertRows({}, prev_row_count, row_count - 1); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index bc6d1f9376..d39bcf9f1d 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -22,6 +22,7 @@ private: int row_count = 0; int column_count = 2; const Msg *dbc_msg = nullptr; + std::deque messages; }; class HistoryLog : public QWidget { diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 65e7bb1af8..30c7e5e0a2 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -83,6 +83,7 @@ MainWindow::MainWindow() : QWidget() { QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); QObject::connect(detail_widget, &DetailWidget::showChart, charts_widget, &ChartsWidget::addChart); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); + QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); QObject::connect(settings_btn, &QPushButton::clicked, this, &MainWindow::setOption); QObject::connect(can, &CANMessages::eventsMerged, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 0b36f25fbc..6e9d7f17cc 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -17,6 +17,7 @@ void Settings::save() { s.setValue("log_size", can_msg_log_size); s.setValue("cached_segment", cached_segment_limit); s.setValue("chart_height", chart_height); + s.setValue("max_chart_x_range", max_chart_x_range); emit changed(); } @@ -26,6 +27,7 @@ void Settings::load() { can_msg_log_size = s.value("log_size", 100).toInt(); cached_segment_limit = s.value("cached_segment", 3).toInt(); chart_height = s.value("chart_height", 200).toInt(); + max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); } // SettingsDlg @@ -45,19 +47,25 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { log_size->setRange(50, 500); log_size->setSingleStep(10); log_size->setValue(settings.can_msg_log_size); - form_layout->addRow(tr("Log size"), log_size); + form_layout->addRow(tr("Signal history log size"), log_size); cached_segment = new QSpinBox(this); cached_segment->setRange(3, 60); cached_segment->setSingleStep(1); cached_segment->setValue(settings.cached_segment_limit); - form_layout->addRow(tr("Cached segments limit"), cached_segment); + form_layout->addRow(tr("Cached segments limit(minute)"), cached_segment); + + max_chart_x_range = new QSpinBox(this); + max_chart_x_range->setRange(1, 60); + max_chart_x_range->setSingleStep(1); + max_chart_x_range->setValue(settings.max_chart_x_range / 60); + form_layout->addRow(tr("Chart's max X-axis range(minute)"), max_chart_x_range); 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); + form_layout->addRow(tr("Chart's height"), chart_height); main_layout->addLayout(form_layout); @@ -74,6 +82,7 @@ void SettingsDlg::save() { settings.can_msg_log_size = log_size->value(); settings.cached_segment_limit = cached_segment->value(); settings.chart_height = chart_height->value(); + settings.max_chart_x_range = max_chart_x_range->value() * 60; settings.save(); accept(); } diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 22542fc04c..fa97c49140 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -15,6 +15,7 @@ public: int can_msg_log_size = 100; int cached_segment_limit = 3; int chart_height = 200; + int max_chart_x_range = 3 * 60; // 3 minutes signals: void changed(); @@ -30,6 +31,7 @@ public: QSpinBox *log_size ; QSpinBox *cached_segment; QSpinBox *chart_height; + QSpinBox *max_chart_x_range; }; extern Settings settings; diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 78965e3e8c..7180d5ac0f 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -57,7 +57,6 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - QObject::connect(can, &CANMessages::rangeChanged, this, &VideoWidget::rangeChanged); 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)); }); @@ -70,8 +69,8 @@ void VideoWidget::pause(bool pause) { can->pause(pause); } -void VideoWidget::rangeChanged(double min, double max) { - if (!can->isZoomed()) { +void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { + if (!is_zoomed) { min = 0; max = can->totalSeconds(); } diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index d6d036c461..51dae4c76f 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -26,9 +26,9 @@ class VideoWidget : public QWidget { public: VideoWidget(QWidget *parnet = nullptr); + void rangeChanged(double min, double max, bool is_zommed); protected: - void rangeChanged(double min, double max); void updateState(); void pause(bool pause); From 16b7d726b3ff404e4c8df8a3045ff75bbaf63719 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 26 Oct 2022 13:33:12 -0700 Subject: [PATCH 0096/1179] quectel no sim GPS support (#26227) * add no sim gps support * address comments * remove xtra assistance enabling Co-authored-by: Kurt Nistelberger --- selfdrive/sensord/rawgps/rawgpsd.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/selfdrive/sensord/rawgps/rawgpsd.py b/selfdrive/sensord/rawgps/rawgpsd.py index 5a6827a759..fa23a161c4 100755 --- a/selfdrive/sensord/rawgps/rawgpsd.py +++ b/selfdrive/sensord/rawgps/rawgpsd.py @@ -87,16 +87,24 @@ def try_setup_logs(diag, log_types): else: raise Exception(f"setup logs failed, {log_types=}") -def mmcli(cmd: str) -> None: +def at_cmd(cmd: str) -> None: for _ in range(5): try: - subprocess.check_call(f"mmcli -m any --timeout 30 {cmd}", shell=True) + subprocess.check_call(f"mmcli -m any --timeout 30 --command='{cmd}'", shell=True) break except subprocess.CalledProcessError: cloudlog.exception("rawgps.mmcli_command_failed") else: raise Exception(f"failed to execute mmcli command {cmd=}") + +def gps_enabled() -> bool: + try: + p = subprocess.check_output("mmcli -m any --command=\"AT+QGPS?\"", shell=True) + return b"QGPS: 1" in p + except subprocess.CalledProcessError as exc: + raise Exception("failed to execute QGPS mmcli command") from exc + def setup_quectel(diag: ModemDiag): # enable OEMDRE in the NV # TODO: it has to reboot for this to take effect @@ -108,11 +116,16 @@ def setup_quectel(diag: ModemDiag): setup_logs(diag, LOG_TYPES) + if gps_enabled(): + at_cmd("AT+QGPSEND") + # disable DPO power savings for more accuracy - mmcli("--command='AT+QGPSCFG=\"dpoenable\",0'") + at_cmd("AT+QGPSCFG=\"dpoenable\",0") # don't automatically turn on GNSS on powerup - mmcli("--command='AT+QGPSCFG=\"autogps\",0'") - mmcli("--location-enable-gps-raw --location-enable-gps-nmea") + at_cmd("AT+QGPSCFG=\"autogps\",0") + + at_cmd("AT+QGPSCFG=\"outport\",\"usbnmea\"") + at_cmd("AT+QGPS=1") # enable OEMDRE mode DIAG_SUBSYS_CMD_F = 75 @@ -134,7 +147,9 @@ def setup_quectel(diag: ModemDiag): )) def teardown_quectel(diag): - mmcli("--location-disable-gps-raw --location-disable-gps-nmea") + at_cmd("AT+QGPSCFG=\"outport\",\"none\"") + if gps_enabled(): + at_cmd("AT+QGPSEND") try_setup_logs(diag, []) @@ -156,7 +171,7 @@ def main() -> NoReturn: # wait for ModemManager to come up cloudlog.warning("waiting for modem to come up") while True: - ret = subprocess.call("mmcli -m any --timeout 10 --location-status", stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True) + ret = subprocess.call("mmcli -m any --timeout 10 --command=\"AT+QGPS?\"", stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True) if ret == 0: break time.sleep(0.1) From 9c9281458510f4e34ee5434138086075cf0c8838 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 26 Oct 2022 13:37:11 -0700 Subject: [PATCH 0097/1179] Improve GPS tests, add qcom tests (#26060) * first ignore * init gps test * make LimeGPS git clone * gps test v1 * add static signal gen script * remove LD_PRELOAD by using rpath, update values after testing * cleanUp * update fuzzy tests * finalize qcom gps tests * add downloader * finalize unit tests * inc limeGPS startup time * loosen init time * add ublox warmstart test * improve location tests Co-authored-by: Kurt Nistelberger --- tools/gpstest/fuzzy_testing.py | 19 +++-- tools/gpstest/remote_checker.py | 18 ++-- tools/gpstest/run_static_gps_signal.py | 83 ------------------- tools/gpstest/run_unittest.sh | 16 ++++ tools/gpstest/simulate_gps_signal.py | 102 +++++++++++++++++++++++ tools/gpstest/test_gps.py | 101 +++++++++++++++++------ tools/gpstest/test_gps_qcom.py | 109 +++++++++++++++++++++++++ 7 files changed, 327 insertions(+), 121 deletions(-) delete mode 100755 tools/gpstest/run_static_gps_signal.py create mode 100755 tools/gpstest/run_unittest.sh create mode 100755 tools/gpstest/simulate_gps_signal.py create mode 100644 tools/gpstest/test_gps_qcom.py diff --git a/tools/gpstest/fuzzy_testing.py b/tools/gpstest/fuzzy_testing.py index 216e7d0dde..df6691c558 100755 --- a/tools/gpstest/fuzzy_testing.py +++ b/tools/gpstest/fuzzy_testing.py @@ -66,7 +66,7 @@ def get_continuous_coords(lat, lon) -> Tuple[int, int]: return round(lat, 5), round(lon, 5) rc_p: Any = None -def exec_remote_checker(lat, lon, duration): +def exec_remote_checker(lat, lon, duration, ip_addr): global rc_p # TODO: good enough for testing remote_cmd = "export PYTHONPATH=/data/pythonpath:/data/pythonpath/pyextra && " @@ -74,8 +74,8 @@ def exec_remote_checker(lat, lon, duration): remote_cmd += f"timeout {duration} /usr/local/pyenv/shims/python tools/gpstest/remote_checker.py " remote_cmd += f"{lat} {lon}" - ssh_cmd = ['ssh', '-i', '/home/batman/openpilot/xx/phone/key/id_rsa', - 'comma@192.168.60.130'] + ssh_cmd = ["ssh", "-i", "/home/batman/openpilot/xx/phone/key/id_rsa", + f"comma@{ip_addr}"] ssh_cmd += [remote_cmd] rc_p = sp.Popen(ssh_cmd, stdout=sp.PIPE) @@ -84,8 +84,9 @@ def exec_remote_checker(lat, lon, duration): print(f"Checker Result: {rc_output.strip().decode('utf-8')}") -def run_remote_checker(spoof_proc, lat, lon, duration) -> bool: - checker_thread = threading.Thread(target=exec_remote_checker, args=(lat, lon, duration)) +def run_remote_checker(spoof_proc, lat, lon, duration, ip_addr) -> bool: + checker_thread = threading.Thread(target=exec_remote_checker, + args=(lat, lon, duration, ip_addr)) checker_thread.start() tcnt = 0 @@ -107,8 +108,12 @@ def run_remote_checker(spoof_proc, lat, lon, duration) -> bool: def main(): + if len(sys.argv) < 2: + print(f"usage: {sys.argv[0]} [-c]") + ip_addr = sys.argv[1] + continuous_mode = False - if len(sys.argv) == 2 and sys.argv[1] == '-c': + if len(sys.argv) == 3 and sys.argv[2] == '-c': print("Continuous Mode!") continuous_mode = True @@ -123,7 +128,7 @@ def main(): start_time = time.monotonic() # remote checker runs blocking - if not run_remote_checker(spoof_proc, lat, lon, duration): + if not run_remote_checker(spoof_proc, lat, lon, duration, ip_addr): # location could not be matched by ublox module pass diff --git a/tools/gpstest/remote_checker.py b/tools/gpstest/remote_checker.py index 84f6c0c3d9..a649a105c3 100644 --- a/tools/gpstest/remote_checker.py +++ b/tools/gpstest/remote_checker.py @@ -3,6 +3,7 @@ import sys import time from typing import List +from common.params import Params import cereal.messaging as messaging from selfdrive.manager.process_config import managed_processes @@ -12,30 +13,35 @@ procs: List[str] = []#"ubloxd", "pigeond"] def main(): - if len(sys.argv) < 3: + if len(sys.argv) != 4: print("args: ") return - sol_lat = float(sys.argv[1]) - sol_lon = float(sys.argv[2]) + quectel_mod = Params().get_bool("UbloxAvailable") + sol_lat = float(sys.argv[2]) + sol_lon = float(sys.argv[3]) for p in procs: managed_processes[p].start() time.sleep(0.5) # give time to startup - gps_sock = messaging.sub_sock('gpsLocationExternal', timeout=0.1) + socket = 'gpsLocation' if quectel_mod else 'gpsLocationExternal' + gps_sock = messaging.sub_sock(socket, timeout=0.1) # analyze until the location changed while True: events = messaging.drain_sock(gps_sock) for e in events: - lat = e.gpsLocationExternal.latitude - lon = e.gpsLocationExternal.longitude + loc = e.gpsLocation if quectel_mod else e.gpsLocationExternal + lat = loc.latitude + lon = loc.longitude if abs(lat - sol_lat) < DELTA and abs(lon - sol_lon) < DELTA: print("MATCH") return + time.sleep(0.1) + for p in procs: if not managed_processes[p].proc.is_alive(): print(f"ERROR: '{p}' died") diff --git a/tools/gpstest/run_static_gps_signal.py b/tools/gpstest/run_static_gps_signal.py deleted file mode 100755 index 3787038f13..0000000000 --- a/tools/gpstest/run_static_gps_signal.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import random -import datetime as dt -import subprocess as sp -from typing import Tuple - -from laika.downloader import download_nav -from laika.gps_time import GPSTime -from laika.helpers import ConstellationId - -cache_dir = '/tmp/gpstest/' - - -def download_rinex(): - # TODO: check if there is a better way to get the full brdc file for LimeGPS - gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) - utc_time = dt.datetime.utcnow() - dt.timedelta(1) - gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) - return download_nav(gps_time, cache_dir, ConstellationId.GPS) - - -def get_random_coords(lat, lon) -> Tuple[int, int]: - # jump around the world - # max values, lat: -90 to 90, lon: -180 to 180 - - lat_add = random.random()*20 + 10 - lon_add = random.random()*20 + 20 - - lat = ((lat + lat_add + 90) % 180) - 90 - lon = ((lon + lon_add + 180) % 360) - 180 - return round(lat, 5), round(lon, 5) - - -def check_availability() -> bool: - cmd = ["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"] - output = sp.check_output(cmd) - - if output.strip() == b"": - return False - - print(f"Device: {output.strip().decode('utf-8')}") - return True - - -def main(): - if not os.path.exists('LimeGPS'): - print("LimeGPS not found run 'setup.sh' first") - return - - if not os.path.exists('LimeSuite'): - print("LimeSuite not found run 'setup.sh' first") - return - - if not check_availability(): - print("No limeSDR device found!") - return - - rinex_file = download_rinex() - lat, lon = get_random_coords(47.2020, 15.7403) - - if len(sys.argv) == 3: - lat = float(sys.argv[1]) - lon = float(sys.argv[2]) - - try: - print(f"starting LimeGPS, Location: {lat},{lon}") - cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},100"] - sp.check_output(cmd, stderr=sp.PIPE) - except KeyboardInterrupt: - print("stopping LimeGPS") - except Exception as e: - out_stderr = e.stderr.decode('utf-8')# pylint:disable=no-member - if "Device is busy." in out_stderr: - print("GPS simulation is already running, Device is busy!") - return - - print(f"LimeGPS crashed: {str(e)}") - print(f"stderr:\n{e.stderr.decode('utf-8')}")# pylint:disable=no-member - -if __name__ == "__main__": - main() diff --git a/tools/gpstest/run_unittest.sh b/tools/gpstest/run_unittest.sh new file mode 100755 index 0000000000..d284fa74e5 --- /dev/null +++ b/tools/gpstest/run_unittest.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# NOTE: can only run inside limeGPS test box! + +# run limeGPS with random static location +timeout 300 ./simulate_gps_signal.py & +gps_PID=$? + +echo "starting limeGPS..." +sleep 10 + +# run unit tests (skipped when module not present) +python -m unittest test_gps.py +python -m unittest test_gps_qcom.py + +kill $gps_PID diff --git a/tools/gpstest/simulate_gps_signal.py b/tools/gpstest/simulate_gps_signal.py new file mode 100755 index 0000000000..f1e5ad2028 --- /dev/null +++ b/tools/gpstest/simulate_gps_signal.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +import os +import random +import argparse +import datetime as dt +import subprocess as sp +from typing import Tuple + +from laika.downloader import download_nav +from laika.gps_time import GPSTime +from laika.helpers import ConstellationId + +cache_dir = '/tmp/gpstest/' + + +def download_rinex(): + # TODO: check if there is a better way to get the full brdc file for LimeGPS + gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) + utc_time = dt.datetime.utcnow() - dt.timedelta(1) + gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) + return download_nav(gps_time, cache_dir, ConstellationId.GPS) + +def get_coords(lat, lon, s1, s2, o1=0, o2=0) -> Tuple[int, int]: + lat_add = random.random()*s1 + o1 + lon_add = random.random()*s2 + o2 + + lat = ((lat + lat_add + 90) % 180) - 90 + lon = ((lon + lon_add + 180) % 360) - 180 + return round(lat, 5), round(lon, 5) + +def get_continuous_coords(lat, lon) -> Tuple[int, int]: + # continuously move around the world + return get_coords(lat, lon, 0.01, 0.01) + +def get_random_coords(lat, lon) -> Tuple[int, int]: + # jump around the world + return get_coords(lat, lon, 20, 20, 10, 20) + +def check_availability() -> bool: + cmd = ["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"] + output = sp.check_output(cmd) + + if output.strip() == b"": + return False + + print(f"Device: {output.strip().decode('utf-8')}") + return True + +def main(lat, lon, jump_sim, contin_sim): + if not os.path.exists('LimeGPS'): + print("LimeGPS not found run 'setup.sh' first") + return + + if not os.path.exists('LimeSuite'): + print("LimeSuite not found run 'setup.sh' first") + return + + if not check_availability(): + print("No limeSDR device found!") + return + + rinex_file = download_rinex() + + if lat == 0 and lon == 0: + lat, lon = get_random_coords(47.2020, 15.7403) + + timeout = None + if jump_sim: + timeout = 30 + + while True: + try: + print(f"starting LimeGPS, Location: {lat},{lon}") + cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},100"] + sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) + except KeyboardInterrupt: + print("stopping LimeGPS") + return + except sp.TimeoutExpired: + print("LimeGPS timeout reached!") + except Exception as e: + out_stderr = e.stderr.decode('utf-8')# pylint:disable=no-member + if "Device is busy." in out_stderr: + print("GPS simulation is already running, Device is busy!") + return + + print(f"LimeGPS crashed: {str(e)}") + print(f"stderr:\n{e.stderr.decode('utf-8')}")# pylint:disable=no-member + + if contin_sim: + lat, lon = get_continuous_coords(lat, lon) + else: + lat, lon = get_random_coords(lat, lon) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Simulate static [or random jumping] GPS signal.") + parser.add_argument("lat", type=float, nargs='?', default=0) + parser.add_argument("lon", type=float, nargs='?', default=0) + parser.add_argument("--jump", action="store_true", help="signal that jumps around the world") + parser.add_argument("--contin", action="store_true", help="continuously/slowly moving around the world") + args = parser.parse_args() + main(args.lat, args.lon, args.jump, args.contin) diff --git a/tools/gpstest/test_gps.py b/tools/gpstest/test_gps.py index f5e19372f7..b5d0cdd254 100644 --- a/tools/gpstest/test_gps.py +++ b/tools/gpstest/test_gps.py @@ -2,8 +2,8 @@ import time import unittest import struct -import numpy as np +from common.params import Params import cereal.messaging as messaging import selfdrive.sensord.pigeond as pd from system.hardware import TICI @@ -22,7 +22,20 @@ def read_events(service, duration_sec): return events -def verify_ubloxgnss_data(socket: messaging.SubSocket): +def create_backup(pigeon): + # controlled GNSS stop + pigeon.send(b"\xB5\x62\x06\x04\x04\x00\x00\x00\x08\x00\x16\x74") + + # store almanac in flash + pigeon.send(b"\xB5\x62\x09\x14\x04\x00\x00\x00\x00\x00\x21\xEC") + try: + if not pigeon.wait_for_ack(ack=pd.UBLOX_SOS_ACK, nack=pd.UBLOX_SOS_NACK): + assert False, "Could not store almanac" + except TimeoutError: + pass + + +def verify_ubloxgnss_data(socket: messaging.SubSocket, max_time: int): start_time = 0 end_time = 0 events = messaging.drain_sock(socket) @@ -42,7 +55,7 @@ def verify_ubloxgnss_data(socket: messaging.SubSocket): assert end_time != 0, "no ublox measurements received!" ttfm = (end_time - start_time)/1e9 - assert ttfm < 35, f"Time to first measurement > 35s, {ttfm}" + assert ttfm < max_time, f"Time to first measurement > {max_time}s, {ttfm}" # check for satellite count in measurements sat_count = [] @@ -52,42 +65,31 @@ def verify_ubloxgnss_data(socket: messaging.SubSocket): sat_count.append(event.ubloxGnss.measurementReport.numMeas) num_sat = int(sum(sat_count)/len(sat_count)) - assert num_sat > 8, f"Not enough satellites {num_sat} (TestBox setup!)" + assert num_sat > 5, f"Not enough satellites {num_sat} (TestBox setup!)" -def verify_gps_location(socket: messaging.SubSocket): - buf_lon = [0]*10 - buf_lat = [0]*10 - buf_i = 0 +def verify_gps_location(socket: messaging.SubSocket, max_time: int): events = messaging.drain_sock(socket) assert len(events) != 0, "no gpsLocationExternal measurements" start_time = events[0].logMonoTime end_time = 0 for event in events: - buf_lon[buf_i % 10] = event.gpsLocationExternal.longitude - buf_lat[buf_i % 10] = event.gpsLocationExternal.latitude - buf_i += 1 + gps_valid = event.gpsLocationExternal.flags % 2 - if buf_i < 9: - continue - - if any([lat == 0 or lon == 0 for lat,lon in zip(buf_lat, buf_lon)]): - continue - - if np.std(buf_lon) < 1e-5 and np.std(buf_lat) < 1e-5: + if gps_valid: end_time = event.logMonoTime break assert end_time != 0, "GPS location never converged!" ttfl = (end_time - start_time)/1e9 - assert ttfl < 40, f"Time to first location > 40s, {ttfl}" + assert ttfl < max_time, f"Time to first location > {max_time}s, {ttfl}" hacc = events[-1].gpsLocationExternal.accuracy vacc = events[-1].gpsLocationExternal.verticalAccuracy - assert hacc < 15, f"Horizontal accuracy too high, {hacc}" - assert vacc < 43, f"Vertical accuracy too high, {vacc}" + assert hacc < 20, f"Horizontal accuracy too high, {hacc}" + assert vacc < 45, f"Vertical accuracy too high, {vacc}" def verify_time_to_first_fix(pigeon): @@ -111,11 +113,16 @@ class TestGPS(unittest.TestCase): if not TICI: raise unittest.SkipTest + ublox_available = Params().get_bool("UbloxAvailable") + if not ublox_available: + raise unittest.SkipTest + + def tearDown(self): pd.set_power(False) @with_processes(['ubloxd']) - def test_ublox_reset(self): + def test_a_ublox_reset(self): pigeon, pm = pd.create_pigeon() pd.init_baudrate(pigeon) @@ -127,14 +134,58 @@ class TestGPS(unittest.TestCase): gle = messaging.sub_sock("gpsLocationExternal", timeout=0.1) # receive some messages (restart after cold start takes up to 30seconds) - pd.run_receiving(pigeon, pm, 40) + pd.run_receiving(pigeon, pm, 60) - verify_ubloxgnss_data(ugs) - verify_gps_location(gle) + # store almanac for next test + create_backup(pigeon) + + verify_ubloxgnss_data(ugs, 60) + verify_gps_location(gle, 60) # skip for now, this might hang for a while #verify_time_to_first_fix(pigeon) + @with_processes(['ubloxd']) + def test_b_ublox_almanac(self): + pigeon, pm = pd.create_pigeon() + pd.init_baudrate(pigeon) + + # device cold start + pigeon.send(b"\xb5\x62\x06\x04\x04\x00\xff\xff\x00\x00\x0c\x5d") + time.sleep(1) # wait for cold start + pd.init_baudrate(pigeon) + + # clear configuration + pigeon.send_with_ack(b"\xb5\x62\x06\x09\x0d\x00\x00\x00\x1f\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x17\x71\x5b") + + # restoring almanac backup + pigeon.send(b"\xB5\x62\x09\x14\x00\x00\x1D\x60") + status = pigeon.wait_for_backup_restore_status() + assert status == 2, "Could not restore almanac backup" + + pd.initialize_pigeon(pigeon) + + ugs = messaging.sub_sock("ubloxGnss", timeout=0.1) + gle = messaging.sub_sock("gpsLocationExternal", timeout=0.1) + + pd.run_receiving(pigeon, pm, 15) + verify_ubloxgnss_data(ugs, 15) + verify_gps_location(gle, 20) + + + @with_processes(['ubloxd']) + def test_c_ublox_startup(self): + pigeon, pm = pd.create_pigeon() + pd.init_baudrate(pigeon) + pd.initialize_pigeon(pigeon) + + ugs = messaging.sub_sock("ubloxGnss", timeout=0.1) + gle = messaging.sub_sock("gpsLocationExternal", timeout=0.1) + pd.run_receiving(pigeon, pm, 10) + verify_ubloxgnss_data(ugs, 10) + verify_gps_location(gle, 10) + + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/tools/gpstest/test_gps_qcom.py b/tools/gpstest/test_gps_qcom.py new file mode 100644 index 0000000000..0909316c5e --- /dev/null +++ b/tools/gpstest/test_gps_qcom.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +import time +import unittest +import subprocess as sp + +from common.params import Params +from system.hardware import TICI +import cereal.messaging as messaging +from selfdrive.manager.process_config import managed_processes + + +def exec_mmcli(cmd): + cmd = "mmcli -m 0 " + cmd + p = sp.Popen(cmd, shell=True, stdout=sp.PIPE, stderr=sp.PIPE) + return p.communicate() + + +def wait_for_location(socket, timeout): + while True: + events = messaging.drain_sock(socket) + for event in events: + if event.gpsLocation.flags % 2: + return False + + timeout -= 1 + if timeout <= 0: + return True + + time.sleep(0.1) + continue + + +class TestGPS(unittest.TestCase): + @classmethod + def setUpClass(cls): + if not TICI: + raise unittest.SkipTest + + ublox_available = Params().get_bool("UbloxAvailable") + if ublox_available: + raise unittest.SkipTest + + @unittest.skip("Skip cold start test due to time") + def test_quectel_cold_start(self): + # delete assistance data to enforce cold start for GNSS + # testing shows that this takes up to 20min + + # invalidate supl setting, cannot be reset + _, err = exec_mmcli("--location-set-supl-server=unittest:1") + + _, err = exec_mmcli("--command='AT+QGPSDEL=0'") + assert len(err) == 0, f"GPSDEL failed: {err}" + + managed_processes['rawgpsd'].start() + start_time = time.monotonic() + glo = messaging.sub_sock("gpsLocation", timeout=0.1) + + timeout = 10*60*25 # 25 minute + timedout = wait_for_location(glo, timeout) + managed_processes['rawgpsd'].stop() + + assert timedout is False, "Waiting for location timed out (25min)!" + + duration = time.monotonic() - start_time + assert duration < 50, f"Received GPS location {duration}!" + + + def test_a_quectel_cold_start_AGPS(self): + _, err = exec_mmcli("--command='AT+QGPSDEL=0'") + assert len(err) == 0, f"GPSDEL failed: {err}" + + # setup AGPS + exec_mmcli("--location-set-supl-server=supl.google.com:7276") + + managed_processes['rawgpsd'].start() + start_time = time.monotonic() + glo = messaging.sub_sock("gpsLocation", timeout=0.1) + + timeout = 10*60*3 # 3 minute + timedout = wait_for_location(glo, timeout) + managed_processes['rawgpsd'].stop() + + assert timedout is False, "Waiting for location timed out (3min)!" + + duration = time.monotonic() - start_time + assert duration < 60, f"Received GPS location {duration}!" + + + def test_b_quectel_startup(self): + + # setup AGPS + exec_mmcli("--location-set-supl-server=supl.google.com:7276") + + managed_processes['rawgpsd'].start() + start_time = time.monotonic() + glo = messaging.sub_sock("gpsLocation", timeout=0.1) + + timeout = 10*60*3 # 3 minute + timedout = wait_for_location(glo, timeout) + managed_processes['rawgpsd'].stop() + + assert timedout is False, "Waiting for location timed out (3min)!" + + duration = time.monotonic() - start_time + assert duration < 60, f"Received GPS location {duration}!" + + +if __name__ == "__main__": + unittest.main() From b80f2efdf29fb5095ea2fa258ec7695730467515 Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Wed, 26 Oct 2022 14:53:01 -0700 Subject: [PATCH 0098/1179] No fcw when standstill (#26252) --- selfdrive/controls/lib/longitudinal_planner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 018136e6f2..457065d3b5 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -133,7 +133,7 @@ class LongitudinalPlanner: # TODO counter is only needed because radar is glitchy, remove once radar is gone # TODO write fcw in e2e_long mode - self.fcw = self.mpc.mode == 'acc' and self.mpc.crash_cnt > 5 + self.fcw = self.mpc.mode == 'acc' and self.mpc.crash_cnt > 5 and not sm['carState'].standstill if self.fcw: cloudlog.info("FCW triggered") From 9e3e49a81f265eefbee32e7d96dbbae3f4b393f1 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 26 Oct 2022 15:11:45 -0700 Subject: [PATCH 0099/1179] readd camerad tests --- Jenkinsfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 85b4880463..b9b9eda667 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -137,7 +137,6 @@ pipeline { } } - /* stage('camerad') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { @@ -148,7 +147,6 @@ pipeline { ]) } } - */ stage('replay') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } From 6b6162d2c822c717cd62312f51113180c21b5664 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 27 Oct 2022 10:47:32 +0800 Subject: [PATCH 0100/1179] UI: support switching streams in CameraView (#26248) --- selfdrive/ui/qt/widgets/cameraview.cc | 35 ++++++++++++++++++--------- selfdrive/ui/qt/widgets/cameraview.h | 7 ++++-- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 200257235d..4f46497776 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -96,8 +96,8 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio) 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, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); - connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived); + QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); + QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); } CameraWidget::~CameraWidget() { @@ -162,13 +162,13 @@ void CameraWidget::initializeGL() { } void CameraWidget::showEvent(QShowEvent *event) { - frames.clear(); if (!vipc_thread) { vipc_thread = new QThread(); connect(vipc_thread, &QThread::started, [=]() { vipcThread(); }); connect(vipc_thread, &QThread::finished, vipc_thread, &QObject::deleteLater); vipc_thread->start(); } + clearFrames(); } void CameraWidget::hideEvent(QHideEvent *event) { @@ -178,6 +178,7 @@ void CameraWidget::hideEvent(QHideEvent *event) { vipc_thread->wait(); vipc_thread = nullptr; } + clearFrames(); } void CameraWidget::updateFrameMat() { @@ -233,6 +234,7 @@ void CameraWidget::paintGL() { glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + std::lock_guard lk(frame_lock); if (frames.empty()) return; int frame_idx = frames.size() - 1; @@ -249,14 +251,14 @@ void CameraWidget::paintGL() { qDebug() << "Skipped frame" << frames[frame_idx].first; } prev_frame_id = frames[frame_idx].first; + VisionBuf *frame = frames[frame_idx].second; + assert(frame != nullptr); glViewport(0, 0, width(), height()); glBindVertexArray(frame_vao); glUseProgram(program->programId()); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - VisionBuf *frame = frames[frame_idx].second; - #ifdef QCOM2 glActiveTexture(GL_TEXTURE0); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_images[frame->idx]); @@ -288,7 +290,6 @@ void CameraWidget::paintGL() { void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { makeCurrent(); - frames.clear(); stream_width = vipc_client->buffers[0].width; stream_height = vipc_client->buffers[0].height; stream_stride = vipc_client->buffers[0].stride; @@ -339,11 +340,7 @@ void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { updateFrameMat(); } -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(); - } +void CameraWidget::vipcFrameReceived() { update(); } @@ -354,11 +351,13 @@ void CameraWidget::vipcThread() { while (!QThread::currentThread()->isInterruptionRequested()) { if (!vipc_client || cur_stream_type != stream_type) { + clearFrames(); cur_stream_type = stream_type; vipc_client.reset(new VisionIpcClient(stream_name, cur_stream_type, false)); } if (!vipc_client->connected) { + clearFrames(); if (!vipc_client->connect(false)) { QThread::msleep(100); continue; @@ -367,7 +366,14 @@ void CameraWidget::vipcThread() { } if (VisionBuf *buf = vipc_client->recv(&meta_main, 1000)) { - emit vipcThreadFrameReceived(buf, meta_main.frame_id); + { + std::lock_guard lk(frame_lock); + frames.push_back(std::make_pair(meta_main.frame_id, buf)); + while (frames.size() > FRAME_BUFFER_SIZE) { + frames.pop_front(); + } + } + emit vipcThreadFrameReceived(); } } @@ -378,3 +384,8 @@ void CameraWidget::vipcThread() { egl_images.clear(); #endif } + +void CameraWidget::clearFrames() { + std::lock_guard lk(frame_lock); + frames.clear(); +} diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 9bcad935c0..ef828f8ff6 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -37,7 +38,7 @@ public: signals: void clicked(); void vipcThreadConnected(VisionIpcClient *); - void vipcThreadFrameReceived(VisionBuf *, quint32); + void vipcThreadFrameReceived(); protected: void paintGL() override; @@ -49,6 +50,7 @@ protected: virtual void updateFrameMat(); void updateCalibration(const mat3 &calib); void vipcThread(); + void clearFrames(); bool zoomed_view; GLuint frame_vao, frame_vbo, frame_ibo; @@ -76,11 +78,12 @@ protected: mat3 calibration = DEFAULT_CALIBRATION; mat3 intrinsic_matrix = fcam_intrinsic_matrix; + std::mutex frame_lock; std::deque> frames; uint32_t draw_frame_id = 0; uint32_t prev_frame_id = 0; protected slots: void vipcConnected(VisionIpcClient *vipc_client); - void vipcFrameReceived(VisionBuf *vipc_client, uint32_t frame_id); + void vipcFrameReceived(); }; From 69b0aa94fa7364265af05936e3e85e94a3c13861 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 26 Oct 2022 20:17:28 -0700 Subject: [PATCH 0101/1179] Toyota: add missing RAV4 2022 engine FW (#26249) Update values.py --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 819b85d759..07c33d0173 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1367,6 +1367,7 @@ FW_VERSIONS = { b'\x01896634AA1000\x00\x00\x00\x00', b'\x01896634A88000\x00\x00\x00\x00', b'\x01896634A89000\x00\x00\x00\x00', + b'\x01896634A89100\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F0R01100\x00\x00\x00\x00', From 5b455f1d318939470b99ab81d2e20d247db2715d Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 26 Oct 2022 20:22:46 -0700 Subject: [PATCH 0102/1179] finalize gps tests (#26255) * finalize gps test before adding to ci Co-authored-by: Kurt Nistelberger --- tools/gpstest/run_unittest.sh | 4 ++-- tools/gpstest/test_gps.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/gpstest/run_unittest.sh b/tools/gpstest/run_unittest.sh index d284fa74e5..9f93fdfc9a 100755 --- a/tools/gpstest/run_unittest.sh +++ b/tools/gpstest/run_unittest.sh @@ -3,8 +3,8 @@ # NOTE: can only run inside limeGPS test box! # run limeGPS with random static location -timeout 300 ./simulate_gps_signal.py & -gps_PID=$? +timeout 300 ./simulate_gps_signal.py 32.7518 -117.1962 & +gps_PID=$(ps -aux | grep -m 1 "timeout 300" | cut -d ' ' -f 7) echo "starting limeGPS..." sleep 10 diff --git a/tools/gpstest/test_gps.py b/tools/gpstest/test_gps.py index b5d0cdd254..8bc5dc89a8 100644 --- a/tools/gpstest/test_gps.py +++ b/tools/gpstest/test_gps.py @@ -65,7 +65,7 @@ def verify_ubloxgnss_data(socket: messaging.SubSocket, max_time: int): sat_count.append(event.ubloxGnss.measurementReport.numMeas) num_sat = int(sum(sat_count)/len(sat_count)) - assert num_sat > 5, f"Not enough satellites {num_sat} (TestBox setup!)" + assert num_sat >= 5, f"Not enough satellites {num_sat} (TestBox setup!)" def verify_gps_location(socket: messaging.SubSocket, max_time: int): @@ -188,4 +188,4 @@ class TestGPS(unittest.TestCase): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From 5e717c12f11151ca064c6829b75616c0776d0059 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 27 Oct 2022 13:14:26 +0800 Subject: [PATCH 0103/1179] Cabana:: remove a fixed TODO (#26257) remove a fixed TODO --- tools/cabana/videowidget.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 7180d5ac0f..9a28f71bb9 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -17,7 +17,6 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); - // 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); From 7c1bb03497f28ad7e014d7df7262f4cfcd2fc738 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 28 Oct 2022 03:57:22 +0800 Subject: [PATCH 0104/1179] Cabana: set fixed height for statusbar (#26264) --- tools/cabana/mainwin.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 30c7e5e0a2..f127e5f52b 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -23,6 +23,7 @@ MainWindow::MainWindow() : QWidget() { main_layout->addLayout(h_layout); QSplitter *splitter = new QSplitter(Qt::Horizontal, this); + splitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); messages_widget = new MessagesWidget(this); splitter->addWidget(messages_widget); @@ -58,6 +59,7 @@ MainWindow::MainWindow() : QWidget() { // status bar status_bar = new QStatusBar(this); + status_bar->setFixedHeight(20); status_bar->setContentsMargins(0, 0, 0, 0); status_bar->setSizeGripEnabled(true); progress_bar = new QProgressBar(); From f04ca9ff3dc1af71a66c2d1d75364938e898ed10 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 28 Oct 2022 03:58:25 +0800 Subject: [PATCH 0105/1179] Cabana: fix dbc opened twice on startup (#26265) --- tools/cabana/messageswidget.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 9b831ad18c..4975061cc5 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -85,10 +85,12 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { } void MessagesWidget::loadDBCFromName(const QString &name) { - dbc()->open(name); - dbc_combo->setCurrentText(name); - // refresh model - model->updateState(); + if (name != dbc()->name()) { + dbc()->open(name); + dbc_combo->setCurrentText(name); + // re-sort model to refresh column 'Name' + model->updateState(true); + } } void MessagesWidget::loadDBCFromPaste() { From d67965901895432375584d95103ee1afc14f5554 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 28 Oct 2022 04:59:52 +0800 Subject: [PATCH 0106/1179] Cabana: fix marker z-index (#26254) --- tools/cabana/chartswidget.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index ea44a4033c..c7846de069 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -247,10 +247,13 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) chart->layout()->setContentsMargins(0, 0, 0, 0); track_line = new QGraphicsLineItem(chart); + track_line->setZValue(chart->zValue() + 10); track_line->setPen(QPen(Qt::gray, 1, Qt::DashLine)); value_text = new QGraphicsSimpleTextItem(chart); + value_text->setZValue(chart->zValue() + 10); value_text->setBrush(Qt::gray); line_marker = new QGraphicsLineItem(chart); + line_marker->setZValue(chart->zValue() + 10); line_marker->setPen(QPen(Qt::black, 2)); setChart(chart); From fbafde6f1c46b50c219c3ec3121b94ee0848a7be Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 27 Oct 2022 14:04:02 -0700 Subject: [PATCH 0107/1179] Ford FW batch (#26251) * add Ford Explorer 2022 fw VIN: 1FM5K8GC7NGA85105 8e1bab39e558e773|2022-09-16--02-38-57 * add Ford Escape Titanium PHEV 2021 fw VIN: 1FMCU0LZXMUA80767 f8eaaccd2a90aef8|2022-09-30--15-42-38--0 * add Ford Escape 2020 fw VIN: 1FMCU9DZ9LUA82589 26b2cace68e36212|2022-10-05--18-55-54--0 --- selfdrive/car/ford/values.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 7b3140fbbf..5114f8d065 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -61,10 +61,10 @@ class FordCarInfo(CarInfo): CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { CAR.ESCAPE_MK4: [ - FordCarInfo("Ford Escape 2020"), - FordCarInfo("Ford Kuga EU", "Driver Assistance Pack"), + FordCarInfo("Ford Escape 2020-21"), + FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"), ], - CAR.EXPLORER_MK6: FordCarInfo("Ford Explorer 2020-21"), + CAR.EXPLORER_MK6: FordCarInfo("Ford Explorer 2020-22"), CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2019", "Driver Assistance Pack"), } @@ -87,31 +87,41 @@ FW_QUERY_CONFIG = FwQueryConfig( FW_VERSIONS = { CAR.ESCAPE_MK4: { (Ecu.eps, 0x730, None): [ + b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x760, None): [ b'LX6C-2D053-NS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6C-2D053-NY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6C-2D053-SA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x764, None): [ b'LB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x706, None): [ b'LJ6T-14F397-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LJ6T-14F397-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7E0, None): [ + b'LX6A-14C204-BJV\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6A-14C204-ESG\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'MX6A-14C204-BEF\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.shiftByWire, 0x732, None): [ + b'LX6P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], }, CAR.EXPLORER_MK6: { (Ecu.eps, 0x730, None): [ b'L1MC-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'M1MC-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x760, None): [ b'L1MC-2D053-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-BF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'L1MC-2D053-KB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x764, None): [ b'LB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', @@ -123,10 +133,12 @@ FW_VERSIONS = { (Ecu.engine, 0x7E0, None): [ b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'NB5A-14C204-HB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.shiftByWire, 0x732, None): [ b'L1MP-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'L1MP-14G395-JB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], }, CAR.FOCUS_MK4: { From 995c74a994345de3d22c84cd1404aaf4cf8b7e82 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 27 Oct 2022 14:36:47 -0700 Subject: [PATCH 0108/1179] process replay: test Bolt EUV (camera-ACC platform) (#26270) ADD BOLT TO PROCESS REPLAY --- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/test_processes.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index ba0f30e5c3..a3ca4163d5 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -8f2919ba4d8509432e93ff0a44f951254c1ff3fe \ No newline at end of file +fbafde6f1c46b50c219c3ec3121b94ee0848a7be \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index cecabd8a3a..5c754d9312 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -24,10 +24,11 @@ source_segments = [ ("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2 ("HONDA", "eb140f119469d9ab|2021-06-12--10-46-24--27"), # HONDA.CIVIC (NIDEC) ("HONDA2", "7d2244f34d1bbcda|2021-06-25--12-25-37--26"), # HONDA.ACCORD (BOSCH) - ("CHRYSLER", "4deb27de11bee626|2021-02-20--11-28-55--8"), # CHRYSLER.PACIFICA + ("CHRYSLER", "4deb27de11bee626|2021-02-20--11-28-55--8"), # CHRYSLER.PACIFICA_2018_HYBRID ("RAM", "2f4452b03ccb98f0|2022-09-07--13-55-08--10"), # CHRYSLER.RAM_1500 ("SUBARU", "341dccd5359e3c97|2022-09-12--10-35-33--3"), # SUBARU.OUTBACK ("GM", "0c58b6a25109da2b|2021-02-23--16-35-50--11"), # GM.VOLT + ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), # GM.BOLT_EUV ("NISSAN", "35336926920f3571|2021-02-12--18-38-48--46"), # NISSAN.XTRAIL ("VOLKSWAGEN", "de9592456ad7d144|2021-06-29--11-00-15--6"), # VOLKSWAGEN.GOLF ("MAZDA", "bd6a637565e91581|2021-10-30--15-14-53--4"), # MAZDA.CX9_2021 @@ -50,6 +51,7 @@ segments = [ ("RAM", "regen20490083AE7|2022-09-27--15-53-15--0"), ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"), + ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), ("NISSAN", "regenC19D899B46D|2022-09-27--15-59-13--0"), ("VOLKSWAGEN", "regenD8F7AC4BD0D|2022-09-27--16-41-45--0"), ("MAZDA", "regenFC3F9ECBB64|2022-09-27--16-03-09--0"), From ba570b963f18d96ac181882b1f4e1678b992f665 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 28 Oct 2022 05:48:40 +0800 Subject: [PATCH 0109/1179] Cabana: change the chart theme in setting (#26220) * change the chart theme in setting * change title colors * cleanup --- tools/cabana/chartswidget.cc | 27 ++++++++++++++++++++------- tools/cabana/chartswidget.h | 5 ++++- tools/cabana/settings.cc | 8 ++++++++ tools/cabana/settings.h | 3 +++ 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index c7846de069..3f1dd890c3 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -200,33 +200,31 @@ ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) main_layout->setSpacing(0); main_layout->setContentsMargins(0, 0, 0, 0); - QWidget *header = new QWidget(this); - header->setStyleSheet("background-color:white"); + header = new QWidget(this); QGridLayout *header_layout = new QGridLayout(header); header_layout->setContentsMargins(11, 11, 11, 0); msg_name_label = new QLabel(this); msg_name_label->setTextFormat(Qt::RichText); header_layout->addWidget(msg_name_label, 0, 0, Qt::AlignLeft); sig_name_label = new QLabel(this); - sig_name_label->setStyleSheet("font-weight:bold"); header_layout->addWidget(sig_name_label, 0, 1, Qt::AlignCenter); //, 0, Qt::AlignCenter); - QPushButton *remove_btn = new QPushButton("✖", this); + remove_btn = new QPushButton("✖", this); remove_btn->setFixedSize(20, 20); remove_btn->setToolTip(tr("Remove chart")); header_layout->addWidget(remove_btn, 0, 2, Qt::AlignRight); main_layout->addWidget(header); chart_view = new ChartView(id, sig, this); - chart_view->setFixedHeight(settings.chart_height); main_layout->addWidget(chart_view); main_layout->addStretch(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); updateTitle(); + updateFromSettings(); QObject::connect(remove_btn, &QPushButton::clicked, [=]() { emit remove(id, sig); }); - QObject::connect(&settings, &Settings::changed, [this]() { chart_view->setFixedHeight(settings.chart_height); }); + QObject::connect(&settings, &Settings::changed, this, &ChartWidget::updateFromSettings); } void ChartWidget::updateTitle() { @@ -234,12 +232,22 @@ void ChartWidget::updateTitle() { sig_name_label->setText(signal->name.c_str()); } +void ChartWidget::updateFromSettings() { + header->setStyleSheet(settings.chart_theme == 0 ? "background-color:white" : "background-color:#23242c"); + QString color_style = settings.chart_theme == 0 ? "color:black" : "color:white"; + sig_name_label->setStyleSheet("font-weight:bold;" + color_style); + msg_name_label->setStyleSheet(color_style); + remove_btn->setStyleSheet(color_style); + chart_view->updateFromSettings(); +} + // ChartView ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) : id(id), signal(sig), QChartView(nullptr, parent) { QLineSeries *series = new QLineSeries(); QChart *chart = new QChart(); + chart->setBackgroundRoundness(0); chart->addSeries(series); chart->createDefaultAxes(); chart->legend()->hide(); @@ -254,7 +262,6 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) value_text->setBrush(Qt::gray); line_marker = new QGraphicsLineItem(chart); line_marker->setZValue(chart->zValue() + 10); - line_marker->setPen(QPen(Qt::black, 2)); setChart(chart); @@ -277,6 +284,12 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) }); } +void ChartView::updateFromSettings() { + setFixedHeight(settings.chart_height); + chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark); + line_marker->setPen(QPen(settings.chart_theme == 0 ? Qt::black : Qt::white, 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())) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index a7c6f4bbd3..897ed62c2f 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -23,6 +23,7 @@ public: void updateSeries(const std::pair &range); void setRange(double min, double max, bool force_update = false); void updateLineMarker(double current_sec); + void updateFromSettings(); signals: void zoomIn(double min, double max); @@ -34,7 +35,6 @@ private: void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void adjustChartMargins(); - void updateAxisY(); QGraphicsLineItem *track_line; @@ -51,6 +51,7 @@ Q_OBJECT public: ChartWidget(const QString &id, const Signal *sig, QWidget *parent); void updateTitle(); + void updateFromSettings(); signals: void remove(const QString &msg_id, const Signal *sig); @@ -58,8 +59,10 @@ signals: public: QString id; const Signal *signal; + QWidget *header; QLabel *msg_name_label; QLabel *sig_name_label; + QPushButton *remove_btn; ChartView *chart_view = nullptr; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 6e9d7f17cc..93bc05f20b 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -17,6 +17,7 @@ void Settings::save() { s.setValue("log_size", can_msg_log_size); s.setValue("cached_segment", cached_segment_limit); s.setValue("chart_height", chart_height); + s.setValue("chart_theme", chart_theme); s.setValue("max_chart_x_range", max_chart_x_range); emit changed(); } @@ -27,6 +28,7 @@ void Settings::load() { can_msg_log_size = s.value("log_size", 100).toInt(); cached_segment_limit = s.value("cached_segment", 3).toInt(); chart_height = s.value("chart_height", 200).toInt(); + chart_theme = s.value("chart_theme", 0).toInt(); max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); } @@ -67,6 +69,11 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { chart_height->setValue(settings.chart_height); form_layout->addRow(tr("Chart's height"), chart_height); + chart_theme = new QComboBox(); + chart_theme->addItems({"Light", "Dark"}); + chart_theme->setCurrentIndex(settings.chart_theme == 1 ? 1 : 0); + form_layout->addRow(tr("Chart theme"), chart_theme); + main_layout->addLayout(form_layout); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); @@ -82,6 +89,7 @@ void SettingsDlg::save() { settings.can_msg_log_size = log_size->value(); settings.cached_segment_limit = cached_segment->value(); settings.chart_height = chart_height->value(); + settings.chart_theme = chart_theme->currentIndex(); settings.max_chart_x_range = max_chart_x_range->value() * 60; settings.save(); accept(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index fa97c49140..88eeebc722 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -15,6 +16,7 @@ public: int can_msg_log_size = 100; int cached_segment_limit = 3; int chart_height = 200; + int chart_theme = 0; int max_chart_x_range = 3 * 60; // 3 minutes signals: @@ -31,6 +33,7 @@ public: QSpinBox *log_size ; QSpinBox *cached_segment; QSpinBox *chart_height; + QComboBox *chart_theme; QSpinBox *max_chart_x_range; }; From b158c016cbd58a84e57124f49c657dbba8beb19e Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Thu, 27 Oct 2022 16:34:11 -0700 Subject: [PATCH 0110/1179] [torqued] Update offline values (#26261) * add qlog mode to torqued * update offline valujes from qlogs * resollve comments * update refs * resolve comments --- selfdrive/car/torque_data/override.yaml | 1 - selfdrive/car/torque_data/params.yaml | 29 ++++++++++++------------ selfdrive/locationd/torqued.py | 23 ++++++++++++++----- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 13a0dae7a7..460b9a9097 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -21,7 +21,6 @@ FORD FOCUS 4TH GEN: [.nan, 1.5, .nan] COMMA BODY: [.nan, 1000, .nan] # Totally new cars -KIA EV6 2022: [3.5, 3.0, 0.0] RAM 1500 5TH GEN: [2.0, 2.0, 0.0] RAM HD 5TH GEN: [1.4, 1.4, 0.0] SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 60b1662cee..5c828fa669 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -39,17 +39,18 @@ HYUNDAI SONATA 2020: [2.9638737459977467, 2.1259108157250735, 0.0781366561692759 HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488717382] JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185] JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003] +KIA EV6 2022: [3.2, 3.0, 0.05] KIA K5 2021: [2.405339728085138, 1.460032270828705, 0.11650989850813716] KIA NIRO EV 2020: [2.9215954981365337, 2.1500583840260044, 0.09236802474810267] KIA SORENTO GT LINE 2018: [2.464854685101844, 1.5335274218367956, 0.12056170567599558] KIA STINGER GT2 2018: [2.7499043387418967, 1.849652021986449, 0.12048334239559202] -LEXUS ES 2019: [2.0203086922726112, 2.134803912579666, 0.12757526789308554] -LEXUS ES HYBRID 2019: [2.392442298703042, 1.863360677810788, 0.17690002108856212] +LEXUS ES 2019: [1.935835, 2.134803912579666, 0.093439] +LEXUS ES HYBRID 2019: [2.135678, 1.863360677810788, 0.109627] LEXUS NX 2018: [2.302625600642627, 2.1382378491466625, 0.14986840878892838] LEXUS NX 2020: [2.4331999786982936, 2.1045680431705414, 0.14099899317761067] LEXUS NX HYBRID 2018: [2.4025593501080955, 1.8080446063815507, 0.15349361249519017] LEXUS RX 2016: [1.5876816543130423, 1.0427699298523752, 0.21334066732397142] -LEXUS RX 2020: [1.5228812994274734, 1.431102486563665, 0.2093316728710659] +LEXUS RX 2020: [1.5228812994274734, 1.431102486563665, 0.164117] LEXUS RX HYBRID 2017: [1.6984261557042386, 1.3211501880159107, 0.1820354534928893] LEXUS RX HYBRID 2020: [1.5522309889823778, 1.255230465866663, 0.2220954003055114] MAZDA CX-9 2021: [1.7601682915983443, 1.0889677335154337, 0.17713792194297195] @@ -62,31 +63,31 @@ TOYOTA AVALON 2019: [1.7036141952825095, 1.239619084240008, 0.08459830394899492] TOYOTA AVALON 2022: [2.3154403649717357, 2.7777922854327124, 0.11453999639164605] TOYOTA C-HR 2018: [1.5591084333664578, 1.271271459066948, 0.20259087058453193] TOYOTA C-HR 2021: [1.7678810166088303, 1.3742176337919942, 0.2319674583741509] -TOYOTA CAMRY 2018: [2.1172995371905015, 1.7156177222420887, 0.13519250664782062] -TOYOTA CAMRY 2021: [2.6922769557433055, 2.3476510120007434, 0.1450430192989234] -TOYOTA CAMRY HYBRID 2018: [2.0974120828287774, 1.7996193116697359, 0.13823613467632756] -TOYOTA CAMRY HYBRID 2021: [2.6426668350384457, 2.3901492458927986, 0.16103875108816076] +TOYOTA CAMRY 2018: [2.1172995371905015, 1.7156177222420887, 0.105192506] +TOYOTA CAMRY 2021: [2.446083, 2.3476510120007434, 0.121615] +TOYOTA CAMRY HYBRID 2018: [1.996333, 1.7996193116697359, 0.112565] +TOYOTA CAMRY HYBRID 2021: [2.263582, 2.3901492458927986, 0.115257] TOYOTA COROLLA 2017: [3.117154369115421, 1.8438132575043773, 0.12289685869250652] TOYOTA COROLLA HYBRID TSS2 2019: [1.9079729107361805, 1.8118712531729109, 0.22251440891543514] TOYOTA COROLLA TSS2 2019: [2.0742917676766712, 1.9258612322678952, 0.16888685704519352] TOYOTA HIGHLANDER 2017: [1.8696367437248915, 1.626293990451463, 0.17485372210240796] TOYOTA HIGHLANDER 2020: [2.022340166827233, 1.6183134804881791, 0.14592306380054457] -TOYOTA HIGHLANDER HYBRID 2018: [1.9421825202382728, 1.6433903296845025, 0.16928956792275918] -TOYOTA HIGHLANDER HYBRID 2020: [2.103373061114133, 2.104015182965606, 0.14447040132184993] +TOYOTA HIGHLANDER HYBRID 2018: [1.752033, 1.6433903296845025, 0.144600] +TOYOTA HIGHLANDER HYBRID 2020: [1.901174, 2.104015182965606, 0.14447040132184993] TOYOTA MIRAI 2021: [2.506899832157829, 1.7417213930750164, 0.20182618449440565] -TOYOTA PRIUS 2017: [2.0183401513314294, 1.5023147650693636, 0.20856908464957724] -TOYOTA PRIUS TSS2 2021: [2.327639738920072, 1.9104337425537743, 0.2030762265549664] +TOYOTA PRIUS 2017: [1.746445, 1.5023147650693636, 0.151515] +TOYOTA PRIUS TSS2 2021: [1.972600, 1.9104337425537743, 0.170968] TOYOTA RAV4 2017: [2.085695074355425, 2.2142832316984733, 0.13339165270103975] -TOYOTA RAV4 2019: [2.5038362866776835, 2.0993589721530252, 0.1552425356342368] +TOYOTA RAV4 2019: [2.331293, 2.0993589721530252, 0.129822] TOYOTA RAV4 2019 8965: [2.5084506298290377, 2.4216520504763475, 0.11992835265067918] TOYOTA RAV4 2019 x02: [2.7209621987605024, 2.2148637653781593, 0.10862567142268198] TOYOTA RAV4 HYBRID 2017: [1.9796257271652042, 1.7503987331707576, 0.14628860048885406] TOYOTA RAV4 HYBRID 2019: [2.2271858492309153, 2.074844961405639, 0.14382216826893632] TOYOTA RAV4 HYBRID 2019 8965: [2.1077397198131336, 1.8162215166877735, 0.13891369391200137] TOYOTA RAV4 HYBRID 2019 x02: [2.803624333289342, 2.272367966572498, 0.11364569214387774] -TOYOTA RAV4 HYBRID 2022: [2.241883248393209, 1.9304407208090029, 0.1565442715453653] +TOYOTA RAV4 HYBRID 2022: [2.241883248393209, 1.9304407208090029, 0.112174] TOYOTA RAV4 HYBRID 2022 x02: [3.044930631831037, 2.3979189796380918, 0.14023209146703736] -TOYOTA SIENNA 2018: [1.8660896232147548, 1.3208264576110418, 0.18799149615227198] +TOYOTA SIENNA 2018: [1.689726, 1.3208264576110418, 0.140456] VOLKSWAGEN ARTEON 1ST GEN: [1.45136518053819, 1.3639364049316804, 0.23806361745695032] VOLKSWAGEN ATLAS 1ST GEN: [1.4677006726964945, 1.6733266634075656, 0.12959584092073367] VOLKSWAGEN GOLF 7TH GEN: [1.3750394140491293, 1.5814743077200641, 0.2018321939386586] diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 66af234590..42dff60087 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -16,7 +16,9 @@ from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY HISTORY = 5 # secs POINTS_PER_BUCKET = 1500 MIN_POINTS_TOTAL = 4000 +MIN_POINTS_TOTAL_QLOG = 800 FIT_POINTS_TOTAL = 2000 +FIT_POINTS_TOTAL_QLOG = 800 MIN_VEL = 15 # m/s FRICTION_FACTOR = 1.5 # ~85% of data coverage FACTOR_SANITY = 0.3 @@ -26,7 +28,7 @@ MIN_FILTER_DECAY = 50 MAX_FILTER_DECAY = 250 LAT_ACC_THRESHOLD = 1 STEER_BUCKET_BOUNDS = [(-0.5, -0.3), (-0.3, -0.2), (-0.2, -0.1), (-0.1, 0), (0, 0.1), (0.1, 0.2), (0.2, 0.3), (0.3, 0.5)] -MIN_BUCKET_POINTS = [100, 300, 500, 500, 500, 500, 300, 100] +MIN_BUCKET_POINTS = np.array([100, 300, 500, 500, 500, 500, 300, 100]) MAX_RESETS = 5.0 MAX_INVALID_THRESHOLD = 10 MIN_ENGAGE_BUFFER = 2 # secs @@ -58,10 +60,11 @@ class NPQueue: class PointBuckets: - def __init__(self, x_bounds, min_points): + def __init__(self, x_bounds, min_points, min_points_total): self.x_bounds = x_bounds self.buckets = {bounds: NPQueue(maxlen=POINTS_PER_BUCKET, rowsize=3) for bounds in x_bounds} self.buckets_min_points = {bounds: min_point for bounds, min_point in zip(x_bounds, min_points)} + self.min_points_total = min_points_total def bucket_lengths(self): return [len(v) for v in self.buckets.values()] @@ -70,7 +73,7 @@ class PointBuckets: return sum(self.bucket_lengths()) def is_valid(self): - return all(len(v) >= min_pts for v, min_pts in zip(self.buckets.values(), self.buckets_min_points.values())) and (self.__len__() >= MIN_POINTS_TOTAL) + return all(len(v) >= min_pts for v, min_pts in zip(self.buckets.values(), self.buckets_min_points.values())) and (self.__len__() >= self.min_points_total) def add_point(self, x, y): for bound_min, bound_max in self.x_bounds: @@ -90,9 +93,17 @@ class PointBuckets: class TorqueEstimator: - def __init__(self, CP): + def __init__(self, CP, decimated=False): self.hist_len = int(HISTORY / DT_MDL) self.lag = CP.steerActuatorDelay + .2 # from controlsd + if decimated: + self.min_bucket_points = MIN_BUCKET_POINTS / 10 + self.min_points_total = MIN_POINTS_TOTAL_QLOG + self.fit_points = FIT_POINTS_TOTAL_QLOG + else: + self.min_bucket_points = MIN_BUCKET_POINTS + self.min_points_total = MIN_POINTS_TOTAL + self.fit_points = FIT_POINTS_TOTAL self.offline_friction = 0.0 self.offline_latAccelFactor = 0.0 @@ -157,10 +168,10 @@ class TorqueEstimator: self.invalid_values_tracker = 0.0 self.decay = MIN_FILTER_DECAY self.raw_points = defaultdict(lambda: deque(maxlen=self.hist_len)) - self.filtered_points = PointBuckets(x_bounds=STEER_BUCKET_BOUNDS, min_points=MIN_BUCKET_POINTS) + self.filtered_points = PointBuckets(x_bounds=STEER_BUCKET_BOUNDS, min_points=self.min_bucket_points, min_points_total=self.min_points_total) def estimate_params(self): - points = self.filtered_points.get_points(FIT_POINTS_TOTAL) + points = self.filtered_points.get_points(self.fit_points) # total least square solution as both x and y are noisy observations # this is empirically the slope of the hysteresis parallelogram as opposed to the line through the diagonals try: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a3ca4163d5..fad9f5e598 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -fbafde6f1c46b50c219c3ec3121b94ee0848a7be \ No newline at end of file +f4ea2499a95e198914fd275a8380178e8ff65a31 \ No newline at end of file From c2326a421993534c49aea1efa78e31a6bfa0625c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 27 Oct 2022 16:44:22 -0700 Subject: [PATCH 0111/1179] process replay: support experimental long (#26233) Support experimental long --- selfdrive/test/process_replay/process_replay.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 9d37be4a56..bc55e33cbf 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -456,6 +456,9 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): os.environ['SKIP_FW_QUERY'] = "1" os.environ['FINGERPRINT'] = CP.carFingerprint + if CP.openpilotLongitudinalControl: + params.put_bool("ExperimentalLongitudinalEnabled", True) + def python_replay_process(cfg, lr, fingerprint=None): sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] From 26cb6d09e76baaf0862cdf061013247bb62a197c Mon Sep 17 00:00:00 2001 From: ambientocclusion <1399123+ambientocclusion@users.noreply.github.com> Date: Thu, 27 Oct 2022 17:04:09 -0700 Subject: [PATCH 0112/1179] Multilang: revise some Japanese translations (#25811) Revise some Japanese translations Co-authored-by: Shane Smiskol --- selfdrive/ui/translations/main_ja.ts | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 314a6b8338..a11333a54d 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -56,7 +56,7 @@ leave blank for automatic configuration - 空白のままにして、自動設定にします + 自動で設定するには、空白のままにしてください。 Cellular Metered @@ -136,7 +136,7 @@ PREVIEW - 見る + プレビュー Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) @@ -156,7 +156,7 @@ Review Training Guide - 入門書を見る + 使い方の確認 REVIEW @@ -168,7 +168,7 @@ Are you sure you want to review the training guide? - 入門書を見てもよろしいですか? + 使い方の確認をしますか? Regulatory @@ -200,11 +200,11 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot は、左または右の4°以内、上の5°または下の8°以内にデバイスを取付ける必要があります。キャリブレーションを引き続きます、リセットはほとんど必要ありません。 + openpilotの本体は、左右4°以内、上5°、下8°以内の角度で取付ける必要があります。継続してキャリブレーションを続けているので、手動でリセットを行う必要はほぼありません。 Your device is pointed %1° %2 and %3° %4. - このデバイスは%2の%1°、%4の%3°に向けます。 + このデバイスは%2 %1°、%4 %3°の向きに設置されています。 down @@ -309,7 +309,7 @@ MapETA eta - 予定到着時間 + 到着予定時間 min @@ -452,15 +452,15 @@ location set Go to https://connect.comma.ai on your phone - モバイルデバイスで「connect.comma.ai」にアクセスして + スマートフォンで「https://connect.comma.ai」にアクセスしてください。 Click "add new device" and scan the QR code on the right - 「新しいデバイスを追加」を押すと、右側のQRコードをスキャンしてください + 「新しいデバイスを追加」を押し、右側のQRコードをスキャンしてください。 Bookmark connect.comma.ai to your home screen to use it like an app - 「connect.comma.ai」をホーム画面に追加して、アプリのように使うことができます + 「connect.comma.ai」をホーム画面に追加して、アプリのように使うことができます。 @@ -608,7 +608,7 @@ location set Toggles - 切り替え + 機能設定 Software @@ -627,7 +627,7 @@ location set Power your device in a car with a harness or proceed at your own risk. - 自己責任でハーネスから電源を供給してください。 + 自己責任で実行を継続するか、ハーネスから電源を供給してください。 Power off @@ -643,7 +643,7 @@ location set Before we get on the road, let’s finish installation and cover some details. - その前に、インストールを完了し、いくつかの詳細を説明します。 + 道路に向かう前に、インストールを完了して使い方を確認しましょう。 Connect to Wi-Fi @@ -655,7 +655,7 @@ location set Continue without Wi-Fi - Wi-Fi に未接続で続行 + Wi-Fi に接続せずに続行 Waiting for internet @@ -663,7 +663,7 @@ location set Choose Software to Install - インストールするソフトウェアを選びます + インストールするソフトウェアを選択してください Dashcam @@ -710,7 +710,7 @@ location set Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. - デバイスを comma connect (connect.comma.ai)でペアリングし comma prime 特典を申請してください。 + デバイスを comma connect (connect.comma.ai)でペアリングし、comma primeの特典を申請してください。 Pair device @@ -836,7 +836,7 @@ location set UNINSTALL - アンインストール + 実行 Uninstall %1 @@ -859,7 +859,7 @@ location set Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - 警告: これは、GitHub の設定にあるすべての公開鍵への SSH アクセスを許可するものです。自分以外の GitHub のユーザー名を入力しないでください。コンマのスタッフが GitHub のユーザー名を追加するようお願いすることはありません。 + 警告: これは、GitHub の設定にあるすべての公開鍵への SSH アクセスを許可するものです。自分以外の GitHub のユーザー名を入力しないでください。commaのスタッフが GitHub のユーザー名を追加するようお願いすることはありません。 ADD @@ -871,7 +871,7 @@ location set LOADING - ローディング + 読み込み中 REMOVE @@ -924,7 +924,7 @@ location set Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. - アダプティブクルーズコントロールとレーンキーピングドライバーアシスト(openpilotシステム)。この機能を使用するには、常に注意が必要です。この設定を変更すると、車の電源が切れたときに有効になります。 + openpilotによるアダプティブクルーズコントロールとレーンキーピングドライバーアシストを利用します。この機能を利用する際は、常に前方への注意が必要です。この設定を変更すると、車の電源が切れた時に反映されます。 Enable Lane Departure Warnings @@ -932,11 +932,11 @@ location set Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). - 時速31マイル(50km)を超えるスピードで走行中、ウインカーを作動させずに検出された車線ライン上に車両が触れた場合、車線に戻るアラートを受信します。 + 時速31マイル(50km)を超えるスピードで走行中、ウインカーを作動させずに検出された車線ライン上に車両が触れた場合、手動で車線内に戻るように警告を行います。 Use Metric System - メートル法を有効化 + メートル法を使用 Display speed in km/h instead of mph. @@ -952,7 +952,7 @@ location set 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 エンドツーエンドのアクセル制御 (超アルファ版) 🌮 + 🌮 エンドツーエンドのアクセル制御 (超α版) 🌮 Experimental openpilot longitudinal control @@ -976,11 +976,11 @@ location set Disengage On Accelerator Pedal - アクセル踏むと openpilot をキャンセル + アクセルを踏むと openpilot を中断 When enabled, pressing the accelerator pedal will disengage openpilot. - 有効な場合は、アクセルを踏むと openpilot をキャンセルします。 + この機能を有効化すると、openpilotを利用中にアクセルを踏むとopenpilotによる運転サポートを中断します。 Show ETA in 24h Format @@ -1003,11 +1003,11 @@ location set Updater Update Required - 更新が必要です + アップデートが必要です An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - オペレーティングシステムのアップデートが必要です。Wi-Fi に接続することで、最速のアップデートを体験できます。ダウンロードサイズは約 1GB です。 + オペレーティングシステムのアップデートが必要です。Wi-Fi に接続してアップデートする事をお勧めします。ダウンロードサイズは約 1GB です。 Connect to Wi-Fi From dbc30c053caacc689e1fafb5e92ff0fcac57db1d Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Thu, 27 Oct 2022 17:27:31 -0700 Subject: [PATCH 0113/1179] UI: fade into wide camera (#26203) * UI: fade into wide camera * handle routes with no wide calib * more cleanup Co-authored-by: Adeeb Shihadeh --- selfdrive/locationd/calibrationd.py | 7 +------ selfdrive/ui/qt/onroad.cc | 8 +++----- selfdrive/ui/qt/widgets/cameraview.cc | 11 ++++++++--- selfdrive/ui/ui.cc | 27 ++++++++++++++++++++++----- selfdrive/ui/ui.h | 4 +++- 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 4e996bc3b9..1c68eb67bd 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -66,7 +66,6 @@ class Calibrator: # Read saved calibration params = Params() calibration_params = params.get("CalibrationParams") - self.wide_camera = params.get_bool('WideCameraOnly') rpy_init = RPY_INIT wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT valid_blocks = 0 @@ -166,10 +165,7 @@ class Calibrator: self.old_rpy_weight = min(0.0, self.old_rpy_weight - 1/SMOOTH_CYCLES) straight_and_fast = ((self.v_ego > MIN_SPEED_FILTER) and (trans[0] > MIN_SPEED_FILTER) and (abs(rot[2]) < MAX_YAW_RATE_FILTER)) - if self.wide_camera: - angle_std_threshold = 4*MAX_VEL_ANGLE_STD - else: - angle_std_threshold = MAX_VEL_ANGLE_STD + angle_std_threshold = MAX_VEL_ANGLE_STD certain_if_calib = ((np.arctan2(trans_std[1], trans[0]) < angle_std_threshold) or (self.valid_blocks < INPUTS_NEEDED)) if not (straight_and_fast and certain_if_calib): @@ -185,7 +181,6 @@ class Calibrator: new_wide_from_device_euler = np.array(wide_from_device_euler) else: new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT - self.rpys[self.block_idx] = (self.idx*self.rpys[self.block_idx] + (BLOCK_SIZE - self.idx) * new_rpy) / float(BLOCK_SIZE) self.wide_from_device_eulers[self.block_idx] = (self.idx*self.wide_from_device_eulers[self.block_idx] + diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 1f677fc92d..346cb3ab96 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -100,10 +100,6 @@ void OnroadWindow::offroadTransition(bool offroad) { #endif alerts->updateAlert({}, bg); - - // update stream type - bool wide_cam = Params().getBool("WideCameraOnly"); - nvg->setStreamType(wide_cam ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); } void OnroadWindow::paintEvent(QPaintEvent *event) { @@ -232,8 +228,10 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { setProperty("rightHandDM", sm["driverMonitoringState"].getDriverMonitoringState().getIsRHD()); } + setStreamType(s.scene.wide_cam ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); if (s.scene.calibration_valid) { - CameraWidget::updateCalibration(s.scene.view_from_calib); + auto calib = s.scene.wide_cam ? s.scene.view_from_wide_calib : s.scene.view_from_calib; + CameraWidget::updateCalibration(calib); } else { CameraWidget::updateCalibration(DEFAULT_CALIBRATION); } diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 4f46497776..13225414d0 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -188,12 +188,17 @@ void CameraWidget::updateFrameMat() { if (stream_type == VISION_STREAM_DRIVER) { frame_mat = get_driver_view_transform(w, h, stream_width, stream_height); } else { - intrinsic_matrix = (stream_type == VISION_STREAM_WIDE_ROAD) ? ecam_intrinsic_matrix : fcam_intrinsic_matrix; - zoom = (stream_type == VISION_STREAM_WIDE_ROAD) ? 2.5 : 1.1; - // Project point at "infinity" to compute x and y offsets // to ensure this ends up in the middle of the screen + // for narrow come and a little lower for wide cam. // TODO: use proper perspective transform? + if (stream_type == VISION_STREAM_WIDE_ROAD) { + intrinsic_matrix = ecam_intrinsic_matrix; + zoom = 2.0; + } else { + intrinsic_matrix = fcam_intrinsic_matrix; + zoom = 1.1; + } const vec3 inf = {{1000., 0., 0.}}; const vec3 Ep = matvecmul3(calibration, inf); const vec3 Kep = matvecmul3(intrinsic_matrix, Ep); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 1a6027bf7f..d1d72b4dad 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -23,8 +23,8 @@ static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, const QRectF clip_region{-margin, -margin, s->fb_w + 2 * margin, s->fb_h + 2 * margin}; const vec3 pt = (vec3){{in_x, in_y, in_z}}; - const vec3 Ep = matvecmul3(s->scene.view_from_calib, pt); - const vec3 KEp = matvecmul3(s->wide_camera ? ecam_intrinsic_matrix : fcam_intrinsic_matrix, Ep); + const vec3 Ep = matvecmul3(s->scene.wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib, pt); + const vec3 KEp = matvecmul3(s->scene.wide_cam ? ecam_intrinsic_matrix : fcam_intrinsic_matrix, Ep); // Project. QPointF point = s->car_space_transform.map(QPointF{KEp.v[0] / KEp.v[2], KEp.v[1] / KEp.v[2]}); @@ -121,17 +121,23 @@ static void update_state(UIState *s) { if (sm.updated("liveCalibration")) { auto rpy_list = sm["liveCalibration"].getLiveCalibration().getRpyCalib(); + auto wfde_list = sm["liveCalibration"].getLiveCalibration().getWideFromDeviceEuler(); Eigen::Vector3d rpy; - rpy << rpy_list[0], rpy_list[1], rpy_list[2]; + Eigen::Vector3d wfde; + if (rpy_list.size() == 3) rpy << rpy_list[0], rpy_list[1], rpy_list[2]; + if (wfde_list.size() == 3) wfde << wfde_list[0], wfde_list[1], wfde_list[2]; Eigen::Matrix3d device_from_calib = euler2rot(rpy); + Eigen::Matrix3d wide_from_device = euler2rot(wfde); Eigen::Matrix3d view_from_device; view_from_device << 0,1,0, 0,0,1, 1,0,0; Eigen::Matrix3d view_from_calib = view_from_device * device_from_calib; + Eigen::Matrix3d view_from_wide_calib = view_from_device * wide_from_device * device_from_calib ; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { scene.view_from_calib.v[i*3 + j] = view_from_calib(i,j); + scene.view_from_wide_calib.v[i*3 + j] = view_from_wide_calib(i,j); } } scene.calibration_valid = sm["liveCalibration"].getLiveCalibration().getCalStatus() == 1; @@ -167,6 +173,17 @@ static void update_state(UIState *s) { scene.light_sensor = std::max(100.0f - scale * sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(), 0.0f); } scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; + + if (sm.updated("carState")) { + float v_ego = sm["carState"].getCarState().getVEgo(); + // TODO: support replays without ecam by using fcam + // Wide or narrow cam dependent on speed + if ((v_ego < 10) || s->wide_cam_only) { + scene.wide_cam = true; + } else if (v_ego > 15) { + scene.wide_cam = false; + } + } } void ui_update_params(UIState *s) { @@ -197,7 +214,7 @@ void UIState::updateStatus() { if (scene.started) { status = STATUS_DISENGAGED; scene.started_frame = sm->frame; - wide_camera = Params().getBool("WideCameraOnly"); + wide_cam_only = Params().getBool("WideCameraOnly"); } started_prev = scene.started; emit offroadTransition(!scene.started); @@ -219,7 +236,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { }); Params params; - wide_camera = params.getBool("WideCameraOnly"); + wide_cam_only = params.getBool("WideCameraOnly"); prime_type = std::atoi(params.get("PrimeType").c_str()); language = QString::fromStdString(params.get("LanguageSetting")); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index f60c26b59a..5a51dda8f8 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -87,7 +87,9 @@ const QColor bg_colors [] = { typedef struct UIScene { bool calibration_valid = false; + bool wide_cam = true; mat3 view_from_calib = DEFAULT_CALIBRATION; + mat3 view_from_wide_calib = DEFAULT_CALIBRATION; cereal::PandaState::PandaType pandaType; // modelV2 @@ -130,7 +132,7 @@ public: QString language; QTransform car_space_transform; - bool wide_camera; + bool wide_cam_only; signals: void uiUpdate(const UIState &s); From f76a390daf677700fbce49253f93412dd44eee0d Mon Sep 17 00:00:00 2001 From: HaraldSchafer Date: Thu, 27 Oct 2022 17:31:15 -0700 Subject: [PATCH 0114/1179] Eliminate toyota close radar glitches causing no resume (#26272) Eliminate toyota close radar glitches --- selfdrive/controls/lib/radar_helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/radar_helpers.py b/selfdrive/controls/lib/radar_helpers.py index bf788190cd..4bb0179267 100644 --- a/selfdrive/controls/lib/radar_helpers.py +++ b/selfdrive/controls/lib/radar_helpers.py @@ -151,7 +151,8 @@ class Cluster(): def potential_low_speed_lead(self, v_ego): # stop for stuff in front of you and low speed, even without model confirmation - return abs(self.yRel) < 1.0 and (v_ego < v_ego_stationary) and self.dRel < 25 + # Radar points closer than 0.75, are almost always glitches on toyota radars + return abs(self.yRel) < 1.0 and (v_ego < v_ego_stationary) and (0.75 < self.dRel < 25) def is_potential_fcw(self, model_prob): return model_prob > .9 From 6698cd48294e94fdb4e09e8943e6505efa29c5d5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 27 Oct 2022 20:53:15 -0700 Subject: [PATCH 0115/1179] controlsd: steer in old preEnable state (#26269) * controlsd: steer in old preEnable state * bump panda * bump panda * Update ref_commit Co-authored-by: Shane Smiskol --- panda | 2 +- selfdrive/controls/controlsd.py | 3 +-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/panda b/panda index bd8d2481dd..187fdee385 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit bd8d2481dd071df62263e093b2e332a2a404dc87 +Subproject commit 187fdee385e59a2a19f85760f529e8e381845dff diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 5172cc4044..1adbba4171 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -254,8 +254,7 @@ class Controls: self.events.add(EventName.pedalPressed) if CS.gasPressed: - self.events.add(EventName.pedalPressedPreEnable if self.disengage_on_accelerator else - EventName.gasPressedOverride) + self.events.add(EventName.gasPressedOverride) if not self.CP.notCar: self.events.add_from_msg(self.sm['driverMonitoringState'].events) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index fad9f5e598..c7d81c3496 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f4ea2499a95e198914fd275a8380178e8ff65a31 \ No newline at end of file +e56c5a6ac5b87ee6083c9f92921e7198591f7b5d From 8de9bbaa73ea94b966b1161fb630bf3cac72c764 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 29 Oct 2022 01:55:05 +0800 Subject: [PATCH 0116/1179] Cabana: improve track line (#26231) * improve track line * show text label on the left if reach the right edge * cleanup * cleanup --- tools/cabana/chartswidget.cc | 42 ++++++++++++++++++++++-------------- tools/cabana/chartswidget.h | 6 ++++-- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3f1dd890c3..a3cbaf5b30 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -147,7 +147,7 @@ void ChartsWidget::addChart(const QString &id, const Signal *sig) { if (it == charts.end()) { auto chart = new ChartWidget(id, sig, this); chart->chart_view->updateSeries(display_range); - QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(chart); });; + QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(chart); }); QObject::connect(chart->chart_view, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); QObject::connect(chart->chart_view, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); charts_layout->insertWidget(0, chart); @@ -184,7 +184,6 @@ void ChartsWidget::signalUpdated(const Signal *sig) { } } - bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { if (obj != this && event->type() == QEvent::Close) { emit dock_btn->clicked(); @@ -256,10 +255,12 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) track_line = new QGraphicsLineItem(chart); track_line->setZValue(chart->zValue() + 10); - track_line->setPen(QPen(Qt::gray, 1, Qt::DashLine)); - value_text = new QGraphicsSimpleTextItem(chart); + track_line->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); + track_ellipse = new QGraphicsEllipseItem(chart); + track_ellipse->setZValue(chart->zValue() + 10); + track_ellipse->setBrush(Qt::darkGray); + value_text = new QGraphicsTextItem(chart); value_text->setZValue(chart->zValue() + 10); - value_text->setBrush(Qt::gray); line_marker = new QGraphicsLineItem(chart); line_marker->setZValue(chart->zValue() + 10); @@ -364,12 +365,14 @@ void ChartView::updateAxisY() { void ChartView::enterEvent(QEvent *event) { track_line->setVisible(true); value_text->setVisible(true); + track_ellipse->setVisible(true); QChartView::enterEvent(event); } void ChartView::leaveEvent(QEvent *event) { track_line->setVisible(false); value_text->setVisible(false); + track_ellipse->setVisible(false); QChartView::leaveEvent(event); } @@ -397,21 +400,28 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); - bool dragging = rubber && rubber->isVisible(); - if (!dragging) { + bool is_zooming = rubber && rubber->isVisible(); + if (!is_zooming) { const auto plot_area = chart()->plotArea(); - float x = std::clamp((float)ev->pos().x(), (float)plot_area.left(), (float)plot_area.right()); - track_line->setLine(x, plot_area.top(), x, plot_area.bottom()); - auto axis_x = dynamic_cast(chart()->axisX()); - double sec = axis_x->min() + ((x - plot_area.x()) / plot_area.width()) * (axis_x->max() - axis_x->min()); - auto value = std::lower_bound(vals.begin(), vals.end(), sec, [](auto &p, double x) { return p.x() < x; }); - value_text->setPos(x + 6, plot_area.bottom() - 25); + 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()) { - value_text->setText(QString("(%1, %2)").arg(value->x(), 0, 'f', 3).arg(value->y())); - } else { - value_text->setText("(--, --)"); + QPointF pos = chart()->mapToPosition((*value)); + 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; + } + value_text->setPos(text_x, pos.y() - 10); } + track_line->setVisible(value != vals.end()); + value_text->setVisible(value != vals.end()); + track_ellipse->setVisible(value != vals.end()); } QChartView::mouseMoveEvent(ev); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 897ed62c2f..60081dd882 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -3,8 +3,9 @@ #include #include +#include #include -#include +#include #include #include #include @@ -38,7 +39,8 @@ private: void updateAxisY(); QGraphicsLineItem *track_line; - QGraphicsSimpleTextItem *value_text; + QGraphicsEllipseItem *track_ellipse; + QGraphicsTextItem *value_text; QGraphicsLineItem *line_marker; QList vals; QString id; From 8f70a84a417f848793f87d6c79c25f3ce15d5d38 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 28 Oct 2022 23:43:12 +0200 Subject: [PATCH 0117/1179] QuectelGPS: add supl server (#26259) add supl server Co-authored-by: Kurt Nistelberger --- selfdrive/sensord/rawgps/rawgpsd.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/sensord/rawgps/rawgpsd.py b/selfdrive/sensord/rawgps/rawgpsd.py index fa23a161c4..1c65051665 100755 --- a/selfdrive/sensord/rawgps/rawgpsd.py +++ b/selfdrive/sensord/rawgps/rawgpsd.py @@ -124,6 +124,7 @@ def setup_quectel(diag: ModemDiag): # don't automatically turn on GNSS on powerup at_cmd("AT+QGPSCFG=\"autogps\",0") + at_cmd("AT+QGPSSUPLURL=\"supl.google.com:7275\"") at_cmd("AT+QGPSCFG=\"outport\",\"usbnmea\"") at_cmd("AT+QGPS=1") From 5ae213142459a64aac8a1654d1087346b17b87c1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 28 Oct 2022 17:26:25 -0700 Subject: [PATCH 0118/1179] bump opendbc (#26277) --- opendbc | 2 +- selfdrive/car/hyundai/carstate.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/opendbc b/opendbc index a95b0ae8a5..526e21da66 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit a95b0ae8a5244a9d6311bf72aa2a7d63d41b4a9f +Subproject commit 526e21da666aeeabcf2369c66903a5675fdf933b diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index ec2b3059a3..2e4cb0d25a 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -507,7 +507,6 @@ class CarState(CarStateBase): ("ZEROS_5", "CRUISE_INFO"), ("DISTANCE_SETTING", "CRUISE_INFO"), ("SET_SPEED", "CRUISE_INFO"), - ("NEW_SIGNAL_4", "CRUISE_INFO"), ] checks = [ From 602b90f518e9bc51dccdb75413ff86481dff277d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 29 Oct 2022 10:05:11 +0800 Subject: [PATCH 0119/1179] UI: reduce frame drops. (#26266) * reduce frame dropping * This mode will not draw the same frame twice * cleanup comment * use previous texture if update is not triggered by vipc thread and without new frame --- selfdrive/ui/qt/widgets/cameraview.cc | 32 ++++++++++----------------- selfdrive/ui/qt/widgets/cameraview.h | 1 - 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 13225414d0..d7591633c9 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -240,24 +240,13 @@ void CameraWidget::paintGL() { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); std::lock_guard lk(frame_lock); - if (frames.empty()) return; - int frame_idx = frames.size() - 1; - - // Always draw latest frame until sync logic is more stable - // for (frame_idx = 0; frame_idx < frames.size() - 1; frame_idx++) { - // if (frames[frame_idx].first == draw_frame_id) break; - // } - - // Log duplicate/dropped frames - if (frames[frame_idx].first == prev_frame_id) { - qDebug() << "Drawing same frame twice" << frames[frame_idx].first; - } else if (frames[frame_idx].first != prev_frame_id + 1) { - qDebug() << "Skipped frame" << frames[frame_idx].first; + // use previous texture if update() is called without new frame. + VisionBuf *frame = nullptr; + if (!frames.empty()) { + frame = frames.front().second; + frames.pop_front(); } - prev_frame_id = frames[frame_idx].first; - VisionBuf *frame = frames[frame_idx].second; - assert(frame != nullptr); glViewport(0, 0, width(), height()); glBindVertexArray(frame_vao); @@ -266,19 +255,21 @@ void CameraWidget::paintGL() { #ifdef QCOM2 glActiveTexture(GL_TEXTURE0); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_images[frame->idx]); - assert(glGetError() == GL_NO_ERROR); + if (frame) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_images[frame->idx]); + assert(glGetError() == GL_NO_ERROR); + } #else glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width, stream_height, GL_RED, GL_UNSIGNED_BYTE, frame->y); + if (frame) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width, stream_height, GL_RED, GL_UNSIGNED_BYTE, frame->y); assert(glGetError() == GL_NO_ERROR); glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride/2); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, textures[1]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width/2, stream_height/2, GL_RG, GL_UNSIGNED_BYTE, frame->uv); + if (frame) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width/2, stream_height/2, GL_RG, GL_UNSIGNED_BYTE, frame->uv); assert(glGetError() == GL_NO_ERROR); #endif @@ -375,6 +366,7 @@ void CameraWidget::vipcThread() { std::lock_guard lk(frame_lock); frames.push_back(std::make_pair(meta_main.frame_id, buf)); while (frames.size() > FRAME_BUFFER_SIZE) { + qDebug() << "Skipped frame" << frames.front().first; frames.pop_front(); } } diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index ef828f8ff6..aff3abc836 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -81,7 +81,6 @@ protected: std::mutex frame_lock; std::deque> frames; uint32_t draw_frame_id = 0; - uint32_t prev_frame_id = 0; protected slots: void vipcConnected(VisionIpcClient *vipc_client); From a622e523b2251472aa59b80eee60cae9fcb1e024 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 29 Oct 2022 12:44:51 +0800 Subject: [PATCH 0120/1179] Cabana: add tab context menu for 'close other tabs' (#26279) close other tabs --- tools/cabana/detailwidget.cc | 45 ++++++++++++++++++++++++++++-------- tools/cabana/detailwidget.h | 2 +- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 7290e4e6ff..8839cdd509 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -22,6 +23,7 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { tabbar->setDrawBase(false); tabbar->setUsesScrollButtons(true); tabbar->setAutoHide(true); + tabbar->setContextMenuPolicy(Qt::CustomContextMenu); main_layout->addWidget(tabbar); // message title @@ -79,22 +81,47 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { dbcMsgChanged(); }); - QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { setMessage(messages[index]); }); - QObject::connect(tabbar, &QTabBar::tabCloseRequested, [=](int index) { - messages.removeAt(index); - tabbar->removeTab(index); - setMessage(messages.isEmpty() ? "" : messages[0]); + QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); + QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { + if (index != -1 && tabbar->tabText(index) != msg_id) { + setMessage(tabbar->tabText(index)); + } }); + QObject::connect(tabbar, &QTabBar::tabCloseRequested, [=](int index) { + if (tabbar->currentIndex() == index) { + tabbar->setCurrentIndex(index == tabbar->count() - 1 ? index - 1 : index + 1); + } + tabbar->removeTab(index); + }); +} + +void DetailWidget::showTabBarContextMenu(const QPoint &pt) { + int index = tabbar->tabAt(pt); + if (index >= 0) { + QMenu menu(this); + menu.addAction(tr("Close Other Tabs")); + if (menu.exec(tabbar->mapToGlobal(pt))) { + for (int i = tabbar->count() - 1; i >= 0; --i) { + if (i != index) + tabbar->removeTab(i); + } + } + } } void DetailWidget::setMessage(const QString &message_id) { if (message_id.isEmpty()) return; - int index = messages.indexOf(message_id); + qWarning() << "setmessage" << message_id; + int index = -1; + for (int i = 0; i < tabbar->count(); ++i) { + if (tabbar->tabText(i) == message_id) { + index = i; + break; + } + } if (index == -1) { - messages.push_back(message_id); - tabbar->addTab(message_id); - index = tabbar->count() - 1; + index = tabbar->addTab(message_id); auto msg = dbc()->msg(message_id); tabbar->setTabToolTip(index, msg ? msg->name.c_str() : "untitled"); } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 5924cdd43f..4ec74eca7e 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -39,6 +39,7 @@ signals: void removeChart(const Signal *sig); private: + void showTabBarContextMenu(const QPoint &pt); void addSignal(int start_bit, int to); void resizeSignal(const Signal *sig, int from, int to); void saveSignal(const Signal *sig, const Signal &new_sig); @@ -53,7 +54,6 @@ private: QPushButton *edit_btn; QWidget *signals_container; QTabBar *tabbar; - QStringList messages; HistoryLog *history_log; BinaryView *binary_view; ScrollArea *scroll; From 5aa0d211f075681e18395d0fd7dd73d8cc44573c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 30 Oct 2022 03:01:08 +0800 Subject: [PATCH 0121/1179] Cabana: double click the title bar to move binview to a separate column (#26280) * double click to move binview to seperate column * cleanup * double click frame * continue * rename signal * add tooltip * fix layout * don't show last cell's bottom line * increase spliter handle size * cleanup * set resize mode to ResizeToContents * add a split button * cleanup layout&fix space * cleanup * remove hardcoded size * cleanup --- tools/cabana/binaryview.cc | 12 +++++---- tools/cabana/binaryview.h | 1 + tools/cabana/detailwidget.cc | 52 ++++++++++++++++++++++++++++-------- tools/cabana/detailwidget.h | 17 ++++++++++++ tools/cabana/mainwin.cc | 14 +++++----- tools/cabana/mainwin.h | 4 ++- 6 files changed, 75 insertions(+), 25 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 26fecd8c38..91353e9726 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -20,13 +20,15 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { setItemDelegate(delegate); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->hide(); - verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); + verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setMouseTracking(true); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); +} - QObject::connect(model, &QAbstractItemModel::modelReset, [this]() { - setFixedHeight((CELL_HEIGHT + 1) * std::min(model->rowCount(), 8) + 2); - }); +QSize BinaryView::sizeHint() const { + QSize sz = QTableView::sizeHint(); + return {sz.width(), model->rowCount() <= 8 ? ((CELL_HEIGHT + 1) * model->rowCount() + 2) : sz.height()}; } void BinaryView::highlight(const Signal *sig) { @@ -108,9 +110,9 @@ void BinaryView::leaveEvent(QEvent *event) { void BinaryView::setMessage(const QString &message_id) { msg_id = message_id; model->setMessage(message_id); - resizeRowsToContents(); clearSelection(); updateState(); + updateGeometry(); } void BinaryView::updateState() { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 0f58e9ed20..060a2eef7f 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -61,6 +61,7 @@ public: void highlight(const Signal *sig); const Signal *hoveredSignal() const { return hovered_sig; } QSet getOverlappingSignals() const; + QSize sizeHint() const override; signals: void signalHovered(const Signal *sig); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 8839cdd509..69b420483d 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -13,10 +13,18 @@ // DetailWidget DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout = new QHBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); - main_layout->setSpacing(0); + right_column = new QVBoxLayout(); + main_layout->addLayout(right_column); + + binary_view_container = new QWidget(this); + binary_view_container->setMinimumWidth(500); + binary_view_container->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + QVBoxLayout *bin_layout = new QVBoxLayout(binary_view_container); + bin_layout->setContentsMargins(0, 0, 0, 0); + bin_layout->setSpacing(0); // tabbar tabbar = new QTabBar(this); tabbar->setTabsClosable(true); @@ -24,14 +32,19 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { tabbar->setUsesScrollButtons(true); tabbar->setAutoHide(true); tabbar->setContextMenuPolicy(Qt::CustomContextMenu); - main_layout->addWidget(tabbar); + bin_layout->addWidget(tabbar); + + TitleFrame *title_frame = new TitleFrame(this); + title_frame->setFrameShape(QFrame::StyledPanel); + title_frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); // message title - QFrame *title_frame = new QFrame(); - main_layout->addWidget(title_frame); - QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); - title_frame->setFrameShape(QFrame::StyledPanel); QHBoxLayout *title_layout = new QHBoxLayout(); + split_btn = new QPushButton("⬅", this); + split_btn->setFixedSize(20, 20); + split_btn->setToolTip(tr("Split to two columns")); + title_layout->addWidget(split_btn); title_layout->addWidget(new QLabel("time:")); time_label = new QLabel(this); time_label->setStyleSheet("font-weight:bold"); @@ -56,10 +69,12 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); warning_widget->hide(); frame_layout->addWidget(warning_widget); + bin_layout->addWidget(title_frame); // binary view binary_view = new BinaryView(this); - main_layout->addWidget(binary_view, 0, Qt::AlignTop); + bin_layout->addWidget(binary_view); + right_column->addWidget(binary_view_container); // signals signals_container = new QWidget(this); @@ -70,12 +85,14 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { scroll->setWidget(signals_container); scroll->setWidgetResizable(true); scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - main_layout->addWidget(scroll); + right_column->addWidget(scroll); // history log history_log = new HistoryLog(this); - main_layout->addWidget(history_log); + right_column->addWidget(history_log); + QObject::connect(split_btn, &QPushButton::clicked, this, &DetailWidget::moveBinaryView); + QObject::connect(title_frame, &TitleFrame::doubleClicked, this, &DetailWidget::moveBinaryView); QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg); QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); @@ -112,7 +129,6 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { void DetailWidget::setMessage(const QString &message_id) { if (message_id.isEmpty()) return; - qWarning() << "setmessage" << message_id; int index = -1; for (int i = 0; i < tabbar->count(); ++i) { if (tabbar->tabText(i) == message_id) { @@ -182,6 +198,20 @@ void DetailWidget::updateState() { history_log->updateState(); } +void DetailWidget::moveBinaryView() { + if (binview_in_left_col) { + right_column->insertWidget(0, binary_view_container); + emit binaryViewMoved(true); + } else { + main_layout->insertWidget(0, binary_view_container); + emit binaryViewMoved(false); + } + split_btn->setText(binview_in_left_col ? "⬅" : "➡"); + split_btn->setToolTip(binview_in_left_col ? tr("Split to two columns") : tr("Move back")); + binary_view->updateGeometry(); + binview_in_left_col = !binview_in_left_col; +} + void DetailWidget::showForm() { SignalEdit *sender = qobject_cast(QObject::sender()); for (auto f : signals_container->findChildren()) { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 4ec74eca7e..3f042bf2b8 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -2,11 +2,21 @@ #include #include +#include #include "tools/cabana/binaryview.h" #include "tools/cabana/historylog.h" #include "tools/cabana/signaledit.h" +class TitleFrame : public QFrame { + Q_OBJECT +public: + TitleFrame(QWidget *parent) : QFrame(parent) {} + void mouseDoubleClickEvent(QMouseEvent *e) { emit doubleClicked(); } +signals: + void doubleClicked(); +}; + class EditMessageDialog : public QDialog { Q_OBJECT @@ -37,6 +47,7 @@ public: signals: void showChart(const QString &msg_id, const Signal *sig); void removeChart(const Signal *sig); + void binaryViewMoved(bool in); private: void showTabBarContextMenu(const QPoint &pt); @@ -47,6 +58,7 @@ private: void editMsg(); void showForm(); void updateState(); + void moveBinaryView(); QString msg_id; QLabel *name_label, *time_label, *warning_label; @@ -54,6 +66,11 @@ private: QPushButton *edit_btn; QWidget *signals_container; QTabBar *tabbar; + QHBoxLayout *main_layout; + QVBoxLayout *right_column; + bool binview_in_left_col = false; + QWidget *binary_view_container; + QPushButton *split_btn; HistoryLog *history_log; BinaryView *binary_view; ScrollArea *scroll; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index f127e5f52b..71ec873551 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -3,14 +3,13 @@ #include #include #include -#include #include #include "tools/replay/util.h" static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - if (main_win) main_win->showStatusMessage(msg); + if (main_win) emit main_win->showMessage(msg, 0); } MainWindow::MainWindow() : QWidget() { @@ -22,15 +21,14 @@ MainWindow::MainWindow() : QWidget() { h_layout->setContentsMargins(0, 0, 0, 0); main_layout->addLayout(h_layout); - QSplitter *splitter = new QSplitter(Qt::Horizontal, this); - splitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + splitter = new QSplitter(Qt::Horizontal, this); + splitter->setHandleWidth(11); messages_widget = new MessagesWidget(this); splitter->addWidget(messages_widget); detail_widget = new DetailWidget(this); splitter->addWidget(detail_widget); - splitter->setSizes({100, 500}); h_layout->addWidget(splitter); // right widgets @@ -74,16 +72,17 @@ MainWindow::MainWindow() : QWidget() { qRegisterMetaType("ReplyMsgType"); installMessageHandler([this](ReplyMsgType type, const std::string msg) { // use queued connection to recv the log messages from replay. - emit logMessageFromReplay(QString::fromStdString(msg), 3000); + emit showMessage(QString::fromStdString(msg), 3000); }); installDownloadProgressHandler([this](uint64_t cur, uint64_t total, bool success) { emit updateProgressBar(cur, total, success); }); - QObject::connect(this, &MainWindow::logMessageFromReplay, status_bar, &QStatusBar::showMessage); + QObject::connect(this, &MainWindow::showMessage, status_bar, &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); QObject::connect(detail_widget, &DetailWidget::showChart, charts_widget, &ChartsWidget::addChart); + QObject::connect(detail_widget, &DetailWidget::binaryViewMoved, [this](bool in) { splitter->setSizes({in ? 100 : 0, 500}); }); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); QObject::connect(settings_btn, &QPushButton::clicked, this, &MainWindow::setOption); @@ -103,7 +102,6 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe } } - void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 63f704dcc8..b77744ba9c 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "tools/cabana/chartswidget.h" @@ -17,7 +18,7 @@ public: void showStatusMessage(const QString &msg, int timeout = 0) { status_bar->showMessage(msg, timeout); } signals: - void logMessageFromReplay(const QString &msg, int timeout); + void showMessage(const QString &msg, int timeout); void updateProgressBar(uint64_t cur, uint64_t total, bool success); protected: @@ -29,6 +30,7 @@ protected: MessagesWidget *messages_widget; DetailWidget *detail_widget; ChartsWidget *charts_widget; + QSplitter *splitter; QWidget *floating_window = nullptr; QVBoxLayout *r_layout; QProgressBar *progress_bar; From 9377448888c181674fdc1b1aa8c3bc485156d3d2 Mon Sep 17 00:00:00 2001 From: Rohit Bernard <43088347+RohitBernard@users.noreply.github.com> Date: Sat, 29 Oct 2022 13:20:37 -0700 Subject: [PATCH 0122/1179] sim: Converting RGB frames to NV12 format in OpenCL (#26169) * convert carla rgb frames to nv12 * code cleanup * move kernel Co-authored-by: Adeeb Shihadeh --- tools/sim/bridge.py | 5 +- .../rgb_to_yuv.cl => tools/sim/rgb_to_nv12.cl | 46 ++++++++----------- 2 files changed, 21 insertions(+), 30 deletions(-) rename system/camerad/transforms/rgb_to_yuv.cl => tools/sim/rgb_to_nv12.cl (75%) diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index a105ed751e..f72927ba9a 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -82,11 +82,10 @@ class Camerad: self.queue = cl.CommandQueue(self.ctx) cl_arg = f" -DHEIGHT={H} -DWIDTH={W} -DRGB_STRIDE={W * 3} -DUV_WIDTH={W // 2} -DUV_HEIGHT={H // 2} -DRGB_SIZE={W * H} -DCL_DEBUG " - # TODO: move rgb_to_yuv.cl to local dir once the frame stream camera is removed - kernel_fn = os.path.join(BASEDIR, "system", "camerad", "transforms", "rgb_to_yuv.cl") + kernel_fn = os.path.join(BASEDIR, "tools/sim/rgb_to_nv12.cl") with open(kernel_fn) as f: prg = cl.Program(self.ctx, f.read()).build(cl_arg) - self.krnl = prg.rgb_to_yuv + self.krnl = prg.rgb_to_nv12 self.Wdiv4 = W // 4 if (W % 4 == 0) else (W + (4 - W % 4)) // 4 self.Hdiv4 = H // 4 if (H % 4 == 0) else (H + (4 - H % 4)) // 4 diff --git a/system/camerad/transforms/rgb_to_yuv.cl b/tools/sim/rgb_to_nv12.cl similarity index 75% rename from system/camerad/transforms/rgb_to_yuv.cl rename to tools/sim/rgb_to_nv12.cl index 60dbdb4d5e..54816d5d7d 100644 --- a/system/camerad/transforms/rgb_to_yuv.cl +++ b/tools/sim/rgb_to_nv12.cl @@ -29,23 +29,21 @@ inline void convert_4_ys(__global uchar * out_yuv, int yi, const uchar8 rgbs1, c vstore4(yy, 0, out_yuv + yi); } -inline void convert_uv(__global uchar * out_yuv, int ui, int vi, +inline void convert_uv(__global uchar * out_yuv, int uvi, const uchar8 rgbs1, const uchar8 rgbs2) { // U & V: average of 2x2 pixels square const short ab = AVERAGE(rgbs1.s0, rgbs1.s3, rgbs2.s0, rgbs2.s3); const short ag = AVERAGE(rgbs1.s1, rgbs1.s4, rgbs2.s1, rgbs2.s4); const short ar = AVERAGE(rgbs1.s2, rgbs1.s5, rgbs2.s2, rgbs2.s5); #ifdef CL_DEBUG - if(ui >= RGB_SIZE + RGB_SIZE / 4) - printf("U overflow, %d >= %d\n", ui, RGB_SIZE + RGB_SIZE / 4); - if(vi >= RGB_SIZE + RGB_SIZE / 2) - printf("V overflow, %d >= %d\n", vi, RGB_SIZE + RGB_SIZE / 2); + if(uvi >= RGB_SIZE + RGB_SIZE / 2) + printf("UV overflow, %d >= %d\n", uvi, RGB_SIZE + RGB_SIZE / 2); #endif - out_yuv[ui] = RGB_TO_U(ar, ag, ab); - out_yuv[vi] = RGB_TO_V(ar, ag, ab); + out_yuv[uvi] = RGB_TO_U(ar, ag, ab); + out_yuv[uvi+1] = RGB_TO_V(ar, ag, ab); } -inline void convert_2_uvs(__global uchar * out_yuv, int ui, int vi, +inline void convert_2_uvs(__global uchar * out_yuv, int uvi, const uchar8 rgbs1, const uchar8 rgbs2, const uchar8 rgbs3, const uchar8 rgbs4) { // U & V: average of 2x2 pixels square const short ab1 = AVERAGE(rgbs1.s0, rgbs1.s3, rgbs2.s0, rgbs2.s3); @@ -54,25 +52,20 @@ inline void convert_2_uvs(__global uchar * out_yuv, int ui, int vi, const short ab2 = AVERAGE(rgbs1.s6, rgbs3.s1, rgbs2.s6, rgbs4.s1); const short ag2 = AVERAGE(rgbs1.s7, rgbs3.s2, rgbs2.s7, rgbs4.s2); const short ar2 = AVERAGE(rgbs3.s0, rgbs3.s3, rgbs4.s0, rgbs4.s3); - uchar2 u2 = (uchar2)( + uchar4 uv = (uchar4)( RGB_TO_U(ar1, ag1, ab1), - RGB_TO_U(ar2, ag2, ab2) - ); - uchar2 v2 = (uchar2)( RGB_TO_V(ar1, ag1, ab1), + RGB_TO_U(ar2, ag2, ab2), RGB_TO_V(ar2, ag2, ab2) ); #ifdef CL_DEBUG1 - if(ui > RGB_SIZE + RGB_SIZE / 4 - 2) - printf("U 2 overflow, %d >= %d\n", ui, RGB_SIZE + RGB_SIZE / 4 - 2); - if(vi > RGB_SIZE + RGB_SIZE / 2 - 2) - printf("V 2 overflow, %d >= %d\n", vi, RGB_SIZE + RGB_SIZE / 2 - 2); + if(uvi > RGB_SIZE + RGB_SIZE / 2 - 4) + printf("UV2 overflow, %d >= %d\n", uvi, RGB_SIZE + RGB_SIZE / 2 - 2); #endif - vstore2(u2, 0, out_yuv + ui); - vstore2(v2, 0, out_yuv + vi); + vstore4(uv, 0, out_yuv + uvi); } -__kernel void rgb_to_yuv(__global uchar const * const rgb, +__kernel void rgb_to_nv12(__global uchar const * const rgb, __global uchar * out_yuv) { const int dx = get_global_id(0); @@ -81,8 +74,7 @@ __kernel void rgb_to_yuv(__global uchar const * const rgb, const int row = mul24(dy, 4); // Current row in rgb image const int bgri_start = mad24(row, RGB_STRIDE, mul24(col, 3)); // Start offset of rgb data being converted const int yi_start = mad24(row, WIDTH, col); // Start offset in the target yuv buffer - int ui = mad24(row / 2, UV_WIDTH, RGB_SIZE + col / 2); - int vi = mad24(row / 2 , UV_WIDTH, RGB_SIZE + UV_WIDTH * UV_HEIGHT + col / 2); + int uvi = mad24(row / 2, WIDTH, RGB_SIZE + col); int num_col = min(WIDTH - col, 4); int num_row = min(HEIGHT - row, 4); if(num_row == 4) { @@ -99,15 +91,15 @@ __kernel void rgb_to_yuv(__global uchar const * const rgb, convert_4_ys(out_yuv, yi_start + WIDTH, rgbs1_0, rgbs1_1); convert_4_ys(out_yuv, yi_start + WIDTH * 2, rgbs2_0, rgbs2_1); convert_4_ys(out_yuv, yi_start + WIDTH * 3, rgbs3_0, rgbs3_1); - convert_2_uvs(out_yuv, ui, vi, rgbs0_0, rgbs1_0, rgbs0_1, rgbs1_1); - convert_2_uvs(out_yuv, ui + UV_WIDTH, vi + UV_WIDTH, rgbs2_0, rgbs3_0, rgbs2_1, rgbs3_1); + convert_2_uvs(out_yuv, uvi, rgbs0_0, rgbs1_0, rgbs0_1, rgbs1_1); + convert_2_uvs(out_yuv, uvi + WIDTH, rgbs2_0, rgbs3_0, rgbs2_1, rgbs3_1); } else if(num_col == 2) { convert_2_ys(out_yuv, yi_start, rgbs0_0); convert_2_ys(out_yuv, yi_start + WIDTH, rgbs1_0); convert_2_ys(out_yuv, yi_start + WIDTH * 2, rgbs2_0); convert_2_ys(out_yuv, yi_start + WIDTH * 3, rgbs3_0); - convert_uv(out_yuv, ui, vi, rgbs0_0, rgbs1_0); - convert_uv(out_yuv, ui + UV_WIDTH, vi + UV_WIDTH, rgbs2_0, rgbs3_0); + convert_uv(out_yuv, uvi, rgbs0_0, rgbs1_0); + convert_uv(out_yuv, uvi + WIDTH, rgbs2_0, rgbs3_0); } } else { const uchar8 rgbs0_0 = vload8(0, rgb + bgri_start); @@ -117,11 +109,11 @@ __kernel void rgb_to_yuv(__global uchar const * const rgb, if(num_col == 4) { convert_4_ys(out_yuv, yi_start, rgbs0_0, rgbs0_1); convert_4_ys(out_yuv, yi_start + WIDTH, rgbs1_0, rgbs1_1); - convert_2_uvs(out_yuv, ui, vi, rgbs0_0, rgbs1_0, rgbs0_1, rgbs1_1); + convert_2_uvs(out_yuv, uvi, rgbs0_0, rgbs1_0, rgbs0_1, rgbs1_1); } else if(num_col == 2) { convert_2_ys(out_yuv, yi_start, rgbs0_0); convert_2_ys(out_yuv, yi_start + WIDTH, rgbs1_0); - convert_uv(out_yuv, ui, vi, rgbs0_0, rgbs1_0); + convert_uv(out_yuv, uvi, rgbs0_0, rgbs1_0); } } } From 5de54c35a9017454982c1deda973a8519968d854 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 29 Oct 2022 13:28:14 -0700 Subject: [PATCH 0123/1179] cabana: fix settings titles --- tools/cabana/settings.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 93bc05f20b..17299ebca4 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -55,19 +55,19 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { cached_segment->setRange(3, 60); cached_segment->setSingleStep(1); cached_segment->setValue(settings.cached_segment_limit); - form_layout->addRow(tr("Cached segments limit(minute)"), cached_segment); + form_layout->addRow(tr("Cached segments limit"), cached_segment); max_chart_x_range = new QSpinBox(this); max_chart_x_range->setRange(1, 60); max_chart_x_range->setSingleStep(1); max_chart_x_range->setValue(settings.max_chart_x_range / 60); - form_layout->addRow(tr("Chart's max X-axis range(minute)"), max_chart_x_range); + form_layout->addRow(tr("Chart range (minutes)"), max_chart_x_range); 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's height"), chart_height); + form_layout->addRow(tr("Chart height"), chart_height); chart_theme = new QComboBox(); chart_theme->addItems({"Light", "Dark"}); From 80b088c332808439ea9cfe23557fae5a86fb075c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 30 Oct 2022 22:31:12 +0800 Subject: [PATCH 0124/1179] Cabana: add save DBC dialog (#26282) * export DBC to text edit * added saveAs & Copy To Clipboard * cleanup * cleanup include * add test case * rename variable * fix precision --- .github/workflows/selfdrive_tests.yaml | 1 + tools/cabana/.gitignore | 2 +- tools/cabana/SConscript | 6 ++- tools/cabana/dbcmanager.cc | 21 +++++++- tools/cabana/dbcmanager.h | 4 +- tools/cabana/messageswidget.cc | 67 ++++++++++++++++++++++---- tools/cabana/messageswidget.h | 11 +++++ tools/cabana/tests/test_cabana | 4 ++ tools/cabana/tests/test_cabana.cc | 35 ++++++++++++++ tools/cabana/tests/test_runner.cc | 10 ++++ 10 files changed, 146 insertions(+), 15 deletions(-) create mode 100755 tools/cabana/tests/test_cabana create mode 100644 tools/cabana/tests/test_cabana.cc create mode 100644 tools/cabana/tests/test_runner.cc diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index e921cd3d00..598f2c592b 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -232,6 +232,7 @@ jobs: ./selfdrive/loggerd/tests/test_logger &&\ ./system/proclogd/tests/test_proclog && \ ./tools/replay/tests/test_replay && \ + ./tools/cabana/tests/test_cabana && \ ./system/camerad/test/ae_gray_test && \ coverage xml" - name: "Upload coverage to Codecov" diff --git a/tools/cabana/.gitignore b/tools/cabana/.gitignore index d7a552eabb..73879ab05d 100644 --- a/tools/cabana/.gitignore +++ b/tools/cabana/.gitignore @@ -4,4 +4,4 @@ moc_* _cabana settings car_fingerprint_to_dbc.json - +tests/_test_cabana diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 4e4e11dbd8..b7321e1f8d 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -18,5 +18,9 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_env.Execute('./generate_dbc_json.py --out car_fingerprint_to_dbc.json') -cabana_env.Program('_cabana', ['cabana.cc', 'mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', 'canmessages.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) +cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + +if GetOption('test'): + cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index c3fbab0349..479b14afec 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -28,8 +28,25 @@ void DBCManager::open(const QString &name, const QString &content) { emit DBCFileChanged(); } -void save(const QString &dbc_file_name) { - // TODO: save DBC to file +QString DBCManager::generateDBC() { + if (!dbc) return {}; + + QString dbc_string; + for (auto &m : dbc->msgs) { + dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(m.address).arg(m.name.c_str()).arg(m.size); + for (auto &sig : m.sigs) { + dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [0|0] \"\" XXX\n") + .arg(sig.name.c_str()) + .arg(sig.start_bit) + .arg(sig.size) + .arg(sig.is_little_endian ? '1' : '0') + .arg(sig.is_signed ? '-' : '+') + .arg(sig.factor, 0, 'g', 20) + .arg(sig.offset); + } + dbc_string += "\n"; + } + return dbc_string; } void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size) { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 9e64c4ed53..913445d44e 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -13,8 +13,7 @@ public: void open(const QString &dbc_file_name); void open(const QString &name, const QString &content); - void save(const QString &dbc_file_name); - + QString generateDBC(); 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); @@ -24,6 +23,7 @@ public: inline QString name() const { return dbc_name; } void updateMsg(const QString &id, const QString &name, uint32_t size); + inline const DBC *getDBC() const { return dbc; } inline const Msg *msg(const QString &id) const { return msg(addressFromId(id)); } inline const Msg *msg(uint32_t address) const { auto it = msg_map.find(address); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 4975061cc5..4d97bba589 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -69,9 +71,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &CANMessages::updated, [this]() { model->updateState(); }); QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadDBCFromPaste); - QObject::connect(save_btn, &QPushButton::clicked, [=]() { - // TODO: save DBC to file - }); + QObject::connect(save_btn, &QPushButton::clicked, this, &MessagesWidget::saveDBC); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid()) { emit msgSelectionChanged(current.data(Qt::UserRole).toString()); @@ -79,7 +79,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { }); QFile json_file("./car_fingerprint_to_dbc.json"); - if(json_file.open(QIODevice::ReadOnly)) { + if (json_file.open(QIODevice::ReadOnly)) { fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); } } @@ -103,14 +103,20 @@ void MessagesWidget::loadDBCFromPaste() { void MessagesWidget::loadDBCFromFingerprint() { auto fingerprint = can->carFingerprint(); - if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { + if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; - if (dbc_name != QJsonValue::Undefined) { + if (dbc_name != QJsonValue::Undefined) { loadDBCFromName(dbc_name.toString()); } } } +void MessagesWidget::saveDBC() { + SaveDBCDialog dlg(this); + dlg.dbc_edit->setText(dbc()->generateDBC()); + dlg.exec(); +} + // MessageListModel QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -224,6 +230,8 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { } } +// LoadDBCDialog + LoadDBCDialog::LoadDBCDialog(QWidget *parent) : QDialog(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); dbc_edit = new QTextEdit(this); @@ -233,7 +241,48 @@ LoadDBCDialog::LoadDBCDialog(QWidget *parent) : QDialog(parent) { 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); + setMinimumSize({640, 480}); + QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +// SaveDBCDialog + +SaveDBCDialog::SaveDBCDialog(QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Save DBC")); + QVBoxLayout *main_layout = new QVBoxLayout(this); + dbc_edit = new QTextEdit(this); + dbc_edit->setAcceptRichText(false); + main_layout->addWidget(dbc_edit); + + QPushButton *copy_to_clipboard = new QPushButton(tr("Copy To Clipboard"), this); + QPushButton *save_as = new QPushButton(tr("Save As"), this); + + QHBoxLayout *btn_layout = new QHBoxLayout(); + btn_layout->addStretch(); + btn_layout->addWidget(copy_to_clipboard); + btn_layout->addWidget(save_as); + main_layout->addLayout(btn_layout); + setMinimumSize({640, 480}); + + QObject::connect(copy_to_clipboard, &QPushButton::clicked, this, &SaveDBCDialog::copytoClipboard); + QObject::connect(save_as, &QPushButton::clicked, this, &SaveDBCDialog::saveAs); +} + +void SaveDBCDialog::copytoClipboard() { + dbc_edit->selectAll(); + dbc_edit->copy(); + QDialog::accept(); +} + +void SaveDBCDialog::saveAs() { + QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), + QDir::homePath() + "/untitled.dbc", tr("DBC (*.dbc)")); + if (!file_name.isEmpty()) { + QFile file(file_name); + if (file.open(QIODevice::WriteOnly)) { + file.write(dbc_edit->toPlainText().toUtf8()); + } + QDialog::accept(); + } } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index fcd4939dac..a3d4d860b2 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -17,6 +17,16 @@ public: QTextEdit *dbc_edit; }; +class SaveDBCDialog : public QDialog { + Q_OBJECT + +public: + SaveDBCDialog(QWidget *parent); + void copytoClipboard(); + void saveAs(); + QTextEdit *dbc_edit; +}; + class MessageListModel : public QAbstractTableModel { Q_OBJECT @@ -52,6 +62,7 @@ public slots: void loadDBCFromName(const QString &name); void loadDBCFromFingerprint(); void loadDBCFromPaste(); + void saveDBC(); signals: void msgSelectionChanged(const QString &message_id); diff --git a/tools/cabana/tests/test_cabana b/tools/cabana/tests/test_cabana new file mode 100755 index 0000000000..bac242fbdd --- /dev/null +++ b/tools/cabana/tests/test_cabana @@ -0,0 +1,4 @@ +#!/bin/sh +cd "$(dirname "$0")" +export LD_LIBRARY_PATH="../../../opendbc/can:$LD_LIBRARY_PATH" +exec ./_test_cabana "$1" diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc new file mode 100644 index 0000000000..d0aa2cbb4f --- /dev/null +++ b/tools/cabana/tests/test_cabana.cc @@ -0,0 +1,35 @@ + +#include "catch2/catch.hpp" +#include "tools/cabana/dbcmanager.h" + +TEST_CASE("DBCManager::generateDBC") { + DBCManager dbc_origin(nullptr); + dbc_origin.open("toyota_new_mc_pt_generated"); + QString dbc_string = dbc_origin.generateDBC(); + + DBCManager dbc_from_generated(nullptr); + dbc_from_generated.open("", dbc_string); + + auto dbc = dbc_origin.getDBC(); + auto new_dbc = dbc_from_generated.getDBC(); + REQUIRE(dbc->msgs.size() == new_dbc->msgs.size()); + for (int i = 0; i < dbc->msgs.size(); ++i) { + REQUIRE(dbc->msgs[i].name == new_dbc->msgs[i].name); + REQUIRE(dbc->msgs[i].address == new_dbc->msgs[i].address); + REQUIRE(dbc->msgs[i].size == new_dbc->msgs[i].size); + REQUIRE(dbc->msgs[i].sigs.size() == new_dbc->msgs[i].sigs.size()); + auto &sig = dbc->msgs[i].sigs; + auto &new_sig = new_dbc->msgs[i].sigs; + for (int j = 0; j < sig.size(); ++j) { + REQUIRE(sig[j].name == new_sig[j].name); + REQUIRE(sig[j].start_bit == new_sig[j].start_bit); + REQUIRE(sig[j].msb == new_sig[j].msb); + REQUIRE(sig[j].lsb == new_sig[j].lsb); + REQUIRE(sig[j].size == new_sig[j].size); + REQUIRE(sig[j].is_signed == new_sig[j].is_signed); + REQUIRE(sig[j].factor == new_sig[j].factor); + REQUIRE(sig[j].offset == new_sig[j].offset); + REQUIRE(sig[j].is_little_endian == new_sig[j].is_little_endian); + } + } +} diff --git a/tools/cabana/tests/test_runner.cc b/tools/cabana/tests/test_runner.cc new file mode 100644 index 0000000000..b20ac86c64 --- /dev/null +++ b/tools/cabana/tests/test_runner.cc @@ -0,0 +1,10 @@ +#define CATCH_CONFIG_RUNNER +#include "catch2/catch.hpp" +#include + +int main(int argc, char **argv) { + // unit tests for Qt + QCoreApplication app(argc, argv); + const int res = Catch::Session().run(argc, argv); + return (res < 0xff ? res : 0xff); +} From 9c7e3759441f0dff1200f7946e77f06c6a101c26 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 30 Oct 2022 22:31:43 +0800 Subject: [PATCH 0125/1179] Cabana: sync button state with chart (#26285) sync button state with charts --- tools/cabana/chartswidget.cc | 14 ++++++++++++-- tools/cabana/chartswidget.h | 5 ++++- tools/cabana/detailwidget.cc | 14 ++++++++++++-- tools/cabana/detailwidget.h | 7 ++++--- tools/cabana/mainwin.cc | 5 ++--- tools/cabana/signaledit.cc | 18 ++++++++++++------ tools/cabana/signaledit.h | 7 +++++-- 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index a3cbaf5b30..21fd71b8ea 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -142,9 +142,11 @@ void ChartsWidget::updateTitleBar() { dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); } -void ChartsWidget::addChart(const QString &id, const Signal *sig) { +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 (it != charts.end()) { + if (!show) removeChart((*it)); + } else if (show) { auto chart = new ChartWidget(id, sig, this); chart->chart_view->updateSeries(display_range); QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(chart); }); @@ -152,14 +154,21 @@ void ChartsWidget::addChart(const QString &id, const Signal *sig) { QObject::connect(chart->chart_view, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); charts_layout->insertWidget(0, chart); charts.push_back(chart); + emit chartOpened(chart->id, chart->signal); } updateTitleBar(); } +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(ChartWidget *chart) { charts.removeOne(chart); chart->deleteLater(); updateTitleBar(); + emit chartClosed(chart->id, chart->signal); } void ChartsWidget::removeAll(const Signal *sig) { @@ -168,6 +177,7 @@ void ChartsWidget::removeAll(const Signal *sig) { auto c = it.next(); if (sig == nullptr || c->signal == sig) { c->deleteLater(); + emit chartClosed(c->id, c->signal); it.remove(); } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 60081dd882..602d50ca0a 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -73,12 +73,15 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); - void addChart(const QString &id, const Signal *sig); + void showChart(const QString &id, const Signal *sig, bool show); void removeChart(ChartWidget *chart); + bool isChartOpened(const QString &id, const Signal *sig); signals: void dock(bool floating); void rangeChanged(double min, double max, bool is_zommed); + void chartOpened(const QString &id, const Signal *sig); + void chartClosed(const QString &id, const Signal *sig); private: void eventsMerged(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 69b420483d..59e5b5f296 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -12,7 +12,7 @@ // DetailWidget -DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { +DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { main_layout = new QHBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -110,6 +110,8 @@ DetailWidget::DetailWidget(QWidget *parent) : QWidget(parent) { } tabbar->removeTab(index); }); + QObject::connect(charts, &ChartsWidget::chartOpened, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, true); }); + QObject::connect(charts, &ChartsWidget::chartClosed, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, false); }); } void DetailWidget::showTabBarContextMenu(const QPoint &pt) { @@ -157,13 +159,14 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { 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])); + form->setChartOpened(charts->isChartOpened(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); QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); + QObject::connect(form, &SignalEdit::showChart, [this, sig = &msg->sigs[i]](bool show) { charts->showChart(msg_id, sig, show); }); if (i == show_form_idx) { QTimer::singleShot(0, [=]() { emit form->showFormClicked(); }); } @@ -222,6 +225,13 @@ void DetailWidget::showForm() { } } +void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool opened) { + if (id == msg_id) { + for (auto f : signals_container->findChildren()) + if (f->sig == sig) f->setChartOpened(opened); + } +} + void DetailWidget::editMsg() { auto msg = dbc()->msg(msg_id); QString name = msg ? msg->name.c_str() : "untitled"; diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 3f042bf2b8..656aacb106 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -5,6 +5,7 @@ #include #include "tools/cabana/binaryview.h" +#include "tools/cabana/chartswidget.h" #include "tools/cabana/historylog.h" #include "tools/cabana/signaledit.h" @@ -40,16 +41,15 @@ class DetailWidget : public QWidget { Q_OBJECT public: - DetailWidget(QWidget *parent); + DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const QString &message_id); void dbcMsgChanged(int show_form_idx = -1); signals: - void showChart(const QString &msg_id, const Signal *sig); - void removeChart(const Signal *sig); void binaryViewMoved(bool in); private: + void updateChartState(const QString &id, const Signal *sig, bool opened); void showTabBarContextMenu(const QPoint &pt); void addSignal(int start_bit, int to); void resizeSignal(const Signal *sig, int from, int to); @@ -74,4 +74,5 @@ private: HistoryLog *history_log; BinaryView *binary_view; ScrollArea *scroll; + ChartsWidget *charts; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 71ec873551..c2baca4d22 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -26,7 +26,8 @@ MainWindow::MainWindow() : QWidget() { messages_widget = new MessagesWidget(this); splitter->addWidget(messages_widget); - detail_widget = new DetailWidget(this); + charts_widget = new ChartsWidget(this); + detail_widget = new DetailWidget(charts_widget, this); splitter->addWidget(detail_widget); h_layout->addWidget(splitter); @@ -50,7 +51,6 @@ MainWindow::MainWindow() : QWidget() { video_widget = new VideoWidget(this); r_layout->addWidget(video_widget, 0, Qt::AlignTop); - charts_widget = new ChartsWidget(this); r_layout->addWidget(charts_widget); h_layout->addWidget(right_container); @@ -81,7 +81,6 @@ MainWindow::MainWindow() : QWidget() { QObject::connect(this, &MainWindow::showMessage, status_bar, &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); - QObject::connect(detail_widget, &DetailWidget::showChart, charts_widget, &ChartsWidget::addChart); QObject::connect(detail_widget, &DetailWidget::binaryViewMoved, [this](bool in) { splitter->setSizes({in ? 100 : 0, 500}); }); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 1bb5e9e533..ef0a85eba3 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -82,15 +82,14 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWid title_layout->addWidget(title, 1); QPushButton *seek_btn = new QPushButton("⌕"); - seek_btn->setStyleSheet("font-weight:bold;font-size:20px"); + seek_btn->setStyleSheet("QPushButton{font-weight:bold;font-size:18px}"); seek_btn->setToolTip(tr("Find signal values")); - seek_btn->setFixedSize(20, 20); + seek_btn->setFixedSize(25, 25); title_layout->addWidget(seek_btn); - QPushButton *plot_btn = new QPushButton("📈"); - plot_btn->setToolTip(tr("Show Plot")); - plot_btn->setFixedSize(20, 20); - QObject::connect(plot_btn, &QPushButton::clicked, this, &SignalEdit::showChart); + plot_btn = new QPushButton(this); + plot_btn->setStyleSheet("QPushButton {font-size:18px}"); + plot_btn->setFixedSize(25, 25); title_layout->addWidget(plot_btn); main_layout->addLayout(title_layout); @@ -120,6 +119,7 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWid QObject::connect(remove_btn, &QPushButton::clicked, [this]() { emit remove(this->sig); }); QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); QObject::connect(save_btn, &QPushButton::clicked, this, &SignalEdit::saveSignal); + QObject::connect(plot_btn, &QPushButton::clicked, [this]() { emit showChart(!chart_opened); }); QObject::connect(seek_btn, &QPushButton::clicked, [this, msg_id]() { SignalFindDlg dlg(msg_id, this->sig, this); dlg.exec(); @@ -145,6 +145,12 @@ void SignalEdit::saveSignal() { emit save(this->sig, s); } +void SignalEdit::setChartOpened(bool opened) { + plot_btn->setText(opened ? "☒" : "📈"); + plot_btn->setToolTip(opened ? tr("Close Plot") :tr("Show Plot")); + chart_opened = opened; +} + void SignalEdit::setFormVisible(bool visible) { form_container->setVisible(visible); icon->setText(visible ? "▼" : ">"); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 71719852f1..e3d38d5b25 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -26,13 +26,15 @@ class SignalEdit : public QWidget { public: SignalEdit(int index, const QString &msg_id, const Signal *sig, QWidget *parent = nullptr); + void setChartOpened(bool opened); void setFormVisible(bool show); void signalHovered(const Signal *sig); inline bool isFormVisible() const { return form_container->isVisible(); } + const Signal *sig = nullptr; signals: void highlight(const Signal *sig); - void showChart(); + void showChart(bool show); void showFormClicked(); void remove(const Signal *sig); void save(const Signal *sig, const Signal &new_sig); @@ -48,7 +50,8 @@ protected: QLabel *icon; int form_idx = 0; QString msg_id; - const Signal *sig = nullptr; + bool chart_opened = false; + QPushButton *plot_btn; }; class SignalFindDlg : public QDialog { From 6fed76695cbab39ffbaca2cd5e656e4c5a5badca Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 30 Oct 2022 23:53:02 +0800 Subject: [PATCH 0126/1179] Cabana: fix possible crash when removing tabs (#26283) fix dead loop --- tools/cabana/detailwidget.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 59e5b5f296..57a3910303 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -104,12 +104,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart setMessage(tabbar->tabText(index)); } }); - QObject::connect(tabbar, &QTabBar::tabCloseRequested, [=](int index) { - if (tabbar->currentIndex() == index) { - tabbar->setCurrentIndex(index == tabbar->count() - 1 ? index - 1 : index + 1); - } - tabbar->removeTab(index); - }); + QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); QObject::connect(charts, &ChartsWidget::chartOpened, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, true); }); QObject::connect(charts, &ChartsWidget::chartClosed, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, false); }); } @@ -120,9 +115,14 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { QMenu menu(this); menu.addAction(tr("Close Other Tabs")); if (menu.exec(tabbar->mapToGlobal(pt))) { - for (int i = tabbar->count() - 1; i >= 0; --i) { - if (i != index) - tabbar->removeTab(i); + tabbar->setCurrentIndex(index); + // remove all tabs before the one to keep + for (int i = 0; i < index; ++i) { + tabbar->removeTab(0); + } + // remove all tabs after the one to keep + while (tabbar->count() > 1) { + tabbar->removeTab(1); } } } From eecd6982059211491cb019dca5453dcde9cc1038 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sun, 30 Oct 2022 17:39:40 -0700 Subject: [PATCH 0127/1179] remove black connecting background --- selfdrive/ui/qt/offroad/networking.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index 13697adfb5..5b87d47976 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -256,7 +256,6 @@ WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) padding: 27px; padding-left: 43px; padding-right: 43px; - background-color: black; } #ssidLabel { font-size: 55px; From 0c03fb1be4f47facef1bcda9ad3cb97b98636286 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sun, 30 Oct 2022 17:43:15 -0700 Subject: [PATCH 0128/1179] Revert "remove black connecting background" This reverts commit eecd6982059211491cb019dca5453dcde9cc1038. --- selfdrive/ui/qt/offroad/networking.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index 5b87d47976..13697adfb5 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -256,6 +256,7 @@ WifiUI::WifiUI(QWidget *parent, WifiManager* wifi) : QWidget(parent), wifi(wifi) padding: 27px; padding-left: 43px; padding-right: 43px; + background-color: black; } #ssidLabel { font-size: 55px; From c3388d216c33111ae8bd16452016cf8908679c28 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Sun, 30 Oct 2022 23:55:48 -0700 Subject: [PATCH 0129/1179] Model trained with headlight augmentation (#26284) * d8501d20-bb59-4193-aa82-82b2737dedd6/449 ddfe2a22-fb0e-4ff0-a97f-0157b95eb44d/700 * update ref --- 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 49a1c3a3b8..243223eabd 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:a41d42f92913e6cc3909e505b1220b16d31f7cfca5f8a4e82109577b4151b645 +oid sha256:dcfad22cecf37275d01a339d96174800c109e9a70f853fdef3e4ef62ed3f4bbe size 45922983 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 5843a1e174..d13ced3a53 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -d2f1711fd58d4f2c25b81bd332270da60ff9636d +49ea844254883ac61caa2ac425f453799aeb28a6 From b727f6cff4968a53dd489e9825b785d97eda66ef Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 31 Oct 2022 08:37:05 -0700 Subject: [PATCH 0130/1179] EV6 long tuning (#26166) * some matching and jerk limit * update that * one jerk limit * little more * more jerk * bump opendbc * update refs --- opendbc | 2 +- selfdrive/car/hyundai/carcontroller.py | 4 ++- selfdrive/car/hyundai/carstate.py | 38 ++++++++++---------- selfdrive/car/hyundai/hyundaicanfd.py | 44 +++++++++++++----------- selfdrive/car/hyundai/interface.py | 6 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 50 insertions(+), 46 deletions(-) diff --git a/opendbc b/opendbc index 526e21da66..b3dc569994 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 526e21da666aeeabcf2369c66903a5675fdf933b +Subproject commit b3dc569994fd10e4de04afd650980c51ddfce5e1 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 913f683e2c..2f944edc0f 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -49,6 +49,7 @@ class CarController: self.angle_limit_counter = 0 self.frame = 0 + self.accel_last = 0 self.apply_steer_last = 0 self.car_fingerprint = CP.carFingerprint self.last_button_frame = 0 @@ -123,8 +124,9 @@ class CarController: if self.CP.openpilotLongitudinalControl: can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.frame)) if self.frame % 2 == 0: - can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CP, CC.enabled, accel, stopping, CC.cruiseControl.override, + can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CP, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override, set_speed_in_units)) + self.accel_last = accel else: # button presses if (self.frame - self.last_button_frame) * DT_CTRL > 0.25: diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 2e4cb0d25a..3cce581868 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -196,10 +196,10 @@ class CarState(CarStateBase): if not self.CP.openpilotLongitudinalControl: speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS cp_cruise_info = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam - ret.cruiseState.speed = cp_cruise_info.vl["CRUISE_INFO"]["SET_SPEED"] * speed_factor - ret.cruiseState.standstill = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STANDSTILL"] == 1 - ret.cruiseState.enabled = cp_cruise_info.vl["CRUISE_INFO"]["CRUISE_STATUS"] != 0 - self.cruise_info = copy.copy(cp_cruise_info.vl["CRUISE_INFO"]) + ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor + ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 + ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) + self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"]) cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" self.prev_cruise_buttons = self.cruise_buttons[-1] @@ -464,12 +464,12 @@ class CarState(CarStateBase): if CP.flags & HyundaiFlags.CANFD_HDA2 and not CP.openpilotLongitudinalControl: signals += [ - ("CRUISE_STATUS", "CRUISE_INFO"), - ("SET_SPEED", "CRUISE_INFO"), - ("CRUISE_STANDSTILL", "CRUISE_INFO"), + ("ACCMode", "SCC_CONTROL"), + ("VSetDis", "SCC_CONTROL"), + ("CRUISE_STANDSTILL", "SCC_CONTROL"), ] checks += [ - ("CRUISE_INFO", 50), + ("SCC_CONTROL", 50), ] if CP.carFingerprint in EV_CAR: @@ -497,20 +497,20 @@ class CarState(CarStateBase): checks = [("CAM_0x2a4", 20)] else: signals = [ - ("COUNTER", "CRUISE_INFO"), - ("NEW_SIGNAL_1", "CRUISE_INFO"), - ("CRUISE_MAIN", "CRUISE_INFO"), - ("CRUISE_STATUS", "CRUISE_INFO"), - ("CRUISE_INACTIVE", "CRUISE_INFO"), - ("ZEROS_9", "CRUISE_INFO"), - ("CRUISE_STANDSTILL", "CRUISE_INFO"), - ("ZEROS_5", "CRUISE_INFO"), - ("DISTANCE_SETTING", "CRUISE_INFO"), - ("SET_SPEED", "CRUISE_INFO"), + ("COUNTER", "SCC_CONTROL"), + ("NEW_SIGNAL_1", "SCC_CONTROL"), + ("MainMode_ACC", "SCC_CONTROL"), + ("ACCMode", "SCC_CONTROL"), + ("CRUISE_INACTIVE", "SCC_CONTROL"), + ("ZEROS_9", "SCC_CONTROL"), + ("CRUISE_STANDSTILL", "SCC_CONTROL"), + ("ZEROS_5", "SCC_CONTROL"), + ("DISTANCE_SETTING", "SCC_CONTROL"), + ("VSetDis", "SCC_CONTROL"), ] checks = [ - ("CRUISE_INFO", 50), + ("SCC_CONTROL", 50), ] return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 6) diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index e1478e6f18..8b53e7c378 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -1,3 +1,4 @@ +from common.numpy_fast import clip from selfdrive.car.hyundai.values import HyundaiFlags @@ -52,10 +53,9 @@ def create_buttons(packer, CP, cnt, btn): def create_acc_cancel(packer, CP, cruise_info_copy): values = cruise_info_copy values.update({ - "CRUISE_STATUS": 0, - "CRUISE_INACTIVE": 1, + "ACCMode": 4, }) - return packer.make_can_msg("CRUISE_INFO", get_e_can_bus(CP), values) + return packer.make_can_msg("SCC_CONTROL", get_e_can_bus(CP), values) def create_lfahda_cluster(packer, CP, enabled): values = { @@ -65,33 +65,37 @@ def create_lfahda_cluster(packer, CP, enabled): return packer.make_can_msg("LFAHDA_CLUSTER", get_e_can_bus(CP), values) -def create_acc_control(packer, CP, enabled, accel, stopping, gas_override, set_speed): - cruise_status = 0 if not enabled else (4 if gas_override else 2) +def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_override, set_speed): + jerk = 5 + jn = jerk / 50 if not enabled or gas_override: - accel = 0 + a_val, a_raw = 0, 0 + else: + a_raw = accel + a_val = clip(accel, accel_last - jn, accel_last + jn) + if stopping: + a_raw = 0 + values = { - "CRUISE_STATUS": cruise_status, - "CRUISE_INACTIVE": 0 if enabled else 1, - "CRUISE_MAIN": 1, - "CRUISE_STANDSTILL": 0, - "STOP_REQ": 1 if stopping else 0, - "ACCEL_REQ": accel, - "ACCEL_REQ2": accel, - "SET_SPEED": set_speed, - "DISTANCE_SETTING": 4, + "ACCMode": 0 if not enabled else (2 if gas_override else 1), + "MainMode_ACC": 1, + "StopReq": 1 if stopping else 0, + "aReqValue": a_val, + "aReqRaw": a_raw, + "VSetDis": set_speed, + "JerkLowerLimit": jerk if enabled else 1, "ACC_ObjDist": 1, - "ObjValid": 1, + "ObjValid": 0, "OBJ_STATUS": 2, - "SET_ME_2": 0x2, + "SET_ME_2": 0x4, "SET_ME_3": 0x3, "SET_ME_TMP_64": 0x64, - - "NEW_SIGNAL_9": 2, "NEW_SIGNAL_10": 4, + "DISTANCE_SETTING": 4, } - return packer.make_can_msg("CRUISE_INFO", get_e_can_bus(CP), values) + return packer.make_can_msg("SCC_CONTROL", get_e_can_bus(CP), values) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 6a1d741dec..4b4d51f3f1 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -202,14 +202,10 @@ class CarInterface(CarInterfaceBase): if candidate in CANFD_CAR: ret.longitudinalTuning.kpV = [0.1] ret.longitudinalTuning.kiV = [0.0] - ret.longitudinalActuatorDelayLowerBound = 0.15 - ret.longitudinalActuatorDelayUpperBound = 0.5 ret.experimentalLongitudinalAvailable = bool(ret.flags & HyundaiFlags.CANFD_HDA2) else: ret.longitudinalTuning.kpV = [0.5] ret.longitudinalTuning.kiV = [0.0] - ret.longitudinalActuatorDelayLowerBound = 0.5 - ret.longitudinalActuatorDelayUpperBound = 0.5 ret.experimentalLongitudinalAvailable = candidate not in (LEGACY_SAFETY_MODE_CAR | CAMERA_SCC_CAR) ret.openpilotLongitudinalControl = experimental_long and ret.experimentalLongitudinalAvailable ret.pcmCruise = not ret.openpilotLongitudinalControl @@ -218,6 +214,8 @@ class CarInterface(CarInterfaceBase): ret.startingState = True ret.vEgoStarting = 0.1 ret.startAccel = 2.0 + ret.longitudinalActuatorDelayLowerBound = 0.5 + ret.longitudinalActuatorDelayUpperBound = 0.5 # *** feature detection *** if candidate in CANFD_CAR: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c7d81c3496..0e4ac94784 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -e56c5a6ac5b87ee6083c9f92921e7198591f7b5d +fc3a044c567a8702ed1500d745170c365dd6b3d4 \ No newline at end of file From af685851af226041f349212a0344dd00f0c3dd6e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 1 Nov 2022 00:50:27 +0800 Subject: [PATCH 0131/1179] Cabana: update msg name after load dbc from paste (#26294) update msg name after load dbc from paste --- tools/cabana/messageswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 4d97bba589..205e5347ce 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -98,6 +98,7 @@ void MessagesWidget::loadDBCFromPaste() { if (dlg.exec()) { dbc()->open("from paste", dlg.dbc_edit->toPlainText()); dbc_combo->setCurrentText("loaded from paste"); + model->updateState(true); } } From 23f290941aa16742ba9d9477c4d98533aca15322 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 1 Nov 2022 00:51:41 +0800 Subject: [PATCH 0132/1179] Cabana: get double precision from std::numeric_limits (#26293) fix precision --- tools/cabana/dbcmanager.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 479b14afec..0ab67dd305 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -1,5 +1,6 @@ #include "tools/cabana/dbcmanager.h" +#include #include #include @@ -41,8 +42,8 @@ QString DBCManager::generateDBC() { .arg(sig.size) .arg(sig.is_little_endian ? '1' : '0') .arg(sig.is_signed ? '-' : '+') - .arg(sig.factor, 0, 'g', 20) - .arg(sig.offset); + .arg(sig.factor, 0, 'g', std::numeric_limits::digits10) + .arg(sig.offset, 0, 'g', std::numeric_limits::digits10); } dbc_string += "\n"; } From 131263a75b1cbf6bff0e01a1561d87d25faae353 Mon Sep 17 00:00:00 2001 From: FAN HANGYU <111691572+MaloneFan@users.noreply.github.com> Date: Tue, 1 Nov 2022 04:13:57 +0800 Subject: [PATCH 0133/1179] Honda: add Chinese Odyssey FW versions (#25943) * Update values.py add a carFW of odyssey_chn * move after odyssey * common carparams * just ignore Co-authored-by: Shane Smiskol --- selfdrive/car/honda/interface.py | 18 ++++++------------ selfdrive/car/honda/values.py | 17 +++++++++++++++++ selfdrive/car/tests/routes.py | 2 +- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index c884f586a0..e397f02838 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -220,23 +220,17 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.06]] tire_stiffness_factor = 0.677 - elif candidate == CAR.ODYSSEY: - ret.mass = 4471. * CV.LB_TO_KG + STD_CARGO_KG + elif candidate in (CAR.ODYSSEY, CAR.ODYSSEY_CHN): + ret.mass = 1900. + STD_CARGO_KG ret.wheelbase = 3.00 ret.centerToFront = ret.wheelbase * 0.41 ret.steerRatio = 14.35 # as spec - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end - tire_stiffness_factor = 0.82 - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] - - elif candidate == CAR.ODYSSEY_CHN: - ret.mass = 1849.2 + STD_CARGO_KG # mean of 4 models in kg - ret.wheelbase = 2.90 - ret.centerToFront = ret.wheelbase * 0.41 # from CAR.ODYSSEY - ret.steerRatio = 14.35 - ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.82 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]] + if candidate == CAR.ODYSSEY_CHN: + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]] # TODO: determine if there is a dead zone at the top end + else: + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end elif candidate in (CAR.PILOT, CAR.PASSPORT): ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index e0810e0bbb..2510f2e1ff 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1031,6 +1031,23 @@ FW_VERSIONS = { b'54008-THR-A020\x00\x00', ], }, + CAR.ODYSSEY_CHN: { + (Ecu.eps, 0x18da30f1, None): [ + b'39990-T6D-H220\x00\x00', + ], + (Ecu.gateway, 0x18daeff1, None): [ + b'38897-T6A-J010\x00\x00', + ], + (Ecu.combinationMeter, 0x18da60f1, None): [ + b'78109-T6A-F310\x00\x00', + ], + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-T6A-P040\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-T6A-P110\x00\x00', + ], + }, CAR.PILOT: { (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TG7-A520\x00\x00', diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 326d80b822..5c6d214bcc 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -25,6 +25,7 @@ non_tested_cars = [ GM.BOLT_EV, HYUNDAI.GENESIS_G90, HYUNDAI.KIA_OPTIMA_H, + HONDA.ODYSSEY_CHN, ] CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,)) @@ -61,7 +62,6 @@ routes = [ CarTestRoute("2c4292a5cd10536c|2021-08-19--21-32-15", HONDA.FREED), CarTestRoute("03be5f2fd5c508d1|2020-04-19--18-44-15", HONDA.HRV), CarTestRoute("917b074700869333|2021-05-24--20-40-20", HONDA.ACURA_ILX), - CarTestRoute("81722949a62ea724|2019-04-06--15-19-25", HONDA.ODYSSEY_CHN), CarTestRoute("08a3deb07573f157|2020-03-06--16-11-19", HONDA.ACCORD), # 1.5T CarTestRoute("1da5847ac2488106|2021-05-24--19-31-50", HONDA.ACCORD), # 2.0T CarTestRoute("085ac1d942c35910|2021-03-25--20-11-15", HONDA.ACCORD), # 2021 with new style HUD msgs From d793d3622b72833b27e6f61d64bd3f5a43e70cda Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 13:54:13 -0700 Subject: [PATCH 0134/1179] test_models: fix runaway memory growth for long running tests (#26295) * delete can msgs * only can msgs --- selfdrive/car/tests/test_models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index e4e141153f..8cf748e746 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -109,6 +109,10 @@ class TestCarModelBase(unittest.TestCase): assert cls.CP assert cls.CP.carFingerprint == cls.car_model + @classmethod + def tearDownClass(cls): + del cls.can_msgs + def setUp(self): self.CI = self.CarInterface(self.CP, self.CarController, self.CarState) assert self.CI From 3fc373b4e4829b03ddc363741006af0589d97588 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 1 Nov 2022 04:59:16 +0800 Subject: [PATCH 0135/1179] Cabana: fix mouse freezes / hangs (#26292) * fix mouseReleaseEvent * trigger ci --- tools/cabana/chartswidget.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 21fd71b8ea..56346c6d6e 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -402,10 +402,13 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { // zoom in if selected range is greater than 0.5s emit zoomIn(min, max); } + event->accept(); } else if (event->button() == Qt::RightButton) { emit zoomReset(); + event->accept(); + } else { + QGraphicsView::mouseReleaseEvent(event); } - event->accept(); } void ChartView::mouseMoveEvent(QMouseEvent *ev) { From 4d7bdc271f8e02ca3f1745b442b09937a69ebe2b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 17:45:56 -0700 Subject: [PATCH 0136/1179] test_models: remove carState test from panda tests (#26298) Update test_models.py --- selfdrive/car/tests/test_models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 8cf748e746..a9999a4371 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -237,7 +237,6 @@ class TestCarModelBase(unittest.TestCase): # TODO: check rest of panda's carstate (steering, ACC main on, etc.) checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev() - checks['cruiseState'] += CS.cruiseState.enabled and not CS.cruiseState.available if self.CP.carName not in ("hyundai", "volkswagen", "body"): # TODO: fix standstill mismatches for other makes checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving() From 39167cccd9a9eb9c0864796196032256ce0c390d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 18:11:18 -0700 Subject: [PATCH 0137/1179] RAM HD: add missing abs FW (#26300) FW from 8fb5eabf914632ae|2022-08-04--17-28-53 (test route) --- selfdrive/car/chrysler/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index c703ef6cb8..16530ed989 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -241,6 +241,7 @@ FW_VERSIONS = { b'68334977AH', b'68504022AB', b'68530686AB', + b'68504022AC', ], (Ecu.fwdRadar, 0x753, None): [ b'04672895AB', From fe75dd4c09c267d82748359b01c2b94889f17c10 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 18:11:25 -0700 Subject: [PATCH 0138/1179] Elantra 2021: add missing FW (#26299) add FW for 82e9cdd3f43bf83e|2021-05-15--02-42-51 (test route) --- 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 98cb72293f..c760c724a9 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1232,6 +1232,7 @@ FW_VERSIONS = { b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00CN7 MDPS C 1.00 1.06 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4CNDC106', b'\xf1\x8756310/AA070\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106', b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106', + b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106\xf1\xa01.06', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-AB000 200819', @@ -1244,6 +1245,7 @@ FW_VERSIONS = { b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 104 \x08\x03 58910-AA800', b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800', b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 105 \x10\x03 58910-AA800', + b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800\xf1\xa01.01', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x00HT6WA280BLHT6VA640A1CCN0N20NS5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From d07b7fd7a832832b7f1f167b5dc60a16778d2502 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 18:37:43 -0700 Subject: [PATCH 0139/1179] PJ: support internal cd:/ paths (#26302) Update juggle.py --- tools/plotjuggler/juggle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/plotjuggler/juggle.py b/tools/plotjuggler/juggle.py index b7c32d9bf1..1e592da3b1 100755 --- a/tools/plotjuggler/juggle.py +++ b/tools/plotjuggler/juggle.py @@ -89,7 +89,7 @@ def juggle_route(route_or_segment_name, segment_count, qlog, can, layout, dbc=No query = parse_qs(urlparse(route_or_segment_name).query) route_or_segment_name = query["route"][0] - if route_or_segment_name.startswith(("http://", "https://")) or os.path.isfile(route_or_segment_name): + if route_or_segment_name.startswith(("http://", "https://", "cd:/")) or os.path.isfile(route_or_segment_name): logs = [route_or_segment_name] elif ci: route_or_segment_name = SegmentName(route_or_segment_name, allow_route_name=True) From 3160493c85cb132abf5acb5e4e22fc4a7c108ef1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 19:44:53 -0700 Subject: [PATCH 0140/1179] Nissan: match panda standstill (#26301) * move to openpilot * draft * support internal urls * not used * update seg list * regen segment list * regen seg list * fix * check both rear wheels * revert chganges * bump panda * bump padna --- panda | 2 +- selfdrive/car/nissan/carstate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda b/panda index 187fdee385..997e328074 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 187fdee385e59a2a19f85760f529e8e381845dff +Subproject commit 997e328074e4b356c514e8d5e6570f151465d9e8 diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py index a5ca237110..d6b6d17d55 100644 --- a/selfdrive/car/nissan/carstate.py +++ b/selfdrive/car/nissan/carstate.py @@ -44,7 +44,7 @@ class CarState(CarStateBase): ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4. ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) - ret.standstill = ret.vEgoRaw < 0.01 + ret.standstill = cp.vl["WHEEL_SPEEDS_REAR"]["WHEEL_SPEED_RL"] == 0.0 and cp.vl["WHEEL_SPEEDS_REAR"]["WHEEL_SPEED_RR"] == 0.0 if self.CP.carFingerprint == CAR.ALTIMA: ret.cruiseState.enabled = bool(cp.vl["CRUISE_STATE"]["CRUISE_ENABLED"]) From 23d5e5e07fb2c35e00b77a2f5ae5fad84bc71934 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 21:32:17 -0700 Subject: [PATCH 0141/1179] test_models: speed up test (#26304) * Update test_models.py * Update test_models.py --- selfdrive/car/tests/test_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index a9999a4371..b665fbe9c7 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -9,7 +9,7 @@ from parameterized import parameterized_class from cereal import log, car from common.realtime import DT_CTRL -from selfdrive.boardd.boardd import can_capnp_to_can_list, can_list_to_can_capnp +from selfdrive.boardd.boardd import can_capnp_to_can_list from selfdrive.car.fingerprints import all_known_cars from selfdrive.car.car_helpers import interfaces from selfdrive.car.gm.values import CAR as GM @@ -214,10 +214,10 @@ class TestCarModelBase(unittest.TestCase): # warm up pass, as initial states may be different for can in self.can_msgs[:300]: + self.CI.update(CC, (can.as_builder().to_bytes(), )) for msg in can_capnp_to_can_list(can.can, src_filter=range(64)): to_send = package_can_msg(msg) self.safety.safety_rx_hook(to_send) - self.CI.update(CC, (can_list_to_can_capnp([msg, ]), )) if not self.CP.pcmCruise: self.safety.set_controls_allowed(0) From c171fe9f9a93ef0e6018de5703ed55f307a8cb72 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 31 Oct 2022 23:01:22 -0700 Subject: [PATCH 0142/1179] UI: draw onroad objects on right frame (#26306) * update before draw * fix a lot of janky * fix more flicker * cleanup * fix flicker when opening settings * simplify --- selfdrive/ui/qt/onroad.cc | 62 ++++++++++++++++----- selfdrive/ui/qt/onroad.h | 3 + selfdrive/ui/qt/widgets/cameraview.cc | 79 ++++++++++++++------------- selfdrive/ui/qt/widgets/cameraview.h | 10 ++-- selfdrive/ui/ui.cc | 28 ++-------- selfdrive/ui/ui.h | 6 ++ 6 files changed, 109 insertions(+), 79 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 346cb3ab96..d3bc931b67 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -227,14 +227,6 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { setProperty("dmActive", sm["driverMonitoringState"].getDriverMonitoringState().getIsActiveMode()); setProperty("rightHandDM", sm["driverMonitoringState"].getDriverMonitoringState().getIsRHD()); } - - setStreamType(s.scene.wide_cam ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); - if (s.scene.calibration_valid) { - auto calib = s.scene.wide_cam ? s.scene.view_from_wide_calib : s.scene.view_from_calib; - CameraWidget::updateCalibration(calib); - } else { - CameraWidget::updateCalibration(DEFAULT_CALIBRATION); - } } void AnnotatedCameraWidget::drawHud(QPainter &p) { @@ -545,18 +537,62 @@ void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::ModelDataV } void AnnotatedCameraWidget::paintGL() { - const double start_draw_t = millis_since_boot(); - UIState *s = uiState(); - const cereal::ModelDataV2::Reader &model = (*s->sm)["modelV2"].getModelV2(); - CameraWidget::setFrameId(model.getFrameId()); - CameraWidget::paintGL(); + SubMaster &sm = *(s->sm); + const double start_draw_t = millis_since_boot(); + const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); + + // draw camera frame + { + std::lock_guard lk(frame_lock); + + if (frames.empty()) { + if (skip_frame_count > 0) { + skip_frame_count--; + qDebug() << "skipping frame, not ready"; + return; + } + } else { + // skip drawing up to this many frames if we're + // missing camera frames. this smooths out the + // transitions from the narrow and wide cameras + skip_frame_count = 5; + } + + // Wide or narrow cam dependent on speed + float v_ego = sm["carState"].getCarState().getVEgo(); + if ((v_ego < 10) || s->wide_cam_only) { + wide_cam_requested = true; + } else if (v_ego > 15) { + wide_cam_requested = false; + } + // TODO: also detect when ecam vision stream isn't available + // for replay of old routes, never go to widecam + wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; + CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); + + s->scene.wide_cam = CameraWidget::getStreamType() == VISION_STREAM_WIDE_ROAD; + if (s->scene.calibration_valid) { + auto calib = s->scene.wide_cam ? s->scene.view_from_wide_calib : s->scene.view_from_calib; + CameraWidget::updateCalibration(calib); + } else { + CameraWidget::updateCalibration(DEFAULT_CALIBRATION); + } + CameraWidget::setFrameId(model.getFrameId()); + CameraWidget::paintGL(); + } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); if (s->worldObjectsVisible()) { + if (sm.rcv_frame("modelV2") > s->scene.started_frame) { + update_model(s, sm["modelV2"].getModelV2()); + if (sm.rcv_frame("radarState") > s->scene.started_frame) { + update_leads(s, sm["radarState"].getRadarState(), sm["modelV2"].getModelV2().getPosition()); + } + } drawLaneLines(painter, s); diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 2a663185f4..7edca6b3d5 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -70,6 +70,9 @@ private: int status = STATUS_DISENGAGED; std::unique_ptr pm; + int skip_frame_count = 0; + bool wide_cam_requested = false; + protected: void paintGL() override; void initializeGL() override; diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index d7591633c9..a606d6893e 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -94,7 +94,7 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio) } // namespace CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : - stream_name(stream_name), stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { + stream_name(stream_name), requested_stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { setAttribute(Qt::WA_OpaquePaintEvent); QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); @@ -124,7 +124,7 @@ void CameraWidget::initializeGL() { GLint frame_pos_loc = program->attributeLocation("aPosition"); GLint frame_texcoord_loc = program->attributeLocation("aTexCoord"); - auto [x1, x2, y1, y2] = stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); + auto [x1, x2, y1, y2] = requested_stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; const float frame_coords[4][4] = { {-1.0, -1.0, x2, y1}, // bl @@ -163,36 +163,26 @@ void CameraWidget::initializeGL() { void CameraWidget::showEvent(QShowEvent *event) { if (!vipc_thread) { + clearFrames(); vipc_thread = new QThread(); connect(vipc_thread, &QThread::started, [=]() { vipcThread(); }); connect(vipc_thread, &QThread::finished, vipc_thread, &QObject::deleteLater); vipc_thread->start(); } - clearFrames(); -} - -void CameraWidget::hideEvent(QHideEvent *event) { - if (vipc_thread) { - vipc_thread->requestInterruption(); - vipc_thread->quit(); - vipc_thread->wait(); - vipc_thread = nullptr; - } - clearFrames(); } void CameraWidget::updateFrameMat() { int w = width(), h = height(); if (zoomed_view) { - if (stream_type == VISION_STREAM_DRIVER) { + if (active_stream_type == VISION_STREAM_DRIVER) { frame_mat = get_driver_view_transform(w, h, stream_width, stream_height); } else { // Project point at "infinity" to compute x and y offsets // to ensure this ends up in the middle of the screen // for narrow come and a little lower for wide cam. // TODO: use proper perspective transform? - if (stream_type == VISION_STREAM_WIDE_ROAD) { + if (active_stream_type == VISION_STREAM_WIDE_ROAD) { intrinsic_matrix = ecam_intrinsic_matrix; zoom = 2.0; } else { @@ -212,11 +202,11 @@ void CameraWidget::updateFrameMat() { x_offset = std::clamp(x_offset_, -max_x_offset, max_x_offset); y_offset = std::clamp(y_offset_, -max_y_offset, max_y_offset); - float zx = zoom * 2 * intrinsic_matrix.v[2] / width(); - float zy = zoom * 2 * intrinsic_matrix.v[5] / height(); + float zx = zoom * 2 * intrinsic_matrix.v[2] / w; + float zy = zoom * 2 * intrinsic_matrix.v[5] / h; const mat4 frame_transform = {{ - zx, 0.0, 0.0, -x_offset / width() * 2, - 0.0, zy, 0.0, y_offset / height() * 2, + zx, 0.0, 0.0, -x_offset / w * 2, + 0.0, zy, 0.0, y_offset / h * 2, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, }}; @@ -224,7 +214,7 @@ void CameraWidget::updateFrameMat() { } } else if (stream_width > 0 && stream_height > 0) { // fit frame to widget size - float widget_aspect_ratio = (float)width() / height(); + float widget_aspect_ratio = (float)w / h; float frame_aspect_ratio = (float)stream_width / stream_height; frame_mat = get_fit_view_transform(widget_aspect_ratio, frame_aspect_ratio); } @@ -232,7 +222,6 @@ void CameraWidget::updateFrameMat() { void CameraWidget::updateCalibration(const mat3 &calib) { calibration = calib; - updateFrameMat(); } void CameraWidget::paintGL() { @@ -240,13 +229,26 @@ void CameraWidget::paintGL() { glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); std::lock_guard lk(frame_lock); + if (frames.empty()) return; - // use previous texture if update() is called without new frame. - VisionBuf *frame = nullptr; - if (!frames.empty()) { - frame = frames.front().second; - frames.pop_front(); + int frame_idx = frames.size() - 1; + + // Always draw latest frame until sync logic is more stable + // for (frame_idx = 0; frame_idx < frames.size() - 1; frame_idx++) { + // if (frames[frame_idx].first == draw_frame_id) break; + // } + + // Log duplicate/dropped frames + if (frames[frame_idx].first == prev_frame_id) { + qDebug() << "Drawing same frame twice" << frames[frame_idx].first; + } else if (frames[frame_idx].first != prev_frame_id + 1) { + qDebug() << "Skipped frame" << frames[frame_idx].first; } + prev_frame_id = frames[frame_idx].first; + VisionBuf *frame = frames[frame_idx].second; + assert(frame != nullptr); + + updateFrameMat(); glViewport(0, 0, width(), height()); glBindVertexArray(frame_vao); @@ -254,22 +256,22 @@ void CameraWidget::paintGL() { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #ifdef QCOM2 + // no frame copy glActiveTexture(GL_TEXTURE0); - if (frame) { - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_images[frame->idx]); - assert(glGetError() == GL_NO_ERROR); - } + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_images[frame->idx]); + assert(glGetError() == GL_NO_ERROR); #else + // fallback to copy glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); - if (frame) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width, stream_height, GL_RED, GL_UNSIGNED_BYTE, frame->y); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width, stream_height, GL_RED, GL_UNSIGNED_BYTE, frame->y); assert(glGetError() == GL_NO_ERROR); glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride/2); glActiveTexture(GL_TEXTURE0 + 1); glBindTexture(GL_TEXTURE_2D, textures[1]); - if (frame) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width/2, stream_height/2, GL_RG, GL_UNSIGNED_BYTE, frame->uv); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width/2, stream_height/2, GL_RG, GL_UNSIGNED_BYTE, frame->uv); assert(glGetError() == GL_NO_ERROR); #endif @@ -332,8 +334,6 @@ void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, stream_width/2, stream_height/2, 0, GL_RG, GL_UNSIGNED_BYTE, nullptr); assert(glGetError() == GL_NO_ERROR); #endif - - updateFrameMat(); } void CameraWidget::vipcFrameReceived() { @@ -341,16 +341,18 @@ void CameraWidget::vipcFrameReceived() { } void CameraWidget::vipcThread() { - VisionStreamType cur_stream_type = stream_type; + VisionStreamType cur_stream = requested_stream_type; std::unique_ptr vipc_client; VisionIpcBufExtra meta_main = {0}; while (!QThread::currentThread()->isInterruptionRequested()) { - if (!vipc_client || cur_stream_type != stream_type) { + if (!vipc_client || cur_stream != requested_stream_type) { clearFrames(); - cur_stream_type = stream_type; - vipc_client.reset(new VisionIpcClient(stream_name, cur_stream_type, false)); + qDebug() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; + cur_stream = requested_stream_type;; + vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); } + active_stream_type = cur_stream; if (!vipc_client->connected) { clearFrames(); @@ -366,7 +368,6 @@ void CameraWidget::vipcThread() { std::lock_guard lk(frame_lock); frames.push_back(std::make_pair(meta_main.frame_id, buf)); while (frames.size() > FRAME_BUFFER_SIZE) { - qDebug() << "Skipped frame" << frames.front().first; frames.pop_front(); } } diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index aff3abc836..0698d1fb9a 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -31,9 +31,10 @@ public: using QOpenGLWidget::QOpenGLWidget; 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; } + void setStreamType(VisionStreamType type) { requested_stream_type = type; } + VisionStreamType getStreamType() { return active_stream_type; } signals: void clicked(); @@ -45,7 +46,6 @@ protected: void initializeGL() override; void resizeGL(int w, int h) override { updateFrameMat(); } void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override { emit clicked(); } virtual void updateFrameMat(); void updateCalibration(const mat3 &calib); @@ -68,7 +68,8 @@ protected: int stream_width = 0; int stream_height = 0; int stream_stride = 0; - std::atomic stream_type; + std::atomic active_stream_type; + std::atomic requested_stream_type; QThread *vipc_thread = nullptr; // Calibration @@ -78,9 +79,10 @@ protected: mat3 calibration = DEFAULT_CALIBRATION; mat3 intrinsic_matrix = fcam_intrinsic_matrix; - std::mutex frame_lock; + std::recursive_mutex frame_lock; std::deque> frames; uint32_t draw_frame_id = 0; + uint32_t prev_frame_id = 0; protected slots: void vipcConnected(VisionIpcClient *vipc_client); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index d1d72b4dad..821064f81f 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -35,7 +35,7 @@ static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, return false; } -static int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height) { +int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height) { const auto line_x = line.getX(); int max_idx = 0; for (int i = 1; i < TRAJECTORY_SIZE && line_x[i] <= path_height; ++i) { @@ -44,7 +44,7 @@ static int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line return max_idx; } -static void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::ModelDataV2::XYZTData::Reader &line) { +void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::ModelDataV2::XYZTData::Reader &line) { for (int i = 0; i < 2; ++i) { auto lead_data = (i == 0) ? radar_state.getLeadOne() : radar_state.getLeadTwo(); if (lead_data.getStatus()) { @@ -54,7 +54,7 @@ static void update_leads(UIState *s, const cereal::RadarState::Reader &radar_sta } } -static void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, +void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) { const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); @@ -78,7 +78,7 @@ static void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTDa *pvd = left_points + right_points; } -static void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { +void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { UIScene &scene = s->scene; auto model_position = model.getPosition(); float max_distance = std::clamp(model_position.getX()[TRAJECTORY_SIZE - 1], @@ -141,14 +141,7 @@ static void update_state(UIState *s) { } } scene.calibration_valid = sm["liveCalibration"].getLiveCalibration().getCalStatus() == 1; - } - if (s->worldObjectsVisible()) { - if (sm.updated("modelV2")) { - update_model(s, sm["modelV2"].getModelV2()); - } - if (sm.updated("radarState") && sm.rcv_frame("modelV2") > s->scene.started_frame) { - update_leads(s, sm["radarState"].getRadarState(), sm["modelV2"].getModelV2().getPosition()); - } + scene.calibration_wide_valid = wfde_list.size() == 3; } if (sm.updated("pandaStates")) { auto pandaStates = sm["pandaStates"].getPandaStates(); @@ -173,17 +166,6 @@ static void update_state(UIState *s) { scene.light_sensor = std::max(100.0f - scale * sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(), 0.0f); } scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; - - if (sm.updated("carState")) { - float v_ego = sm["carState"].getCarState().getVEgo(); - // TODO: support replays without ecam by using fcam - // Wide or narrow cam dependent on speed - if ((v_ego < 10) || s->wide_cam_only) { - scene.wide_cam = true; - } else if (v_ego > 15) { - scene.wide_cam = false; - } - } } void ui_update_params(UIState *s) { diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 5a51dda8f8..e550afd5f2 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -87,6 +87,7 @@ const QColor bg_colors [] = { typedef struct UIScene { bool calibration_valid = false; + bool calibration_wide_valid = false; bool wide_cam = true; mat3 view_from_calib = DEFAULT_CALIBRATION; mat3 view_from_wide_calib = DEFAULT_CALIBRATION; @@ -181,3 +182,8 @@ public slots: }; void ui_update_params(UIState *s); +int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height); +void update_model(UIState *s, const cereal::ModelDataV2::Reader &model); +void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::ModelDataV2::XYZTData::Reader &line); +void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, + float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert); From 0e162cc13b31e136f8a53c0af20dd71c2f84bed7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 31 Oct 2022 23:02:31 -0700 Subject: [PATCH 0143/1179] test_models: fix Nidec routes that start enabled (#26305) * Update test_models.py * Update test_models.py * fix non-pcmCruise routes where button is left pressed in warmup * more explicit, don't allow multiple continues * revert chjange * -that --- selfdrive/car/tests/test_models.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index b665fbe9c7..ee25b8205f 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -219,13 +219,10 @@ class TestCarModelBase(unittest.TestCase): to_send = package_can_msg(msg) self.safety.safety_rx_hook(to_send) - if not self.CP.pcmCruise: - self.safety.set_controls_allowed(0) - controls_allowed_prev = False CS_prev = car.CarState.new_message() checks = defaultdict(lambda: 0) - for can in self.can_msgs: + for idx, can in enumerate(self.can_msgs): CS = self.CI.update(CC, (can.as_builder().to_bytes(), )) for msg in can_capnp_to_can_list(can.can, src_filter=range(64)): msg = list(msg) @@ -234,6 +231,14 @@ class TestCarModelBase(unittest.TestCase): ret = self.safety.safety_rx_hook(to_send) self.assertEqual(1, ret, f"safety rx failed ({ret=}): {to_send}") + # Skip first frame so CS_prev is properly initialized + if idx == 0: + CS_prev = CS + # Button may be left pressed in warm up period + if not self.CP.pcmCruise: + self.safety.set_controls_allowed(0) + continue + # TODO: check rest of panda's carstate (steering, ACC main on, etc.) checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev() From d1cf31bced9609f43a518b2c07b0f440ecc2479a Mon Sep 17 00:00:00 2001 From: Ricardo Nuno <47164756+ricardonunosr@users.noreply.github.com> Date: Tue, 1 Nov 2022 15:09:47 +0000 Subject: [PATCH 0144/1179] sim: add docker kill to openpilot docker (#26310) add docker kill to openpilot docker --- tools/sim/start_openpilot_docker.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/sim/start_openpilot_docker.sh b/tools/sim/start_openpilot_docker.sh index e48e63574d..dba89b8b70 100755 --- a/tools/sim/start_openpilot_docker.sh +++ b/tools/sim/start_openpilot_docker.sh @@ -20,6 +20,7 @@ else EXTRA_ARGS="${EXTRA_ARGS} -it" fi +docker kill openpilot_client || true docker run --net=host\ --name openpilot_client \ --rm \ From 6ca6a26d4c12ab0813c8474eb1a9bed6f69374ee Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 2 Nov 2022 00:31:47 +0800 Subject: [PATCH 0145/1179] Cabana: fix update issues when the the replay is paused (#26311) fix state not updated if replay is paused --- tools/cabana/chartswidget.cc | 1 + tools/cabana/messageswidget.cc | 5 +++++ tools/cabana/messageswidget.h | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 56346c6d6e..72c9c40570 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -155,6 +155,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show) { charts_layout->insertWidget(0, chart); charts.push_back(chart); emit chartOpened(chart->id, chart->signal); + updateState(); } updateTitleBar(); } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 205e5347ce..e80a66bce9 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -147,6 +147,11 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { return {}; } +void MessageListModel::setFilterString(const QString &string) { + filter_str = string; + updateState(true); +} + bool MessageListModel::updateMessages(bool sort) { if (msgs.size() == can->can_msgs.size() && filter_str.isEmpty() && !sort) return false; diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index a3d4d860b2..255dce7dc8 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -38,7 +38,7 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void updateState(bool sort = false); - void setFilterString(const QString &string) { filter_str = string; } + void setFilterString(const QString &string); private: bool updateMessages(bool sort); From b31b0310444e83dc8e151767f57ee21f46f1515b Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 1 Nov 2022 13:00:26 -0400 Subject: [PATCH 0146/1179] =?UTF-8?q?VW=20MQB:=20Fahrzeugl=C3=A4ngsbeschle?= =?UTF-8?q?unigungssteuerungseinrichtung=20(#22963)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * can I kick it? * bumpity bump bump * bump panda * everybody's gotta be special * attempt at improving stopping/starting * reduce lateral feedforward * tweak gradient and comfort bands * oops * accel from the dept of redundancy dept * bump opendbc * jerk limiter not needed and causing problems * don't leave stop/start flags hung when not enabled * reduce comfort band with lead car * borrow decel comp from HKG * align stopping state thresholds * (re)try letting PI clean up some of this * bump panda * tweaks and comments * elide superfluous import * VW MQB: Longitudinal prereqs * gate this too * bump CI * cleanup * more cleanup; require gateway integration * don't run long state/actuators unless sending message * setpoint visibility in instrument cluster * show fixed lead car if lead visible * hold my beer? * tuning * the code is darkest before the refactor * a little more * set freewheel and stop distance correctly * rounding issue maybe? * ACC_04 Charisma profiles and HUD alerts * fix ACC_04 counter, fix gradient and accel bugs * revert tuning change in upstream focused branch * need 0.5m/s to leave * reduced braking when not absolutely needed * oops * bump panda * match opendbc to master * filter ACC_13, disable secondary accel * bump panda * bump panda * bump opendbc and panda * startAccel is deprecated * testing manual trans min engage speeds * pass stock ACC type to TSK * bump panda * bump opendbc * bump opendbc * test hax for Brake alert * remove ACC_13 with matching panda bump * fix submodule refs * update long control safety param name * bump panda * actuator delay corrected by Mk1 eyeball * a little more * tweak stop/start thresholds * Revert "tweak stop/start thresholds" This reverts commit 60abd57d2025c3218f069dbec4600c8d14033c05. * more lag reduction * bump opendbc * support both analog and digital clusters * tuning adjustments * bump opendbc and panda * accept two button types for resume * support separate set and resume * bump panda * #24706 * partial revert 6b93ac27 * fixes * one more * refactor all the things * follow experimental long refactor * fill in ACC hud status * temp force E2E availability * start cleaning up * comment touchup * gimme some comfort baby * experiment * SnG me maybe? * a little more rollout * is this why I'm not leaving? * turns out you need startAccel to leave * try without ACC_04 * cleanup unused variables * temp hack to standstill handling * temp hack to button handling * trim rollout distance with slower vEgoStopping * ultra fat comfort band due to noisy E2E actuator * I like big changes and I cannot lie * remove lead car display for now * cleanup, drives somewhat better * partial FtS/basic support * diff reduction * not needed * more cleanup * oops * more cleanup * restore lead car visible for PQ * bump panda * better enable button solution * redundant * OP long on *all* the things * OP long on all the things *sometimes* * docs generator a little TOO clever * solve starting-state a different way * try that again * bump panda * oops * follow DBC refactor * retry CI * signal name changed * sync with custom enable button branch * oops * more follow refactor * bump panda * sync opendbc to master * bump panda * updated comments * light P, no I * bump panda * bump panda again * add openpilot long test_models route * bump panda with replay route * temporarily disable experimental long for merge * bump panda to master * resolve conflict? * now can we go to head? * explicit length check * update refs Co-authored-by: Comma Device Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/car/tests/routes.py | 3 +- selfdrive/car/volkswagen/carstate.py | 3 + selfdrive/car/volkswagen/interface.py | 14 +++-- selfdrive/car/volkswagen/mqbcan.py | 70 ++++++++++++++++++++++++ selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/panda b/panda index 997e328074..0ca6d9d924 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 997e328074e4b356c514e8d5e6570f151465d9e8 +Subproject commit 0ca6d9d9248f2cea4ef2292671b6980b416c3f4b diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 5c6d214bcc..d833203427 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -172,7 +172,8 @@ routes = [ CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1), CarTestRoute("2c68dda277d887ac|2021-05-11--15-22-20", VOLKSWAGEN.ATLAS_MK1), - CarTestRoute("cae14e88932eb364|2021-03-26--14-43-28", VOLKSWAGEN.GOLF_MK7), + CarTestRoute("cae14e88932eb364|2021-03-26--14-43-28", VOLKSWAGEN.GOLF_MK7), # Stock ACC + CarTestRoute("3cfdec54aa035f3f|2022-10-13--14-58-58", VOLKSWAGEN.GOLF_MK7), # openpilot longitudinal CarTestRoute("58a7d3b707987d65|2021-03-25--17-26-37", VOLKSWAGEN.JETTA_MK7), CarTestRoute("4d134e099430fba2|2021-03-26--00-26-06", VOLKSWAGEN.PASSAT_MK8), CarTestRoute("3cfdec54aa035f3f|2022-07-19--23-45-10", VOLKSWAGEN.PASSAT_NMS), diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 5dc4543c0d..d09420cf7a 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -105,6 +105,7 @@ class CarState(CarStateBase): ret.stockAeb = bool(ext_cp.vl["ACC_10"]["ANB_Teilbremsung_Freigabe"]) or bool(ext_cp.vl["ACC_10"]["ANB_Zielbremsung_Freigabe"]) # Update ACC radar status. + self.acc_type = ext_cp.vl["ACC_06"]["ACC_Typ"] if pt_cp.vl["TSK_06"]["TSK_Status"] == 2: # ACC okay and enabled, but not currently engaged ret.cruiseState.available = True @@ -480,11 +481,13 @@ class MqbExtraSignals: # Additional signal and message lists for optional or bus-portable controllers fwd_radar_signals = [ ("ACC_Wunschgeschw_02", "ACC_02"), # ACC set speed + ("ACC_Typ", "ACC_06"), # Basic vs F2S vs SNG ("AWV2_Freigabe", "ACC_10"), # FCW brake jerk release ("ANB_Teilbremsung_Freigabe", "ACC_10"), # AEB partial braking release ("ANB_Zielbremsung_Freigabe", "ACC_10"), # AEB target braking release ] fwd_radar_checks = [ + ("ACC_06", 50), # From J428 ACC radar control module ("ACC_10", 50), # From J428 ACC radar control module ("ACC_02", 17), # From J428 ACC radar control module ] diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 870f3ab163..ca6d1fa7f8 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -32,14 +32,13 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagenPq)] ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1 - if 0x440 in fingerprint[0]: # Getriebe_1 + if 0x440 in fingerprint[0] or len(fingerprint[0]) == 0: # Getriebe_1, or empty FP for CI/docs generation ret.transmissionType = TransmissionType.automatic else: ret.transmissionType = TransmissionType.manual if any(msg in fingerprint[1] for msg in (0x1A0, 0xC2)): # Bremse_1, Lenkwinkel_1 ret.networkLocation = NetworkLocation.gateway - ret.experimentalLongitudinalAvailable = True else: ret.networkLocation = NetworkLocation.fwdCamera @@ -56,7 +55,7 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagen)] ret.enableBsm = 0x30F in fingerprint[0] # SWA_01 - if 0xAD in fingerprint[0]: # Getriebe_11 + if 0xAD in fingerprint[0] or len(fingerprint[0]) == 0: # Getriebe_11, or empty FP for CI/docs generation ret.transmissionType = TransmissionType.automatic elif 0x187 in fingerprint[0]: # EV_Gearshift ret.transmissionType = TransmissionType.direct @@ -82,7 +81,8 @@ class CarInterface(CarInterfaceBase): # Global longitudinal tuning defaults, can be overridden per-vehicle - if experimental_long and candidate in PQ_CARS: + ret.experimentalLongitudinalAvailable = ret.networkLocation == NetworkLocation.gateway and False # Disabled for now + if experimental_long and False: # Disabled for now # Proof-of-concept, prep for E2E only. No radar points available. Panda ALLOW_DEBUG firmware required. ret.openpilotLongitudinalControl = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_VOLKSWAGEN_LONG_CONTROL @@ -90,7 +90,11 @@ class CarInterface(CarInterfaceBase): ret.minEnableSpeed = 4.5 ret.pcmCruise = not ret.openpilotLongitudinalControl - ret.longitudinalActuatorDelayUpperBound = 0.5 # s + ret.stoppingControl = True + ret.startingState = True + ret.startAccel = 1.0 + ret.vEgoStarting = 1.0 + ret.vEgoStopping = 1.0 ret.longitudinalTuning.kpV = [0.1] ret.longitudinalTuning.kiV = [0.0] diff --git a/selfdrive/car/volkswagen/mqbcan.py b/selfdrive/car/volkswagen/mqbcan.py index 3819f4f76f..25a710dbb8 100644 --- a/selfdrive/car/volkswagen/mqbcan.py +++ b/selfdrive/car/volkswagen/mqbcan.py @@ -36,3 +36,73 @@ def create_acc_buttons_control(packer, bus, gra_stock_values, counter, cancel=Fa }) return packer.make_can_msg("GRA_ACC_01", bus, values) + + +def acc_control_value(main_switch_on, acc_faulted, long_active): + if acc_faulted: + acc_control = 6 + elif long_active: + acc_control = 3 + elif main_switch_on: + acc_control = 2 + else: + acc_control = 0 + + return acc_control + + +def acc_hud_status_value(main_switch_on, acc_faulted, long_active): + # TODO: happens to resemble the ACC control value for now, but extend this for init/gas override later + return acc_control_value(main_switch_on, acc_faulted, long_active) + + +def create_acc_accel_control(packer, bus, acc_type, enabled, accel, acc_control, stopping, starting, esp_hold): + commands = [] + + acc_06_values = { + "ACC_Typ": acc_type, + "ACC_Status_ACC": acc_control, + "ACC_StartStopp_Info": enabled, + "ACC_Sollbeschleunigung_02": accel if enabled else 3.01, + "ACC_zul_Regelabw_unten": 0.2, # TODO: dynamic adjustment of comfort-band + "ACC_zul_Regelabw_oben": 0.2, # TODO: dynamic adjustment of comfort-band + "ACC_neg_Sollbeschl_Grad_02": 4.0 if enabled else 0, # TODO: dynamic adjustment of jerk limits + "ACC_pos_Sollbeschl_Grad_02": 4.0 if enabled else 0, # TODO: dynamic adjustment of jerk limits + "ACC_Anfahren": starting, + "ACC_Anhalten": stopping, + } + commands.append(packer.make_can_msg("ACC_06", bus, acc_06_values)) + + if starting: + acc_hold_type = 4 # hold release / startup + elif esp_hold: + acc_hold_type = 3 # hold standby + elif stopping: + acc_hold_type = 1 # hold request + else: + acc_hold_type = 0 + + acc_07_values = { + "ACC_Anhalteweg": 0.75 if stopping else 20.46, # Distance to stop (stopping coordinator handles terminal roll-out) + "ACC_Freilauf_Info": 2 if enabled else 0, + "ACC_Folgebeschl": 3.02, # Not using secondary controller accel unless and until we understand its impact + "ACC_Sollbeschleunigung_02": accel if enabled else 3.01, + "ACC_Anforderung_HMS": acc_hold_type, + "ACC_Anfahren": starting, + "ACC_Anhalten": stopping, + } + commands.append(packer.make_can_msg("ACC_07", bus, acc_07_values)) + + return commands + + +def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, lead_visible): + values = { + "ACC_Status_Anzeige": acc_hud_status, + "ACC_Wunschgeschw_02": set_speed if set_speed < 250 else 327.36, + "ACC_Gesetzte_Zeitluecke": 3, + "ACC_Display_Prio": 3, + # TODO: ACC_Abstandsindex for lead car distance, must determine analog vs digital cluster for scaling + } + + return packer.make_can_msg("ACC_02", bus, values) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0e4ac94784..44594d12e6 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -fc3a044c567a8702ed1500d745170c365dd6b3d4 \ No newline at end of file +dd41df756253a9e711eb0fd0c3e007284f600ee8 \ No newline at end of file From b76829c72550f467447a8a5673dbe442c84dc1f0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 1 Nov 2022 15:55:21 -0700 Subject: [PATCH 0147/1179] docs: expose available openpilot longitudinal control (#26312) * openpilot -> openpilot available * note for dsu cars * common footnotes * Revert "note for dsu cars" - another PR This reverts commit 7f18742fdaaf5f86a1f1caa041b8b027d4b767cf. * space * better? * Update selfdrive/car/docs_definitions.py Co-authored-by: Adeeb Shihadeh * typo Co-authored-by: Adeeb Shihadeh --- docs/CARS.md | 201 +++++++++++++++--------------- selfdrive/car/docs.py | 6 +- selfdrive/car/docs_definitions.py | 17 ++- 3 files changed, 120 insertions(+), 104 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 2df2b96e24..b79ba6a478 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -10,17 +10,17 @@ A supported vehicle is one that just works when you install a comma three. All s |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Acura|RDX 2019-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|Q3 2020-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Cadillac|Escalade ESV 2016[1](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| +|Cadillac|Escalade ESV 2016[2](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Silverado 1500 2020-21|Safety Package II|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Chevrolet|Volt 2017-18[1](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| +|Chevrolet|Volt 2017-18[2](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| @@ -28,35 +28,35 @@ A supported vehicle is one that just works when you install a comma three. All s |Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Genesis|G70 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| +|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Genesis|G90 2017-18|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|GMC|Acadia 2018[1](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| +|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|GMC|Acadia 2018[2](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |GMC|Sierra 1500 2020-21|Driver Alert Package II|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Honda|Accord 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Accord Hybrid 2018-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Civic 2019-21|All|openpilot|0 mph|2 mph[2](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[3](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| |Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|CR-V 2017-22|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|e 2020|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Insight 2019-22|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Inspire 2018|All|openpilot|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| -|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| +|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Ioniq 5 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| @@ -65,22 +65,22 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I| -|Hyundai|Palisade 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Santa Fe 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D| -|Hyundai|Santa Fe 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Santa Fe Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D| +|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Sonata 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Hyundai|Sonata Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Hyundai|Sonata 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| +|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Tucson Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| @@ -88,38 +88,38 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Kia|EV6 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| |Kia|EV6 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| -|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Kia|Niro EV 2019|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Kia|Niro EV 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Kia|Niro EV 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Niro EV 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| +|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| +|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| |Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Telluride 2020|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Kia|Telluride 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|ES Hybrid 2017-18|Lexus Safety System+|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|ES Hybrid 2017-18|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|NX 2018-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|NX 2018-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|NX Hybrid 2018-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|NX Hybrid 2018-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2016|Lexus Safety System+|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2017-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX 2016|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|RX Hybrid 2016|Lexus Safety System+|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX Hybrid 2017-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX Hybrid 2016|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX Hybrid 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| @@ -141,8 +141,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Škoda|Kamiq 2021[5](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Karoq 2019-21[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Škoda|Kamiq 2021[6](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Škoda|Karoq 2019-21[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| @@ -150,85 +150,86 @@ A supported vehicle is one that just works when you install a comma three. All s |Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Avalon 2016|Toyota Safety Sense P|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2017-18|All|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2019-21|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon 2016|Toyota Safety Sense P|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon 2017-18|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon 2019-21|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Avalon Hybrid 2019-21|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon Hybrid 2019-21|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry 2018-20|All|Stock|0 mph[4](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry 2021-22|All|openpilot|0 mph[4](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Camry 2018-20|All|Stock|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Camry 2021-22|All|openpilot|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Camry Hybrid 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla 2017-19|All|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Corolla 2017-19|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross (Non-US only) 2020-21|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander 2017-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Highlander 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Highlander 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander Hybrid 2017-19|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Highlander Hybrid 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius 2016|Toyota Safety Sense P|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Prius 2017-20|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius 2016|Toyota Safety Sense P|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius 2017-20|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius Prime 2017-20|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius Prime 2017-20|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius v 2017|Toyota Safety Sense P|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 2016|Toyota Safety Sense P|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 2017-18|All|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius v 2017|Toyota Safety Sense P|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|RAV4 2016|Toyota Safety Sense P|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|RAV4 2017-18|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2017-18|All|Stock[3](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|RAV4 Hybrid 2017-18|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Sienna 2018-20|All|Stock[3](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Volkswagen|Arteon 2018-22[7,8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon eHybrid 2020-22[7,8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon R 2020-22[7,8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas 2018-23[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas Cross Sport 2021-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|California 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Caravelle 2020[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|CC 2018-22[7,8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Toyota|Sienna 2018-20|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Volkswagen|Arteon 2018-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon eHybrid 2020-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon R 2020-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas 2018-23[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas Cross Sport 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|California 2021[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Caravelle 2020[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|CC 2018-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf 2015-20[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Volkswagen|Golf 2015-20[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf R 2015-19[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Volkswagen|Golf R 2015-19[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Jetta 2018-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta GLI 2021-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat 2015-22[6,7,8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat Alltrack 2015-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat GTE 2015-22[7,8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo 2020-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo GTI 2020-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|T-Cross 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|T-Roc 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Taos 2022[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont 2018-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont Cross Sport 2021-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont X 2021-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Tiguan 2019-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta 2018-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta GLI 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat 2015-22[7,8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat Alltrack 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat GTE 2015-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Polo 2020-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Polo GTI 2020-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|T-Cross 2021[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|T-Roc 2021[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Taos 2022[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont 2018-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont Cross Sport 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont X 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Tiguan 2019-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -1Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
-22019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-3When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
-4openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
-5Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
-6Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
-7Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). In the interim, if your car has a J533 connector CAN gateway inside the dashboard, choose "VW J533 Development" from the vehicle drop-down for a suitable harness. (Some newer models are also observed to not have a J533 connector.)
-8Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.)
+1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).
+2Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
+32019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
+4When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
+5openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
+6Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
+7Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
+8Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). In the interim, if your car has a J533 connector CAN gateway inside the dashboard, choose "VW J533 Development" from the vehicle drop-down for a suitable harness. (Some newer models are also observed to not have a J533 connector.)
+9Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.)
## Community Maintained Cars Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index e948698cb4..6e271fb5cb 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -9,12 +9,12 @@ from typing import Dict, List from common.basedir import BASEDIR from selfdrive.car import gen_empty_fingerprint -from selfdrive.car.docs_definitions import CarInfo, Column +from selfdrive.car.docs_definitions import CarInfo, Column, CommonFootnote from selfdrive.car.car_helpers import interfaces, get_interface_attr def get_all_footnotes() -> Dict[Enum, int]: - all_footnotes = [] + all_footnotes = list(CommonFootnote) for footnotes in get_interface_attr("Footnote", ignore_none=True).values(): all_footnotes.extend(footnotes) return {fn: idx + 1 for idx, fn in enumerate(all_footnotes)} @@ -28,7 +28,7 @@ def get_all_car_info() -> List[CarInfo]: all_car_info: List[CarInfo] = [] footnotes = get_all_footnotes() for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items(): - CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), experimental_long=True) + CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint()) if CP.dashcamOnly or car_info is None: continue diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 015877dcb4..9a2a4b1427 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -71,6 +71,13 @@ class Harness(Enum): CarFootnote = namedtuple("CarFootnote", ["text", "column"], defaults=[None]) +class CommonFootnote(Enum): + EXP_LONG_AVAIL = CarFootnote( + "Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. " + + "Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).", + Column.LONGITUDINAL) + + def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]: # Returns applicable footnotes given current column return [fn for fn in footnotes if fn.value.column == column] @@ -128,11 +135,19 @@ class CarInfo: self.car_name = CP.carName self.car_fingerprint = CP.carFingerprint self.make, self.model, self.years = split_name(self.name) + + op_long = "Stock" + if CP.openpilotLongitudinalControl: + op_long = "openpilot" + elif CP.experimentalLongitudinalAvailable: + op_long = "openpilot available" + self.footnotes.append(CommonFootnote.EXP_LONG_AVAIL) + self.row = { Column.MAKE: self.make, Column.MODEL: self.model, Column.PACKAGE: self.package, - Column.LONGITUDINAL: "openpilot" if CP.openpilotLongitudinalControl or CP.experimentalLongitudinalAvailable else "Stock", + Column.LONGITUDINAL: op_long, Column.FSR_LONGITUDINAL: f"{max(self.min_enable_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.STEERING_TORQUE: Star.EMPTY, From fcd6125debeb97ba4b8870f5945c8215449c00fe Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Tue, 1 Nov 2022 19:16:37 -0700 Subject: [PATCH 0148/1179] Compute zoom level and downsample image in map_renderer.cc (#26315) * Automatically zoom to fixed scale in map_renderer.cc * Always downsample in map_renderer * Remove updateZoom function * Added mapsd to process_config.py (commented out for now) --- selfdrive/manager/process_config.py | 1 + selfdrive/navd/map_renderer.cc | 66 +++++++++++++++++------------ selfdrive/navd/map_renderer.h | 1 - selfdrive/navd/map_renderer.py | 3 +- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 3f63fbb959..dbccb8d4a9 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -31,6 +31,7 @@ procs = [ NativeProcess("encoderd", "selfdrive/loggerd", ["./encoderd"]), NativeProcess("loggerd", "selfdrive/loggerd", ["./loggerd"], onroad=False, callback=logging), NativeProcess("modeld", "selfdrive/modeld", ["./modeld"]), + # NativeProcess("mapsd", "selfdrive/navd", ["./map_renderer"]), NativeProcess("sensord", "selfdrive/sensord", ["./sensord"], enabled=not PC), NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=(not PC or WEBCAM)), NativeProcess("ui", "selfdrive/ui", ["./ui"], offroad=True, watchdog_max_dt=(5 if not PC else None)), diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index f85916a4ca..daf89b2636 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -1,5 +1,6 @@ #include "selfdrive/navd/map_renderer.h" +#include #include #include #include @@ -10,11 +11,34 @@ #include "selfdrive/ui/qt/maps/map_helpers.h" const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear -const int WIDTH = 512; -const int HEIGHT = WIDTH; - +const int RENDER_HEIGHT = 512, RENDER_WIDTH = 512; +const int HEIGHT = 256, WIDTH = 256; const int NUM_VIPC_BUFFERS = 4; +const int EARTH_CIRCUMFERENCE_METERS = 40075000; +const int PIXELS_PER_TILE = 256; + +float get_meters_per_pixel(float lat, float zoom) { + float num_tiles = pow(2, zoom+1); + float meters_per_tile = cos(DEG2RAD(lat)) * EARTH_CIRCUMFERENCE_METERS / num_tiles; + return meters_per_tile / PIXELS_PER_TILE; +} + +float get_zoom_level_for_scale(float lat, float meters_per_pixel) { + float meters_per_tile = meters_per_pixel * PIXELS_PER_TILE; + float num_tiles = cos(DEG2RAD(lat)) * EARTH_CIRCUMFERENCE_METERS / meters_per_tile; + return log2(num_tiles) - 1; +} + +void downsample(uint8_t *src, uint8_t *dst) { + for (int r = 0; r < HEIGHT; r++) { + for (int c = 0; c < WIDTH; c++) { + dst[r*WIDTH + c] = src[(r*2*RENDER_WIDTH + c*2) * 3]; + } + } +} + + MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_settings(settings) { QSurfaceFormat fmt; fmt.setRenderableType(QSurfaceFormat::OpenGLES); @@ -35,7 +59,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set gl_functions->initializeOpenGLFunctions(); QOpenGLFramebufferObjectFormat fbo_format; - fbo.reset(new QOpenGLFramebufferObject(WIDTH, HEIGHT, fbo_format)); + fbo.reset(new QOpenGLFramebufferObject(RENDER_WIDTH, RENDER_HEIGHT, fbo_format)); std::string style = util::read_file(STYLE_PATH); m_map.reset(new QMapboxGL(nullptr, m_settings, fbo->size(), 1)); @@ -45,7 +69,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set m_map->resize(fbo->size()); m_map->setFramebufferObject(fbo->handle(), fbo->size()); - gl_functions->glViewport(0, 0, WIDTH, HEIGHT); + gl_functions->glViewport(0, 0, RENDER_WIDTH, RENDER_HEIGHT); if (online) { vipc_server.reset(new VisionIpcServer("navd")); @@ -85,22 +109,18 @@ void MapRenderer::msgUpdate() { } } -void MapRenderer::updateZoom(float zoom) { - if (m_map.isNull()) { - return; - } - - m_map->setZoom(zoom); - update(); -} - void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) { if (m_map.isNull()) { return; } + // Choose a zoom level that matches the scale of zoom level 13 at latitude 80deg + float scale_lat80 = get_meters_per_pixel(80, 13); + float zoom = get_zoom_level_for_scale(position.first, scale_lat80); + m_map->setCoordinate(position); m_map->setBearing(bearing); + m_map->setZoom(zoom); update(); } @@ -130,15 +150,13 @@ void MapRenderer::sendVipc() { .timestamp_eof = ts, }; - assert(cap.sizeInBytes() >= buf->len); + assert(cap.sizeInBytes() >= buf->len*4); uint8_t* dst = (uint8_t*)buf->addr; uint8_t* src = cap.bits(); - // RGB to greyscale + // 2x downsample + rgb to grayscale memset(dst, 128, buf->len); - for (int i = 0; i < WIDTH * HEIGHT; i++) { - dst[i] = src[i * 3]; - } + downsample(src, dst); vipc_server->send(buf, &extra); @@ -169,9 +187,8 @@ uint8_t* MapRenderer::getImage() { uint8_t* src = cap.bits(); uint8_t* dst = new uint8_t[WIDTH * HEIGHT]; - for (int i = 0; i < WIDTH * HEIGHT; i++) { - dst[i] = src[i * 3]; - } + // 2x downsample + rgb to grayscale + downsample(src, dst); return dst; } @@ -222,11 +239,6 @@ extern "C" { return new MapRenderer(settings, false); } - void map_renderer_update_zoom(MapRenderer *inst, float zoom) { - inst->updateZoom(zoom); - QApplication::processEvents(); - } - void map_renderer_update_position(MapRenderer *inst, float lat, float lon, float bearing) { inst->updatePosition({lat, lon}, bearing); QApplication::processEvents(); diff --git a/selfdrive/navd/map_renderer.h b/selfdrive/navd/map_renderer.h index 921d871632..855dc91894 100644 --- a/selfdrive/navd/map_renderer.h +++ b/selfdrive/navd/map_renderer.h @@ -47,7 +47,6 @@ private: QTimer* timer; public slots: - void updateZoom(float zoom); void updatePosition(QMapbox::Coordinate position, float bearing); void updateRoute(QList coordinates); void msgUpdate(); diff --git a/selfdrive/navd/map_renderer.py b/selfdrive/navd/map_renderer.py index 079bb028ce..9000622928 100755 --- a/selfdrive/navd/map_renderer.py +++ b/selfdrive/navd/map_renderer.py @@ -9,7 +9,7 @@ from cffi import FFI from common.ffi_wrapper import suffix from common.basedir import BASEDIR -HEIGHT = WIDTH = 512 +HEIGHT = WIDTH = 256 def get_ffi(): @@ -18,7 +18,6 @@ def get_ffi(): ffi = FFI() ffi.cdef(""" void* map_renderer_init(char *maps_host, char *token); -void map_renderer_update_zoom(void *inst, float zoom); void map_renderer_update_position(void *inst, float lat, float lon, float bearing); void map_renderer_update_route(void *inst, char *polyline); void map_renderer_update(void *inst); From bdbdd42d5b736c2d10d2e586c382a5989b38a250 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 1 Nov 2022 23:04:13 -0700 Subject: [PATCH 0149/1179] test_onroad: temp disable max UI draw time check --- selfdrive/test/test_onroad.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 0d3d7b367a..df8112c75f 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -202,9 +202,9 @@ class TestOnroad(unittest.TestCase): print(result) self.assertGreater(len(ts), 20*50, "insufficient samples") - self.assertLess(max(ts), 30.) + #self.assertLess(max(ts), 30.) self.assertLess(np.mean(ts), 10.) - self.assertLess(np.std(ts), 5.) + #self.assertLess(np.std(ts), 5.) def test_cpu_usage(self): proclogs = [m for m in self.lr if m.which() == 'procLog'] From 0f6f305f2da81c30aef849bc55c76e57ebe5e34d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 01:58:15 -0700 Subject: [PATCH 0150/1179] GM: add longitudinal deadzone (#26323) * add deadzone * Update ref_commit --- selfdrive/car/gm/interface.py | 3 +++ selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index e25f203772..905b85436a 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -90,6 +90,9 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kiBP = [0.] ret.longitudinalTuning.kiV = [0.36] + ret.longitudinalTuning.deadzoneBP = [0.] + ret.longitudinalTuning.deadzoneV = [0.15] + ret.steerLimitTimer = 0.4 ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 44594d12e6..1682d5eb14 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -dd41df756253a9e711eb0fd0c3e007284f600ee8 \ No newline at end of file +7828f8a2e00a5b73471a90850b18874617e82610 From 423d16693a4d805db2035dcd87f120b2902c2c4a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 02:09:54 -0700 Subject: [PATCH 0151/1179] Toyota: unify deadzone params (#26325) * i'm sure this makes no difference * update refs --- selfdrive/car/toyota/interface.py | 8 +++----- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 0d5acbfff4..e6a7dac412 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -208,18 +208,16 @@ class CarInterface(CarInterfaceBase): ret.minEnableSpeed = -1. if (stop_and_go or ret.enableGasInterceptor) else MIN_ACC_SPEED tune = ret.longitudinalTuning + tune.deadzoneBP = [0., 9.] + tune.deadzoneV = [.0, .15] if candidate in TSS2_CAR or ret.enableGasInterceptor: - tune.deadzoneBP = [0., 8.05] - tune.deadzoneV = [.0, .14] tune.kpBP = [0., 5., 20.] tune.kpV = [1.3, 1.0, 0.7] tune.kiBP = [0., 5., 12., 20., 27.] tune.kiV = [.35, .23, .20, .17, .1] if candidate in TSS2_CAR: - ret.stoppingDecelRate = 0.3 # reach stopping target smoothly + ret.stoppingDecelRate = 0.3 # reach stopping target smoothly else: - tune.deadzoneBP = [0., 9.] - tune.deadzoneV = [.0, .15] tune.kpBP = [0., 5., 35.] tune.kiBP = [0., 35.] tune.kpV = [3.6, 2.4, 1.5] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1682d5eb14..be8b59f6a4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -7828f8a2e00a5b73471a90850b18874617e82610 +46922acfb984342daa35734e4297ff9d2ddfb18b \ No newline at end of file From e3188c0b1fb8bd02cf22a774fa70057424d3d8db Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 02:10:11 -0700 Subject: [PATCH 0152/1179] PJ: add longitudinal layout (#26324) longitudinal layout --- tools/plotjuggler/layouts/longitudinal.xml | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tools/plotjuggler/layouts/longitudinal.xml diff --git a/tools/plotjuggler/layouts/longitudinal.xml b/tools/plotjuggler/layouts/longitudinal.xml new file mode 100644 index 0000000000..ff8f3ad193 --- /dev/null +++ b/tools/plotjuggler/layouts/longitudinal.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2fb7b4ffad204901033273f6f92f289bbce19f06 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 02:46:29 -0700 Subject: [PATCH 0153/1179] GM camera ACC: vision-only ACC behind toggle (#25631) * put gm camera voacc behind disable radar toggle * bump panda * bump panda * bump panda * experimental long * fixes * car control notes and fixes for Bolt EUV * might enable stop and go * consistent name * min enable speed seems to be around 5 kph * camera acc can engage under 5 kph if stopped * comment * comment * remove this for now * only real brake * comments * update max brake * bump * clean up/fix * same if * simplify * fix * old comment * no brake_pressed * temporary fault fix * tune longitudinal * update docs * bump panda * GM camera ACC cars have no regen in ACC * cleaner * cleaner * fix * set max gas * fixes * fix LKAS unavailable warning from camera * only camera * bump panda * bump panda * bump panda * bump panda * clean up gmcan * clean up CC * flip * rm * rm comment * clean up * custom starting/stopping probably not needed * Update selfdrive/car/gm/carcontroller.py * fix crash * long tuning * we need long control state to resume * CAMERA_ACC_CAR not needed * no interp on accel * tuning * formatting * formatting * formatting * formatting * formatting * no need to init ccp * makes more sense now --- docs/CARS.md | 6 ++-- selfdrive/car/gm/carcontroller.py | 22 ++++++++----- selfdrive/car/gm/gmcan.py | 10 ++++-- selfdrive/car/gm/interface.py | 38 ++++++++++++++------- selfdrive/car/gm/values.py | 42 ++++++++++++++---------- selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 77 insertions(+), 43 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index b79ba6a478..af2c3007a4 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -18,8 +18,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Cadillac|Escalade ESV 2016[2](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Volt 2017-18[2](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| @@ -32,7 +32,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |GMC|Acadia 2018[2](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|Stock|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index a75eb89f25..a6cd2f19b9 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -5,10 +5,11 @@ from common.realtime import DT_CTRL from opendbc.can.packer import CANPacker from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.gm import gmcan -from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons, EV_CAR +from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons VisualAlert = car.CarControl.HUDControl.VisualAlert NetworkLocation = car.CarParams.NetworkLocation +LongCtrlState = car.CarControl.Actuators.LongControlState # Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s CAMERA_CANCEL_DELAY_FRAMES = 10 @@ -30,7 +31,7 @@ class CarController: self.sent_lka_steering_cmd = False self.lka_icon_status_last = (False, False) - self.params = CarControllerParams() + self.params = CarControllerParams(self.CP) self.packer_pt = CANPacker(DBC[self.CP.carFingerprint]['pt']) self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) @@ -83,20 +84,23 @@ class CarController: self.apply_gas = self.params.INACTIVE_REGEN self.apply_brake = 0 else: - if self.CP.carFingerprint in EV_CAR: - self.apply_gas = int(round(interp(actuators.accel, self.params.EV_GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) - self.apply_brake = int(round(interp(actuators.accel, self.params.EV_BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) - else: - self.apply_gas = int(round(interp(actuators.accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) - self.apply_brake = int(round(interp(actuators.accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) + self.apply_gas = int(round(interp(actuators.accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) + self.apply_brake = int(round(interp(actuators.accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) idx = (self.frame // 4) % 4 at_full_stop = CC.longActive and CS.out.standstill near_stop = CC.longActive and (CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE) + friction_brake_bus = CanBus.CHASSIS + # GM Camera exceptions + # TODO: can we always check the longControlState? + if self.CP.networkLocation == NetworkLocation.fwdCamera: + at_full_stop = at_full_stop and actuators.longControlState == LongCtrlState.stopping + friction_brake_bus = CanBus.POWERTRAIN + # GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, CC.enabled, at_full_stop)) - can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, CanBus.CHASSIS, self.apply_brake, idx, near_stop, at_full_stop)) + can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake, idx, CC.enabled, near_stop, at_full_stop, self.CP)) # Send dashboard UI commands (ACC status) send_fcw = hud_alert == VisualAlert.fcw diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 42df2c6afd..56c981326f 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -1,4 +1,5 @@ from selfdrive.car import make_can_msg +from selfdrive.car.gm.values import CAR def create_buttons(packer, bus, idx, button): @@ -52,15 +53,20 @@ def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop): return packer.make_can_msg("ASCMGasRegenCmd", bus, values) -def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_full_stop): +def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_stop, at_full_stop, CP): mode = 0x1 + + # TODO: Understand this better. Volts and ICE Camera ACC cars are 0x1 when enabled with no brake + if enabled and CP.carFingerprint in (CAR.BOLT_EUV,): + mode = 0x9 + if apply_brake > 0: mode = 0xa if at_full_stop: mode = 0xd # TODO: this is to have GM bringing the car to complete stop, - # but currently it conflicts with OP controls, so turned off. + # but currently it conflicts with OP controls, so turned off. Not set by all cars #elif near_stop: # mode = 0xb diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 905b85436a..9ef7f388ff 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -20,8 +20,7 @@ BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.D class CarInterface(CarInterfaceBase): @staticmethod def get_pid_accel_limits(CP, current_speed, cruise_speed): - params = CarControllerParams() - return params.ACCEL_MIN, params.ACCEL_MAX + return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX # Determined by iteratively plotting and minimizing error for f(angle, speed) = steer. @staticmethod @@ -56,13 +55,34 @@ class CarInterface(CarInterfaceBase): else: ret.transmissionType = TransmissionType.automatic + ret.longitudinalTuning.deadzoneBP = [0.] + ret.longitudinalTuning.deadzoneV = [0.15] + + ret.longitudinalTuning.kpBP = [5., 35.] + ret.longitudinalTuning.kiBP = [0.] + if candidate in CAMERA_ACC_CAR: - ret.openpilotLongitudinalControl = False + ret.experimentalLongitudinalAvailable = True ret.networkLocation = NetworkLocation.fwdCamera ret.radarOffCan = True # no radar ret.pcmCruise = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.minEnableSpeed = 5 * CV.KPH_TO_MS + + if experimental_long: + ret.pcmCruise = False + ret.openpilotLongitudinalControl = True + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG + + # Tuning + ret.longitudinalTuning.kpV = [2.0, 1.5] + ret.longitudinalTuning.kiV = [0.72] + ret.stopAccel = -2.0 + ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling + ret.vEgoStopping = 0.25 + ret.vEgoStarting = 0.25 + ret.longitudinalActuatorDelayUpperBound = 0.5 + else: # ASCM, OBD-II harness ret.openpilotLongitudinalControl = True ret.networkLocation = NetworkLocation.gateway @@ -71,6 +91,10 @@ class CarInterface(CarInterfaceBase): # supports stop and go, but initial engage must (conservatively) be above 18mph ret.minEnableSpeed = 18 * CV.MPH_TO_MS + # Tuning + ret.longitudinalTuning.kpV = [2.4, 1.5] + ret.longitudinalTuning.kiV = [0.36] + # These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars likely still work fine. Once a user confirms each car works and a test route is # added to selfdrive/car/tests/routes.py, we can remove it from this list. @@ -85,14 +109,6 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.1 # Default delay, not measured yet tire_stiffness_factor = 0.444 # not optimized yet - ret.longitudinalTuning.kpBP = [5., 35.] - ret.longitudinalTuning.kpV = [2.4, 1.5] - ret.longitudinalTuning.kiBP = [0.] - ret.longitudinalTuning.kiV = [0.36] - - ret.longitudinalTuning.deadzoneBP = [0.] - ret.longitudinalTuning.deadzoneV = [0.15] - ret.steerLimitTimer = 0.4 ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 85e291aaf6..eace6b6aca 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -24,15 +24,6 @@ class CarControllerParams: ADAS_KEEPALIVE_STEP = 100 CAMERA_KEEPALIVE_STEP = 100 - # Volt gas/brake lookups - # TODO: These values should be confirmed on non-Volt vehicles. - # MAX_GAS should achieve 2 m/s^2 and MAX_BRAKE with regen should achieve -4.0 m/s^2 - MAX_GAS = 3072 # Safety limit, not ACC max. Stock ACC >4096 from standstill. - ZERO_GAS = 2048 # Coasting - MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen - MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen - INACTIVE_REGEN = 1404 - # Allow small margin below -3.5 m/s^2 from ISO 15622:2018 since we # perform the closed loop control, and might need some # to apply some more braking if we're on a downhill slope. @@ -41,15 +32,32 @@ class CarControllerParams: ACCEL_MAX = 2. # m/s^2 ACCEL_MIN = -4. # m/s^2 - # ICE has much less engine braking force compared to regen in EVs, - # lower threshold removes some braking deadzone - GAS_LOOKUP_BP = [-0.1, 0., ACCEL_MAX] - EV_GAS_LOOKUP_BP = [-1., 0., ACCEL_MAX] - GAS_LOOKUP_V = [MAX_ACC_REGEN, ZERO_GAS, MAX_GAS] + def __init__(self, CP): + # Gas/brake lookups + self.ZERO_GAS = 2048 # Coasting + self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen - BRAKE_LOOKUP_BP = [ACCEL_MIN, -0.1] - EV_BRAKE_LOOKUP_BP = [ACCEL_MIN, -1.] - BRAKE_LOOKUP_V = [MAX_BRAKE, 0.] + if CP.carFingerprint in CAMERA_ACC_CAR: + self.MAX_GAS = 3400 + self.MAX_ACC_REGEN = 1514 + self.INACTIVE_REGEN = 1554 + # Camera ACC vehicles have no regen while enabled. + # Camera transitions to MAX_ACC_REGEN from ZERO_GAS and uses friction brakes instantly + max_regen_acceleration = 0. + + else: + self.MAX_GAS = 3072 # Safety limit, not ACC max. Stock ACC >4096 from standstill. + self.MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen + self.INACTIVE_REGEN = 1404 + # ICE has much less engine braking force compared to regen in EVs, + # lower threshold removes some braking deadzone + max_regen_acceleration = -1. if CP.carFingerprint in EV_CAR else -0.1 + + self.GAS_LOOKUP_BP = [max_regen_acceleration, 0., self.ACCEL_MAX] + self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, self.ZERO_GAS, self.MAX_GAS] + + self.BRAKE_LOOKUP_BP = [self.ACCEL_MIN, max_regen_acceleration] + self.BRAKE_LOOKUP_V = [self.MAX_BRAKE, 0.] class CAR: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index be8b59f6a4..7b5d954c43 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -46922acfb984342daa35734e4297ff9d2ddfb18b \ No newline at end of file +d37afafc466661262b34631e32e4c383f1277bc5 \ No newline at end of file From 4c90bb8635d460c1a574f3ab3d7aa264179c197e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 3 Nov 2022 01:45:54 +0800 Subject: [PATCH 0154/1179] cabana: optimize chart update (#26327) optimize update --- tools/cabana/chartswidget.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 72c9c40570..85284af6fc 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -325,7 +325,6 @@ void ChartView::updateLineMarker(double current_sec) { 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, 0, x, height()); - chart()->update(); } } @@ -410,6 +409,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } else { QGraphicsView::mouseReleaseEvent(event); } + setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); } void ChartView::mouseMoveEvent(QMouseEvent *ev) { @@ -436,6 +436,8 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { track_line->setVisible(value != vals.end()); value_text->setVisible(value != vals.end()); track_ellipse->setVisible(value != vals.end()); + } else { + setViewportUpdateMode(QGraphicsView::FullViewportUpdate); } QChartView::mouseMoveEvent(ev); } From e355d7383fbd1840f1d8f7e56cec3dba6f4f1d2a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 3 Nov 2022 01:46:17 +0800 Subject: [PATCH 0155/1179] Cabana: add y-axis padding (#26326) add padding --- tools/cabana/chartswidget.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 85284af6fc..3782f381e8 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -368,8 +368,13 @@ void ChartView::updateAxisY() { 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(); }); - (min->y() == max->y()) ? axis_y->setRange(min->y() - 1, max->y() + 1) - : axis_y->setRange(min->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(); + } } void ChartView::enterEvent(QEvent *event) { From fdd125853fad2909fa2eff37822a0715d3a219c1 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 2 Nov 2022 14:42:29 -0700 Subject: [PATCH 0156/1179] camerad: fix OX not having vignetting comp (#26329) --- system/camerad/cameras/real_debayer.cl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/camerad/cameras/real_debayer.cl b/system/camerad/cameras/real_debayer.cl index 59aa488653..cff5ae455b 100644 --- a/system/camerad/cameras/real_debayer.cl +++ b/system/camerad/cameras/real_debayer.cl @@ -72,7 +72,7 @@ float4 val4_from_12(uchar8 pvs, float gain) { float4 pv = {ox03c10_lut[parsed.s0], ox03c10_lut[parsed.s1], ox03c10_lut[parsed.s2], ox03c10_lut[parsed.s3]}; // it's a 24 bit signal, center in the middle 8 bits - return pv*256.0; + return clamp(pv*gain*256.0, 0.0, 1.0); #else // AR // normalize and scale float4 pv = (convert_float4(parsed) - 168.0) / (4096.0 - 168.0); From 0589ff23a52efb90269d270f13a3d921176d377b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 2 Nov 2022 15:51:52 -0700 Subject: [PATCH 0157/1179] bump up controlsd cpu usage --- selfdrive/test/test_onroad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index df8112c75f..4021e27de3 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -21,7 +21,7 @@ from tools.lib.logreader import LogReader # Baseline CPU usage by process PROCS = { - "selfdrive.controls.controlsd": 35.0, + "selfdrive.controls.controlsd": 39.0, "./loggerd": 10.0, "./encoderd": 17.0, "./camerad": 14.5, From d58c19c5762545839df97ae282a4c43826e6960d Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Thu, 3 Nov 2022 00:34:02 +0100 Subject: [PATCH 0158/1179] CI: add LSM-C sensor device (#26303) * add sensord tests to pipeline * . * cleanup * redo * . * address comments * Update Jenkinsfile Co-authored-by: Kurt Nistelberger Co-authored-by: Adeeb Shihadeh --- Jenkinsfile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index b9b9eda667..ea62ff3c49 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -148,6 +148,16 @@ pipeline { } } + stage('sensord (LSM-C)') { + agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } + steps { + phone_steps("tici-lsmc", [ + ["build", "cd selfdrive/manager && ./build.py"], + ["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"], + ]) + } + } + stage('replay') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { From 21ac65da22dc8bce4ba88a520e8550829ea81ab6 Mon Sep 17 00:00:00 2001 From: Igor Biletskyy Date: Wed, 2 Nov 2022 17:36:29 -0700 Subject: [PATCH 0159/1179] bump panda (#26334) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 0ca6d9d924..9147cba1af 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 0ca6d9d9248f2cea4ef2292671b6980b416c3f4b +Subproject commit 9147cba1af0a8d72379242eb1ce0bfd42ab8075e From e634afb719e9ea787155272b3d2fe64b385bcb7d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 17:55:53 -0700 Subject: [PATCH 0160/1179] GM: fix fault while moving backwards (#26333) * log signed speed * bump to master * need this * fix * fix... * see if this works * just fault fix (no logging or standstill. tho revisit standstill) * move * Revert "move" This reverts commit c564e74666e3a418ef43a77926c8a38a2bf89511. --- opendbc | 2 +- selfdrive/car/gm/carstate.py | 2 ++ selfdrive/car/gm/interface.py | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/opendbc b/opendbc index b3dc569994..296f190000 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit b3dc569994fd10e4de04afd650980c51ddfce5e1 +Subproject commit 296f190000a2e71408e207ba21a2257cc853ec15 diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 7cb2274674..af69307a2c 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -28,6 +28,7 @@ class CarState(CarStateBase): self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"]) + self.moving_backward = pt_cp.vl["EBCMWheelSpdRear"]["MovingBackward"] != 0 # Variables used for avoiding LKAS faults self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 @@ -139,6 +140,7 @@ class CarState(CarStateBase): ("FRWheelSpd", "EBCMWheelSpdFront"), ("RLWheelSpd", "EBCMWheelSpdRear"), ("RRWheelSpd", "EBCMWheelSpdRear"), + ("MovingBackward", "EBCMWheelSpdRear"), ("PRNDL2", "ECMPRDNL2"), ("ManualMode", "ECMPRDNL2"), ("LKADriverAppldTrq", "PSCMStatus"), diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 9ef7f388ff..2420098b4a 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -225,8 +225,9 @@ class CarInterface(CarInterfaceBase): # Enabling at a standstill with brake is allowed # TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs - if ret.vEgo < self.CP.minEnableSpeed and not (ret.standstill and ret.brake >= 20 and - self.CP.networkLocation == NetworkLocation.fwdCamera): + below_min_enable_speed = ret.vEgo < self.CP.minEnableSpeed or self.CS.moving_backward + if below_min_enable_speed and not (ret.standstill and ret.brake >= 20 and + self.CP.networkLocation == NetworkLocation.fwdCamera): events.add(EventName.belowEngageSpeed) if ret.cruiseState.standstill: events.add(EventName.resumeRequired) From 735af656a034ea960ece8e346227225adfd6d4b2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 18:56:26 -0700 Subject: [PATCH 0161/1179] car docs: docs-only footnote flag (#26335) docs-only footnotes --- selfdrive/car/docs_definitions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 9a2a4b1427..dbe1886917 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -68,14 +68,14 @@ class Harness(Enum): none = "None" -CarFootnote = namedtuple("CarFootnote", ["text", "column"], defaults=[None]) +CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only"], defaults=(None, False)) class CommonFootnote(Enum): EXP_LONG_AVAIL = CarFootnote( "Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. " + "Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).", - Column.LONGITUDINAL) + Column.LONGITUDINAL, docs_only=True) def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]: From b0656f2c751df64fb3974c66423470b7a59bc1e6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 20:12:35 -0700 Subject: [PATCH 0162/1179] Toyota: add unsupported DSU car list (#26336) * note for dsu cars * don't hardcode dsu footnote (1/2) * test * revert the experimental long toggle * another day:( * DSU doesn't have to be toyota specific, it's a generic carParam! * this is safe, just make sure it's unknown * these cars do not have OP long for some reason * UNSUPPORTED_DSU_CAR * forgot this * . * . * revert * revert * smaller diff --- selfdrive/car/toyota/carcontroller.py | 5 +++-- selfdrive/car/toyota/carstate.py | 8 ++++---- selfdrive/car/toyota/interface.py | 4 ++-- selfdrive/car/toyota/values.py | 5 ++++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index faea08ed3f..4ec9500171 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -5,7 +5,8 @@ from selfdrive.car.toyota.toyotacan import create_steer_command, create_ui_comma create_accel_command, create_acc_cancel_command, \ create_fcw_command, create_lta_steer_command from selfdrive.car.toyota.values import CAR, STATIC_DSU_MSGS, NO_STOP_TIMER_CAR, TSS2_CAR, \ - MIN_ACC_SPEED, PEDAL_TRANSITION, CarControllerParams + MIN_ACC_SPEED, PEDAL_TRANSITION, CarControllerParams, \ + UNSUPPORTED_DSU_CAR from opendbc.can.packer import CANPacker VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -112,7 +113,7 @@ class CarController: lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged # Lexus IS uses a different cancellation message - if pcm_cancel_cmd and self.CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC): + if pcm_cancel_cmd and self.CP.carFingerprint in UNSUPPORTED_DSU_CAR: can_sends.append(create_acc_cancel_command(self.packer)) elif self.CP.openpilotLongitudinalControl: can_sends.append(create_accel_command(self.packer, pcm_accel_cmd, pcm_cancel_cmd, self.standstill_req, lead, CS.acc_type)) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 0cfba2b09f..4758149916 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -6,7 +6,7 @@ from common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from selfdrive.car.interfaces import CarStateBase -from selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE +from selfdrive.car.toyota.values import ToyotaFlags, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR class CarState(CarStateBase): @@ -87,7 +87,7 @@ class CarState(CarStateBase): # 17 is a fault from a prolonged high torque delta between cmd and user ret.steerFaultPermanent = cp.vl["EPS_STATUS"]["LKA_STATE"] == 17 - if self.CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC): + if self.CP.carFingerprint in UNSUPPORTED_DSU_CAR: ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0 ret.cruiseState.speed = cp.vl["DSU_CRUISE"]["SET_SPEED"] * CV.KPH_TO_MS cluster_set_speed = cp.vl["PCM_CRUISE_ALT"]["UI_SET_SPEED"] @@ -112,7 +112,7 @@ class CarState(CarStateBase): # these cars are identified by an ACC_TYPE value of 2. # TODO: it is possible to avoid the lockout and gain stop and go if you # send your own ACC_CONTROL msg on startup with ACC_TYPE set to 1 - if (self.CP.carFingerprint not in TSS2_CAR and self.CP.carFingerprint not in (CAR.LEXUS_IS, CAR.LEXUS_RC)) or \ + if (self.CP.carFingerprint not in TSS2_CAR and self.CP.carFingerprint not in UNSUPPORTED_DSU_CAR) or \ (self.CP.carFingerprint in TSS2_CAR and self.acc_type == 1): self.low_speed_lockout = cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2 @@ -196,7 +196,7 @@ class CarState(CarStateBase): signals.append(("GAS_PEDAL", "GAS_PEDAL")) checks.append(("GAS_PEDAL", 33)) - if CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC): + if CP.carFingerprint in UNSUPPORTED_DSU_CAR: signals.append(("MAIN_ON", "DSU_CRUISE")) signals.append(("SET_SPEED", "DSU_CRUISE")) signals.append(("UI_SET_SPEED", "PCM_CRUISE_ALT")) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index e6a7dac412..3ae1efe04f 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,7 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams +from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -189,7 +189,7 @@ class CarInterface(CarInterfaceBase): smartDsu = 0x2FF in fingerprint[0] # In TSS2 cars the camera does long control found_ecus = [fw.ecu for fw in car_fw] - ret.enableDsu = (len(found_ecus) > 0) and (Ecu.dsu not in found_ecus) and (candidate not in NO_DSU_CAR) and (not smartDsu) + ret.enableDsu = len(found_ecus) > 0 and Ecu.dsu not in found_ecus and candidate not in (NO_DSU_CAR | UNSUPPORTED_DSU_CAR) and not smartDsu ret.enableGasInterceptor = 0x201 in fingerprint[0] # if the smartDSU is detected, openpilot can send ACC_CMD (and the smartDSU will block it from the DSU) or not (the DSU is "connected") ret.openpilotLongitudinalControl = smartDsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 07c33d0173..acacfaea2d 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1363,7 +1363,7 @@ FW_VERSIONS = { ], (Ecu.engine, 0x700, None): [ b'\x01896634AA0000\x00\x00\x00\x00', - b'\x01896634AA0100\x00\x00\x00\x00', + b'\x01896634AA0100\x00\x00\x00\x00', b'\x01896634AA1000\x00\x00\x00\x00', b'\x01896634A88000\x00\x00\x00\x00', b'\x01896634A89000\x00\x00\x00\x00', @@ -2032,6 +2032,9 @@ TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TS NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} +# the DSU uses the AEB message for longitudinal on these cars +UNSUPPORTED_DSU_CAR = {CAR.LEXUS_IS, CAR.LEXUS_RC} + # these cars have a radar which sends ACC messages instead of the camera RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022} From 80e8d76d39b1e1992d1b6cf258aa8d878673ca10 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 2 Nov 2022 20:40:42 -0700 Subject: [PATCH 0163/1179] car docs: speedup test (#26337) * faster * faster --- selfdrive/car/tests/test_docs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py index b7056df5b3..e56f98f7a8 100755 --- a/selfdrive/car/tests/test_docs.py +++ b/selfdrive/car/tests/test_docs.py @@ -10,8 +10,9 @@ from selfdrive.car.honda.values import CAR as HONDA class TestCarDocs(unittest.TestCase): - def setUp(self): - self.all_cars = get_all_car_info() + @classmethod + def setUpClass(cls): + cls.all_cars = get_all_car_info() def test_generator(self): generated_cars_md = generate_cars_md(self.all_cars, CARS_MD_TEMPLATE) From 3e69973819ba337743d4d9c71d31369a761a688d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 3 Nov 2022 01:00:33 -0700 Subject: [PATCH 0164/1179] car docs: auto-generate footnote for DSU cars (#26321) * note for dsu cars * don't hardcode dsu footnote (1/2) * test * revert the experimental long toggle * another day:( * DSU doesn't have to be toyota specific, it's a generic carParam! * this is safe, just make sure it's unknown * these cars do not have OP long for some reason * UNSUPPORTED_DSU_CAR * forgot this * fix autoResume * fix autoResume 2 --- docs/CARS.md | 62 ++++++++++++------------ selfdrive/car/docs.py | 3 +- selfdrive/car/docs_definitions.py | 13 +++-- selfdrive/car/toyota/interface.py | 4 +- selfdrive/car/toyota/values.py | 52 +++++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 70 insertions(+), 66 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index af2c3007a4..ad288a1cc6 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -17,10 +17,10 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|Q3 2020-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Cadillac|Escalade ESV 2016[2](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Chevrolet|Volt 2017-18[2](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| @@ -31,12 +31,12 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|GMC|Acadia 2018[2](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[3](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| |Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| |Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| @@ -105,21 +105,21 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Telluride 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|ES Hybrid 2017-18|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|NX 2018-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|NX Hybrid 2018-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2016|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|RX Hybrid 2016|Lexus Safety System+|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX Hybrid 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| @@ -150,11 +150,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Avalon 2016|Toyota Safety Sense P|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2017-18|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2019-21|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Avalon Hybrid 2019-21|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| @@ -162,32 +162,32 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Camry 2021-22|All|openpilot|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Camry Hybrid 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla 2017-19|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross (Non-US only) 2020-21|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander Hybrid 2017-19|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius 2016|Toyota Safety Sense P|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Prius 2017-20|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius Prime 2017-20|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius v 2017|Toyota Safety Sense P|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 2016|Toyota Safety Sense P|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 2017-18|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2017-18|All|Stock[4](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Sienna 2018-20|All|Stock[4](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Volkswagen|Arteon 2018-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Arteon eHybrid 2020-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Volkswagen|Arteon R 2020-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| @@ -222,9 +222,9 @@ A supported vehicle is one that just works when you install a comma three. All s 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).
-2Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
-32019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-4When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
+2When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
+3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
+42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
5openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
6Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
7Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 6e271fb5cb..58afed27eb 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -7,6 +7,7 @@ from enum import Enum from natsort import natsorted from typing import Dict, List +from cereal import car from common.basedir import BASEDIR from selfdrive.car import gen_empty_fingerprint from selfdrive.car.docs_definitions import CarInfo, Column, CommonFootnote @@ -28,7 +29,7 @@ def get_all_car_info() -> List[CarInfo]: all_car_info: List[CarInfo] = [] footnotes = get_all_footnotes() for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items(): - CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint()) + CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")]) if CP.dashcamOnly or car_info is None: continue diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index dbe1886917..8e057a1563 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -76,6 +76,10 @@ class CommonFootnote(Enum): "Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. " + "Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).", Column.LONGITUDINAL, docs_only=True) + EXP_LONG_DSU = CarFootnote( + "When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace " + + "stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).", + Column.LONGITUDINAL) def get_footnotes(footnotes: List[Enum], column: Column) -> List[Enum]: @@ -137,11 +141,14 @@ class CarInfo: self.make, self.model, self.years = split_name(self.name) op_long = "Stock" - if CP.openpilotLongitudinalControl: + if CP.openpilotLongitudinalControl and not CP.enableDsu: op_long = "openpilot" - elif CP.experimentalLongitudinalAvailable: + elif CP.experimentalLongitudinalAvailable or CP.enableDsu: op_long = "openpilot available" - self.footnotes.append(CommonFootnote.EXP_LONG_AVAIL) + if CP.enableDsu: + self.footnotes.append(CommonFootnote.EXP_LONG_DSU) + else: + self.footnotes.append(CommonFootnote.EXP_LONG_AVAIL) self.row = { Column.MAKE: self.make, diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 3ae1efe04f..02e4caa9d6 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,7 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams +from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams, NO_STOP_TIMER_CAR from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -193,9 +193,9 @@ class CarInterface(CarInterfaceBase): ret.enableGasInterceptor = 0x201 in fingerprint[0] # if the smartDSU is detected, openpilot can send ACC_CMD (and the smartDSU will block it from the DSU) or not (the DSU is "connected") ret.openpilotLongitudinalControl = smartDsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) + ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR if not ret.openpilotLongitudinalControl: - ret.autoResumeSng = False ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_STOCK_LONGITUDINAL # we can't use the fingerprint to detect this reliably, since diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index acacfaea2d..9e96118085 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -87,10 +87,6 @@ class CAR: class Footnote(Enum): - DSU = CarFootnote( - "When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace " + - "stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).", - Column.LONGITUDINAL) CAMRY = CarFootnote( "openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.", Column.FSR_LONGITUDINAL) @@ -107,11 +103,11 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.ALPHARD_TSS2: ToyotaCarInfo("Toyota Alphard 2019-20"), CAR.ALPHARDH_TSS2: ToyotaCarInfo("Toyota Alphard Hybrid 2021"), CAR.AVALON: [ - ToyotaCarInfo("Toyota Avalon 2016", "Toyota Safety Sense P", footnotes=[Footnote.DSU]), - ToyotaCarInfo("Toyota Avalon 2017-18", footnotes=[Footnote.DSU]), + ToyotaCarInfo("Toyota Avalon 2016", "Toyota Safety Sense P"), + ToyotaCarInfo("Toyota Avalon 2017-18"), ], - CAR.AVALON_2019: ToyotaCarInfo("Toyota Avalon 2019-21", footnotes=[Footnote.DSU]), - CAR.AVALONH_2019: ToyotaCarInfo("Toyota Avalon Hybrid 2019-21", footnotes=[Footnote.DSU]), + CAR.AVALON_2019: ToyotaCarInfo("Toyota Avalon 2019-21"), + CAR.AVALONH_2019: ToyotaCarInfo("Toyota Avalon Hybrid 2019-21"), CAR.AVALON_TSS2: ToyotaCarInfo("Toyota Avalon 2022"), CAR.AVALONH_TSS2: ToyotaCarInfo("Toyota Avalon Hybrid 2022"), CAR.CAMRY: ToyotaCarInfo("Toyota Camry 2018-20", video_link="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), @@ -120,7 +116,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-22"), CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-21"), CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), - CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19", footnotes=[Footnote.DSU]), + CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ ToyotaCarInfo("Toyota Corolla 2020-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), ToyotaCarInfo("Toyota Corolla Cross (Non-US only) 2020-21", min_enable_speed=7.5), @@ -131,53 +127,53 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { ToyotaCarInfo("Toyota Corolla Cross Hybrid (Non-US only) 2020-22", min_enable_speed=7.5), ToyotaCarInfo("Lexus UX Hybrid 2019-22"), ], - CAR.HIGHLANDER: ToyotaCarInfo("Toyota Highlander 2017-19", video_link="https://www.youtube.com/watch?v=0wS0wXSLzoo", footnotes=[Footnote.DSU]), + CAR.HIGHLANDER: ToyotaCarInfo("Toyota Highlander 2017-19", video_link="https://www.youtube.com/watch?v=0wS0wXSLzoo"), CAR.HIGHLANDER_TSS2: ToyotaCarInfo("Toyota Highlander 2020-22"), - CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19", footnotes=[Footnote.DSU]), + CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19"), CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"), CAR.PRIUS: [ - ToyotaCarInfo("Toyota Prius 2016", "Toyota Safety Sense P", "https://www.youtube.com/watch?v=8zopPJI8XQ0", [Footnote.DSU]), - ToyotaCarInfo("Toyota Prius 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]), - ToyotaCarInfo("Toyota Prius Prime 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0", footnotes=[Footnote.DSU]), + ToyotaCarInfo("Toyota Prius 2016", "Toyota Safety Sense P", "https://www.youtube.com/watch?v=8zopPJI8XQ0"), + ToyotaCarInfo("Toyota Prius 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0"), + ToyotaCarInfo("Toyota Prius Prime 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0"), ], - CAR.PRIUS_V: ToyotaCarInfo("Toyota Prius v 2017", "Toyota Safety Sense P", min_enable_speed=MIN_ACC_SPEED, footnotes=[Footnote.DSU]), + CAR.PRIUS_V: ToyotaCarInfo("Toyota Prius v 2017", "Toyota Safety Sense P", min_enable_speed=MIN_ACC_SPEED), CAR.PRIUS_TSS2: [ ToyotaCarInfo("Toyota Prius 2021-22", video_link="https://www.youtube.com/watch?v=J58TvCpUd4U"), ToyotaCarInfo("Toyota Prius Prime 2021-22", video_link="https://www.youtube.com/watch?v=J58TvCpUd4U"), ], CAR.RAV4: [ - ToyotaCarInfo("Toyota RAV4 2016", "Toyota Safety Sense P", footnotes=[Footnote.DSU]), - ToyotaCarInfo("Toyota RAV4 2017-18", footnotes=[Footnote.DSU]) + ToyotaCarInfo("Toyota RAV4 2016", "Toyota Safety Sense P"), + ToyotaCarInfo("Toyota RAV4 2017-18") ], CAR.RAV4H: [ - ToyotaCarInfo("Toyota RAV4 Hybrid 2016", "Toyota Safety Sense P", "https://youtu.be/LhT5VzJVfNI?t=26", [Footnote.DSU]), - ToyotaCarInfo("Toyota RAV4 Hybrid 2017-18", video_link="https://youtu.be/LhT5VzJVfNI?t=26", footnotes=[Footnote.DSU]) + ToyotaCarInfo("Toyota RAV4 Hybrid 2016", "Toyota Safety Sense P", "https://youtu.be/LhT5VzJVfNI?t=26"), + ToyotaCarInfo("Toyota RAV4 Hybrid 2017-18", video_link="https://youtu.be/LhT5VzJVfNI?t=26") ], CAR.RAV4_TSS2: ToyotaCarInfo("Toyota RAV4 2019-21", video_link="https://www.youtube.com/watch?v=wJxjDd42gGA"), CAR.RAV4_TSS2_2022: ToyotaCarInfo("Toyota RAV4 2022"), CAR.RAV4H_TSS2: ToyotaCarInfo("Toyota RAV4 Hybrid 2019-21"), CAR.RAV4H_TSS2_2022: ToyotaCarInfo("Toyota RAV4 Hybrid 2022", video_link="https://youtu.be/U0nH9cnrFB0"), CAR.MIRAI: ToyotaCarInfo("Toyota Mirai 2021"), - CAR.SIENNA: ToyotaCarInfo("Toyota Sienna 2018-20", video_link="https://www.youtube.com/watch?v=q1UPOo4Sh68", footnotes=[Footnote.DSU], min_enable_speed=MIN_ACC_SPEED), + CAR.SIENNA: ToyotaCarInfo("Toyota Sienna 2018-20", video_link="https://www.youtube.com/watch?v=q1UPOo4Sh68", min_enable_speed=MIN_ACC_SPEED), # Lexus - CAR.LEXUS_CTH: ToyotaCarInfo("Lexus CT Hybrid 2017-18", "Lexus Safety System+", footnotes=[Footnote.DSU]), - CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18", "Lexus Safety System+", footnotes=[Footnote.DSU]), + CAR.LEXUS_CTH: ToyotaCarInfo("Lexus CT Hybrid 2017-18", "Lexus Safety System+"), + CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18", "Lexus Safety System+"), CAR.LEXUS_ES_TSS2: ToyotaCarInfo("Lexus ES 2019-22"), CAR.LEXUS_ESH_TSS2: ToyotaCarInfo("Lexus ES Hybrid 2019-22", video_link="https://youtu.be/BZ29osRVJeg?t=12"), CAR.LEXUS_IS: ToyotaCarInfo("Lexus IS 2017-19"), - CAR.LEXUS_NX: ToyotaCarInfo("Lexus NX 2018-19", footnotes=[Footnote.DSU]), - CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19", footnotes=[Footnote.DSU]), + CAR.LEXUS_NX: ToyotaCarInfo("Lexus NX 2018-19"), + CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19"), CAR.LEXUS_NX_TSS2: ToyotaCarInfo("Lexus NX 2020-21"), CAR.LEXUS_NXH_TSS2: ToyotaCarInfo("Lexus NX Hybrid 2020-21"), CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2017-20"), CAR.LEXUS_RX: [ - ToyotaCarInfo("Lexus RX 2016", "Lexus Safety System+", footnotes=[Footnote.DSU]), - ToyotaCarInfo("Lexus RX 2017-19", footnotes=[Footnote.DSU]), + ToyotaCarInfo("Lexus RX 2016", "Lexus Safety System+"), + ToyotaCarInfo("Lexus RX 2017-19"), ], CAR.LEXUS_RXH: [ - ToyotaCarInfo("Lexus RX Hybrid 2016", "Lexus Safety System+", footnotes=[Footnote.DSU]), - ToyotaCarInfo("Lexus RX Hybrid 2017-19", footnotes=[Footnote.DSU]), + ToyotaCarInfo("Lexus RX Hybrid 2016", "Lexus Safety System+"), + ToyotaCarInfo("Lexus RX Hybrid 2017-19"), ], CAR.LEXUS_RX_TSS2: ToyotaCarInfo("Lexus RX 2020-22"), CAR.LEXUS_RXH_TSS2: ToyotaCarInfo("Lexus RX Hybrid 2020-21"), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 7b5d954c43..68bd35c38c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -d37afafc466661262b34631e32e4c383f1277bc5 \ No newline at end of file +01b24beff6855e8c4d2fb0efeeefafb46343e013 From b25e56925c2453464f554bfab57b38f9487a9844 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 4 Nov 2022 01:44:37 +0800 Subject: [PATCH 0165/1179] Cabana: make whole DetailWidget scrollable (#26340) --- tools/cabana/binaryview.cc | 11 ++--- tools/cabana/binaryview.h | 1 - tools/cabana/detailwidget.cc | 89 +++++++++++------------------------- tools/cabana/detailwidget.h | 27 +---------- tools/cabana/historylog.cc | 21 ++++----- tools/cabana/historylog.h | 4 +- tools/cabana/settings.cc | 2 +- tools/cabana/settings.h | 2 +- 8 files changed, 45 insertions(+), 112 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 91353e9726..875bd034ec 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -20,15 +20,12 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { setItemDelegate(delegate); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->hide(); - verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setMouseTracking(true); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + setFrameShape(QFrame::NoFrame); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); -} - -QSize BinaryView::sizeHint() const { - QSize sz = QTableView::sizeHint(); - return {sz.width(), model->rowCount() <= 8 ? ((CELL_HEIGHT + 1) * model->rowCount() + 2) : sz.height()}; + setMouseTracking(true); } void BinaryView::highlight(const Signal *sig) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 060a2eef7f..0f58e9ed20 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -61,7 +61,6 @@ public: void highlight(const Signal *sig); const Signal *hoveredSignal() const { return hovered_sig; } QSet getOverlappingSignals() const; - QSize sizeHint() const override; signals: void signalHovered(const Signal *sig); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 57a3910303..9bbc442154 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include "selfdrive/ui/qt/util.h" #include "tools/cabana/canmessages.h" @@ -13,38 +15,26 @@ // DetailWidget DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { - main_layout = new QHBoxLayout(this); + QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); - right_column = new QVBoxLayout(); - main_layout->addLayout(right_column); - - binary_view_container = new QWidget(this); - binary_view_container->setMinimumWidth(500); - binary_view_container->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); - QVBoxLayout *bin_layout = new QVBoxLayout(binary_view_container); - bin_layout->setContentsMargins(0, 0, 0, 0); - bin_layout->setSpacing(0); - // tabbar + // tabbar tabbar = new QTabBar(this); tabbar->setTabsClosable(true); tabbar->setDrawBase(false); tabbar->setUsesScrollButtons(true); tabbar->setAutoHide(true); tabbar->setContextMenuPolicy(Qt::CustomContextMenu); - bin_layout->addWidget(tabbar); + main_layout->addWidget(tabbar); - TitleFrame *title_frame = new TitleFrame(this); + QFrame *title_frame = new QFrame(this); + QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); title_frame->setFrameShape(QFrame::StyledPanel); title_frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); // message title QHBoxLayout *title_layout = new QHBoxLayout(); - split_btn = new QPushButton("⬅", this); - split_btn->setFixedSize(20, 20); - split_btn->setToolTip(tr("Split to two columns")); - title_layout->addWidget(split_btn); title_layout->addWidget(new QLabel("time:")); time_label = new QLabel(this); time_label->setStyleSheet("font-weight:bold"); @@ -62,6 +52,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart // warning warning_widget = new QWidget(this); QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); + warning_hlayout->setContentsMargins(0, 0, 0, 0); QLabel *warning_icon = new QLabel(this); warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning)); warning_hlayout->addWidget(warning_icon, 0, Qt::AlignTop); @@ -69,30 +60,33 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); warning_widget->hide(); frame_layout->addWidget(warning_widget); - bin_layout->addWidget(title_frame); + main_layout->addWidget(title_frame); + + QWidget *container = new QWidget(this); + QVBoxLayout *container_layout = new QVBoxLayout(container); + container_layout->setSpacing(0); + container_layout->setContentsMargins(0, 0, 0, 0); + + scroll = new QScrollArea(this); + scroll->setWidget(container); + scroll->setWidgetResizable(true); + scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + main_layout->addWidget(scroll); // binary view binary_view = new BinaryView(this); - bin_layout->addWidget(binary_view); - right_column->addWidget(binary_view_container); + container_layout->addWidget(binary_view); // signals signals_container = new QWidget(this); signals_container->setLayout(new QVBoxLayout); signals_container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); - - scroll = new ScrollArea(this); - scroll->setWidget(signals_container); - scroll->setWidgetResizable(true); - scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - right_column->addWidget(scroll); + container_layout->addWidget(signals_container); // history log history_log = new HistoryLog(this); - right_column->addWidget(history_log); + container_layout->addWidget(history_log); - QObject::connect(split_btn, &QPushButton::clicked, this, &DetailWidget::moveBinaryView); - QObject::connect(title_frame, &TitleFrame::doubleClicked, this, &DetailWidget::moveBinaryView); QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg); QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); @@ -146,6 +140,8 @@ void DetailWidget::setMessage(const QString &message_id) { tabbar->setCurrentIndex(index); msg_id = message_id; dbcMsgChanged(); + + scroll->verticalScrollBar()->setValue(0); } void DetailWidget::dbcMsgChanged(int show_form_idx) { @@ -201,27 +197,12 @@ void DetailWidget::updateState() { history_log->updateState(); } -void DetailWidget::moveBinaryView() { - if (binview_in_left_col) { - right_column->insertWidget(0, binary_view_container); - emit binaryViewMoved(true); - } else { - main_layout->insertWidget(0, binary_view_container); - emit binaryViewMoved(false); - } - split_btn->setText(binview_in_left_col ? "⬅" : "➡"); - split_btn->setToolTip(binview_in_left_col ? tr("Split to two columns") : tr("Move back")); - binary_view->updateGeometry(); - binview_in_left_col = !binview_in_left_col; -} - void DetailWidget::showForm() { SignalEdit *sender = qobject_cast(QObject::sender()); for (auto f : signals_container->findChildren()) { f->setFormVisible(f == sender && !f->isFormVisible()); - if (f == sender) { + if (f == sender) QTimer::singleShot(0, [=]() { scroll->ensureWidgetVisible(f); }); - } } } @@ -322,19 +303,3 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } - -// ScrollArea - -bool ScrollArea::eventFilter(QObject *obj, QEvent *ev) { - if (obj == widget() && ev->type() == QEvent::Resize) { - int height = widget()->height() + 4; - setMinimumHeight(height > 480 ? 480 : height); - setMaximumHeight(height); - } - return QScrollArea::eventFilter(obj, ev); -} - -void ScrollArea::setWidget(QWidget *w) { - QScrollArea::setWidget(w); - w->installEventFilter(this); -} diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 656aacb106..d8784f3f14 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -2,22 +2,12 @@ #include #include -#include #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" #include "tools/cabana/historylog.h" #include "tools/cabana/signaledit.h" -class TitleFrame : public QFrame { - Q_OBJECT -public: - TitleFrame(QWidget *parent) : QFrame(parent) {} - void mouseDoubleClickEvent(QMouseEvent *e) { emit doubleClicked(); } -signals: - void doubleClicked(); -}; - class EditMessageDialog : public QDialog { Q_OBJECT @@ -28,15 +18,6 @@ public: QSpinBox *size_spin; }; -class ScrollArea : public QScrollArea { - Q_OBJECT - -public: - ScrollArea(QWidget *parent) : QScrollArea(parent) {} - bool eventFilter(QObject *obj, QEvent *ev) override; - void setWidget(QWidget *w); -}; - class DetailWidget : public QWidget { Q_OBJECT @@ -58,7 +39,6 @@ private: void editMsg(); void showForm(); void updateState(); - void moveBinaryView(); QString msg_id; QLabel *name_label, *time_label, *warning_label; @@ -66,13 +46,8 @@ private: QPushButton *edit_btn; QWidget *signals_container; QTabBar *tabbar; - QHBoxLayout *main_layout; - QVBoxLayout *right_column; - bool binview_in_left_col = false; - QWidget *binary_view_container; - QPushButton *split_btn; HistoryLog *history_log; BinaryView *binary_view; - ScrollArea *scroll; + QScrollArea *scroll; ChartsWidget *charts; }; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 8136d0577c..5737421f28 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -64,16 +64,15 @@ void HistoryLogModel::updateState() { } } -HistoryLog::HistoryLog(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); +HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { model = new HistoryLogModel(this); - table = new QTableView(this); - table->setModel(model); - table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - table->setColumnWidth(0, 60); - table->verticalHeader()->setVisible(false); - table->setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); - main_layout->addWidget(table); + setModel(model); + horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + verticalHeader()->setVisible(false); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + setFrameShape(QFrame::NoFrame); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index d39bcf9f1d..0bfc409fe1 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -25,15 +25,13 @@ private: std::deque messages; }; -class HistoryLog : public QWidget { +class HistoryLog : public QTableView { Q_OBJECT public: HistoryLog(QWidget *parent); void setMessage(const QString &message_id) { model->setMessage(message_id); } void updateState() { model->updateState(); } - private: - QTableView *table; HistoryLogModel *model; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 17299ebca4..bba59c0d74 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -25,7 +25,7 @@ void Settings::save() { void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); - can_msg_log_size = s.value("log_size", 100).toInt(); + can_msg_log_size = s.value("log_size", 50).toInt(); cached_segment_limit = s.value("cached_segment", 3).toInt(); chart_height = s.value("chart_height", 200).toInt(); chart_theme = s.value("chart_theme", 0).toInt(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 88eeebc722..cb858de873 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -13,7 +13,7 @@ public: void load(); int fps = 10; - int can_msg_log_size = 100; + int can_msg_log_size = 50; int cached_segment_limit = 3; int chart_height = 200; int chart_theme = 0; From e4ec1d7c4cc65d2f91530776584807eb4b13e59e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 4 Nov 2022 01:44:49 +0800 Subject: [PATCH 0166/1179] Cabana: update line series concurrently (#26339) update series concurrently --- tools/cabana/chartswidget.cc | 9 ++++++--- tools/cabana/chartswidget.h | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3782f381e8..5bf66ebb2d 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,11 +1,13 @@ #include "tools/cabana/chartswidget.h" +#include #include #include #include #include #include #include +#include // ChartsWidget @@ -116,8 +118,9 @@ void ChartsWidget::updateState() { display_range.first = std::max(display_range.first, event_range.first); display_range.second = std::min(display_range.first + settings.max_chart_x_range, event_range.second); if (prev_range != display_range) { + QFutureSynchronizer future_synchronizer; for (auto c : charts) - c->chart_view->updateSeries(display_range); + future_synchronizer.addFuture(QtConcurrent::run(c->chart_view, &ChartView::updateSeries, display_range)); } } @@ -328,7 +331,7 @@ void ChartView::updateLineMarker(double current_sec) { } } -void ChartView::updateSeries(const std::pair &range) { +void ChartView::updateSeries(const std::pair range) { auto events = can->events(); if (!events) return; @@ -337,7 +340,7 @@ void ChartView::updateSeries(const std::pair &range) { uint32_t address = l[1].toUInt(nullptr, 16); vals.clear(); - vals.reserve((range.second - range.first) * 100); // [n]minutes * 100hz + vals.reserve((range.second - range.first) * 1000); // [n]seconds * 1000hz 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()); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 602d50ca0a..ff56008e7d 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -21,7 +21,7 @@ class ChartView : public QChartView { public: ChartView(const QString &id, const Signal *sig, QWidget *parent = nullptr); - void updateSeries(const std::pair &range); + void updateSeries(const std::pair range); void setRange(double min, double max, bool force_update = false); void updateLineMarker(double current_sec); void updateFromSettings(); @@ -42,7 +42,7 @@ private: QGraphicsEllipseItem *track_ellipse; QGraphicsTextItem *value_text; QGraphicsLineItem *line_marker; - QList vals; + QVector vals; QString id; const Signal *signal; }; From ad62a448fa7b6608b95adfe29461bac0bf9b9111 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Thu, 3 Nov 2022 13:21:11 -0700 Subject: [PATCH 0167/1179] [torqued] Set HYUNDAI ELANTRA 2021 Offline vlaues (#26344) change elantra values --- selfdrive/car/torque_data/params.yaml | 1 + selfdrive/car/torque_data/substitute.yaml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 5c828fa669..c2ebadfc7a 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -25,6 +25,7 @@ HONDA ODYSSEY 2018: [1.8774809275211801, 0.8394431662987996, 0.2096978613792822] HONDA PASSPORT 2021: [1.5305538930036766, 0.7956063674638759, 0.19599407381531284] HONDA PILOT 2017: [1.7262026201812795, 0.9470005614967523, 0.21351430733218763] HONDA RIDGELINE 2017: [1.4146525028237624, 0.7356572861629564, 0.23307177552211328] +HYUNDAI ELANTRA 2021: [3.169, 2.1259108157250735, 0.0819] HYUNDAI GENESIS 2015-2016: [1.8466226943929824, 1.5552063647830634, 0.0984484465421171] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index acd7526003..c043c9d455 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -35,7 +35,6 @@ HYUNDAI IONIQ HYBRID 2020-2022: HYUNDAI IONIQ PLUG-IN HYBRID 2019 HYUNDAI IONIQ ELECTRIC 2020: HYUNDAI IONIQ PLUG-IN HYBRID 2019 HYUNDAI ELANTRA 2017: HYUNDAI SONATA 2019 HYUNDAI ELANTRA HYBRID 2021: HYUNDAI SONATA 2020 -HYUNDAI ELANTRA 2021: HYUNDAI SONATA 2020 HYUNDAI TUCSON 2019: HYUNDAI SANTA FE 2019 HYUNDAI SANTA FE 2022: HYUNDAI SANTA FE HYBRID 2022 GENESIS G90 2017: GENESIS G70 2018 From 70363e2491ea4150f85b44ff221d3318208581a9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 4 Nov 2022 04:23:53 +0800 Subject: [PATCH 0168/1179] Cabana: word wrap header (#26341) * auto wrap header * custom headerview --- tools/cabana/historylog.cc | 17 +++++++++++++++-- tools/cabana/historylog.h | 7 +++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 5737421f28..7bb2f37699 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -1,9 +1,10 @@ #include "tools/cabana/historylog.h" #include -#include #include +// HistoryLogModel + QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); if (role == Qt::DisplayRole) { @@ -37,7 +38,7 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return has_signal ? dbc_msg->sigs[section - 1].name.c_str() : "Data"; + return has_signal ? QString::fromStdString(dbc_msg->sigs[section - 1].name).replace('_', ' ') : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && has_signal) { return QBrush(QColor(getColor(section - 1))); } @@ -64,10 +65,22 @@ void HistoryLogModel::updateState() { } } +// HeaderView + +QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { + const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); + const QRect rect = fontMetrics().boundingRect(QRect(0, 0, sectionSize(logicalIndex), 1000), defaultAlignment(), text); + return rect.size() + QSize{10, 5}; +} + +// HistoryLog + HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { model = new HistoryLogModel(this); setModel(model); + setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); verticalHeader()->setVisible(false); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 0bfc409fe1..e1c1319166 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -1,10 +1,17 @@ #pragma once +#include #include #include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" +class HeaderView : public QHeaderView { +public: + HeaderView(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {} + QSize sectionSizeFromContents(int logicalIndex) const; +}; + class HistoryLogModel : public QAbstractTableModel { Q_OBJECT From d172cbbcc8c35b834812871d6768072b9bb1f594 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 3 Nov 2022 16:33:01 -0400 Subject: [PATCH 0169/1179] VW MQB: Add FW for 2021 Audi Q3 (#26343) * VW MQB: Add FW for 2021 Audi Q3 * update docs --- docs/CARS.md | 2 +- selfdrive/car/volkswagen/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index ad288a1cc6..e9d7b9c82f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -14,7 +14,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Audi|Q3 2020-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 695868452d..ee5687eb1d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -227,7 +227,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { VWCarInfo("Audi S3 2015-17"), ], CAR.AUDI_Q2_MK1: VWCarInfo("Audi Q2 2018"), - CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2020-21"), + CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2019-23"), CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018"), CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20"), CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.KAMIQ]), @@ -872,20 +872,24 @@ FW_VERSIONS = { CAR.AUDI_Q3_MK2: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8705E906018N \xf1\x899970', + b'\xf1\x8705L906022M \xf1\x890901', b'\xf1\x8783A906259 \xf1\x890001', b'\xf1\x8783A906259 \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158CN\xf1\x893608', + b'\xf1\x870GC300045D \xf1\x892802', b'\xf1\x870GC300046F \xf1\x892701', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655BF\xf1\x890403\xf1\x82\x1321211111211200311121232152219321422111', + b'\xf1\x875Q0959655CC\xf1\x890421\xf1\x82\x131111111111120031111224118A119321532111', b'\xf1\x875Q0959655CC\xf1\x890421\xf1\x82\x131111111111120031111237116A119321532111', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567G6000300', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567G6000800', + b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571G60533A1', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572R \xf1\x890372', From aab4b7941665528dd8dbf59eb125cfd377f07250 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Thu, 3 Nov 2022 14:27:45 -0700 Subject: [PATCH 0170/1179] CI: set OX frame sync tolerance (#26347) * ox tolerate * int * update comments --- system/camerad/test/test_camerad.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index 378d4b7058..3c6d466a69 100755 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -4,12 +4,14 @@ import unittest from collections import defaultdict import cereal.messaging as messaging +from cereal import log from cereal.services import service_list from selfdrive.manager.process_config import managed_processes from system.hardware import TICI TEST_TIMESPAN = 30 -LAG_FRAME_TOLERANCE = 0.5 # ms +LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0321: 0.5, # ARs use synced pulses for frame starts + log.FrameData.ImageSensor.ox03c10: 1.0} # OXs react to out-of-sync at next frame CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState') @@ -62,6 +64,7 @@ class TestCamerad(unittest.TestCase): assert len(skips) == 0, f"Found frame skips, missing cameras for the following frames: {skips}" def test_frame_sync(self): + sensor_type = [getattr(msgs[0], msgs[0].which()).sensor for frame_id, msgs in self.log_by_frame_id.items()][0].raw frame_times = {frame_id: [getattr(m, m.which()).timestampSof for m in msgs] for frame_id, msgs in self.log_by_frame_id.items()} diffs = {frame_id: (max(ts) - min(ts))/1e6 for frame_id, ts in frame_times.items()} @@ -69,7 +72,7 @@ class TestCamerad(unittest.TestCase): def get_desc(fid, diff): cam_times = [(m.which(), getattr(m, m.which()).timestampSof/1e6) for m in self.log_by_frame_id[fid]] return f"{diff=} {cam_times=}" - laggy_frames = {k: get_desc(k, v) for k, v in diffs.items() if v > LAG_FRAME_TOLERANCE} + laggy_frames = {k: get_desc(k, v) for k, v in diffs.items() if v > LAG_FRAME_TOLERANCE[sensor_type]} assert len(laggy_frames) == 0, f"Frames not synced properly: {laggy_frames=}" if __name__ == "__main__": From c9e65be9b16064c57814218b7c0ebb67a168333f Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 3 Nov 2022 17:37:21 -0400 Subject: [PATCH 0171/1179] VW MQB: Harness updates and docs cleanup (#26313) * VW MQB: Harness updates * don't need the variant footnote Co-authored-by: Adeeb Shihadeh --- docs/CARS.md | 95 +++++++++++++++--------------- selfdrive/car/volkswagen/values.py | 76 +++++++++++------------- 2 files changed, 82 insertions(+), 89 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index e9d7b9c82f..fa1b54c1c3 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -11,12 +11,12 @@ A supported vehicle is one that just works when you install a comma three. All s |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| @@ -129,8 +129,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| @@ -141,13 +141,13 @@ A supported vehicle is one that just works when you install a comma three. All s |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Škoda|Kamiq 2021[6](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Karoq 2019-21[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Škoda|Kamiq 2021[6](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| +|Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| @@ -188,37 +188,37 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Volkswagen|Arteon 2018-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon eHybrid 2020-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon R 2020-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas 2018-23[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas Cross Sport 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|California 2021[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Caravelle 2020[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|CC 2018-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf 2015-20[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf R 2015-19[9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| -|Volkswagen|Jetta 2018-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta GLI 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat 2015-22[7,8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat Alltrack 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat GTE 2015-22[8,9](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo 2020-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo GTI 2020-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|T-Cross 2021[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|T-Roc 2021[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Taos 2022[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont 2018-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont Cross Sport 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont X 2021-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Tiguan 2019-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|VW| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat 2015-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| +|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).
@@ -228,8 +228,7 @@ A supported vehicle is one that just works when you install a comma three. All s 5openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
6Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
7Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
-8Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). In the interim, if your car has a J533 connector CAN gateway inside the dashboard, choose "VW J533 Development" from the vehicle drop-down for a suitable harness. (Some newer models are also observed to not have a J533 connector.)
-9Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.)
+8Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
## Community Maintained Cars Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index ee5687eb1d..74b111a99e 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -151,75 +151,69 @@ class Footnote(Enum): PASSAT = CarFootnote( "Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.", Column.MODEL) - VW_HARNESS = CarFootnote( - "Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma " + - "store. Before ordering, remove the Lane Assist camera cover and check to see if the connector is black " + - "(older design) or light brown (newer design). In the interim, if your car has a J533 connector CAN gateway " + - "inside the dashboard, choose \"VW J533 Development\" from the vehicle drop-down for a suitable harness. " + - "(Some newer models are also observed to not have a J533 connector.)", - Column.MODEL) - VW_VARIANT = CarFootnote( - "Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.)", - Column.MODEL) + VW_MQB_A0 = CarFootnote( + "Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot " + + "in software, but doesn't yet have a harness available from the comma store.", + Column.HARNESS) @dataclass class VWCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC) & Lane Assist" - harness: Enum = Harness.vw + harness: Enum = Harness.j533 CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.ARTEON_MK1: [ - VWCarInfo("Volkswagen Arteon 2018-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"), - VWCarInfo("Volkswagen Arteon R 2020-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"), - VWCarInfo("Volkswagen Arteon eHybrid 2020-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"), - VWCarInfo("Volkswagen CC 2018-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533, video_link="https://youtu.be/FAomFKPFlDA"), + VWCarInfo("Volkswagen Arteon 2018-22", video_link="https://youtu.be/FAomFKPFlDA"), + VWCarInfo("Volkswagen Arteon R 2020-22", video_link="https://youtu.be/FAomFKPFlDA"), + VWCarInfo("Volkswagen Arteon eHybrid 2020-22", video_link="https://youtu.be/FAomFKPFlDA"), + VWCarInfo("Volkswagen CC 2018-22", video_link="https://youtu.be/FAomFKPFlDA"), ], CAR.ATLAS_MK1: [ - VWCarInfo("Volkswagen Atlas 2018-23", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Atlas Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Teramont 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Teramont Cross Sport 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Teramont X 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + VWCarInfo("Volkswagen Atlas 2018-23"), + VWCarInfo("Volkswagen Atlas Cross Sport 2021-22"), + VWCarInfo("Volkswagen Teramont 2018-22"), + VWCarInfo("Volkswagen Teramont Cross Sport 2021-22"), + VWCarInfo("Volkswagen Teramont X 2021-22"), ], CAR.GOLF_MK7: [ VWCarInfo("Volkswagen e-Golf 2014-20"), - VWCarInfo("Volkswagen Golf 2015-20", footnotes=[Footnote.VW_VARIANT]), + VWCarInfo("Volkswagen Golf 2015-20"), VWCarInfo("Volkswagen Golf Alltrack 2015-19"), VWCarInfo("Volkswagen Golf GTD 2015-20"), VWCarInfo("Volkswagen Golf GTE 2015-20"), VWCarInfo("Volkswagen Golf GTI 2015-21"), - VWCarInfo("Volkswagen Golf R 2015-19", footnotes=[Footnote.VW_VARIANT]), + VWCarInfo("Volkswagen Golf R 2015-19"), VWCarInfo("Volkswagen Golf SportsVan 2015-20"), ], CAR.JETTA_MK7: [ - VWCarInfo("Volkswagen Jetta 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Jetta GLI 2021-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + VWCarInfo("Volkswagen Jetta 2018-22"), + VWCarInfo("Volkswagen Jetta GLI 2021-22"), ], CAR.PASSAT_MK8: [ - VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.VW_HARNESS, Footnote.PASSAT, Footnote.VW_VARIANT], harness=Harness.j533), - VWCarInfo("Volkswagen Passat Alltrack 2015-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Passat GTE 2015-22", footnotes=[Footnote.VW_HARNESS, Footnote.VW_VARIANT], harness=Harness.j533), + VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.PASSAT]), + VWCarInfo("Volkswagen Passat Alltrack 2015-22"), + VWCarInfo("Volkswagen Passat GTE 2015-22"), ], - CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22", harness=Harness.j533), + CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22"), CAR.POLO_MK6: [ - VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_MQB_A0]), + VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_MQB_A0]), ], CAR.SHARAN_MK2: [ - VWCarInfo("Volkswagen Sharan 2018-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("SEAT Alhambra 2018-20", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + VWCarInfo("Volkswagen Sharan 2018-22"), + VWCarInfo("SEAT Alhambra 2018-20"), ], - CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022"), + CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_MQB_A0]), + CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22"), CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"), CAR.TRANSPORTER_T61: [ - VWCarInfo("Volkswagen Caravelle 2020", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), - VWCarInfo("Volkswagen California 2021", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + VWCarInfo("Volkswagen Caravelle 2020"), + VWCarInfo("Volkswagen California 2021"), ], - CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_HARNESS], harness=Harness.j533), + CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_MQB_A0]), CAR.AUDI_A3_MK3: [ VWCarInfo("Audi A3 2014-19"), VWCarInfo("Audi A3 Sportback e-tron 2017-18"), @@ -230,10 +224,10 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2019-23"), CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018"), CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20"), - CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.KAMIQ]), - CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21", footnotes=[Footnote.VW_HARNESS]), + CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_MQB_A0, Footnote.KAMIQ]), + CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21"), CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"), - CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020"), + CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_MQB_A0]), CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-18"), CAR.SKODA_OCTAVIA_MK3: [ VWCarInfo("Škoda Octavia 2015, 2018-19"), From ee0dd36a3c775dbd82493c84f4e7272c1eb3fcbd Mon Sep 17 00:00:00 2001 From: Mehmet Tolga Avcioglu Date: Fri, 4 Nov 2022 01:17:36 +0300 Subject: [PATCH 0172/1179] Kona EV 2022: add missing FW versions (#26278) * add fingerprint for kona electric 2022 * Update selfdrive/car/hyundai/values.py Co-authored-by: Shane Smiskol --- 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 c760c724a9..4415679175 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1052,6 +1052,7 @@ FW_VERSIONS = { b'\xf1\x8758520-K4010\xf1\x00OS IEB \x02 101 \x11\x13 58520-K4010', b'\xf1\x8758520-K4010\xf1\x00OS IEB \x04 101 \x11\x13 58520-K4010', b'\xf1\x8758520-K4010\xf1\x00OS IEB \x03 101 \x11\x13 58520-K4010', + b'\xf1\x00OS IEB \r 102"\x05\x16 58520-K4010', # TODO: these return from the MULTI request, above return from LONG b'\x01\x04\x7f\xff\xff\xf8\xff\xff\x00\x00\x01\xd3\x00\x00\x00\x00\xff\xb7\xff\xee\xff\xe0\x00\xc0\xc0\xfc\xd5\xfc\x00\x00U\x10\xffP\xf5\xff\xfd\x00\x00\x00\x00\xfc\x00\x01', b'\x01\x04\x7f\xff\xff\xf8\xff\xff\x00\x00\x01\xdb\x00\x00\x00\x00\xff\xb1\xff\xd9\xff\xd2\x00\xc0\xc0\xfc\xd5\xfc\x00\x00U\x10\xff\xd6\xf5\x00\x06\x00\x00\x00\x14\xfd\x00\x04', @@ -1061,10 +1062,12 @@ FW_VERSIONS = { b'\xf1\x00OSP LKA AT CND LHD 1.00 1.02 99211-J9110 802', b'\xf1\x00OSP LKA AT EUR RHD 1.00 1.02 99211-J9110 802', b'\xf1\x00OSP LKA AT AUS RHD 1.00 1.04 99211-J9200 904', + b'\xf1\x00OSP LKA AT EUR LHD 1.00 1.04 99211-J9200 904', ], (Ecu.eps, 0x7D4, None): [ b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4260\x00 4OEPC102', b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102', + b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102', ], (Ecu.fwdRadar, 0x7D0, None): [ b'\xf1\x00YB__ FCA ----- 1.00 1.01 99110-K4500 \x00\x00\x00', From 9a8c7f2453bcb917eb428704c1733f28e5d42d11 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 3 Nov 2022 15:51:14 -0700 Subject: [PATCH 0173/1179] boardd: remove canfd whitelist --- selfdrive/boardd/panda.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 0b8630b0c0..329ce91c44 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -399,8 +399,7 @@ void Panda::pack_can_buffer(const capnp::List::Reader &can_data } auto can_data = cmsg.getDat(); uint8_t data_len_code = len_to_dlc(can_data.size()); - assert(can_data.size() <= ((hw_type == cereal::PandaState::PandaType::RED_PANDA || - hw_type == cereal::PandaState::PandaType::RED_PANDA_V2) ? 64 : 8)); + assert(can_data.size() <= 64); assert(can_data.size() == dlc_to_len[data_len_code]); can_header header; From 15828c4feaa69af43867cae89c4de2ca2e8a734b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 3 Nov 2022 19:02:39 -0700 Subject: [PATCH 0174/1179] updated: reset working tree in each submodule (#26316) * updated: reset working tree in each submodule * run after fetch too --- selfdrive/updated.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/updated.py b/selfdrive/updated.py index c261a92a84..9da2a05a11 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -175,7 +175,7 @@ def finalize_update() -> None: shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True) run(["git", "reset", "--hard"], FINALIZED) - run(["git", "submodule", "foreach", "--recursive", "git", "reset"], FINALIZED) + run(["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"], FINALIZED) cloudlog.info("Starting git cleanup in finalized update") t = time.monotonic() @@ -374,8 +374,8 @@ class Updater: ["git", "reset", "--hard"], ["git", "clean", "-xdff"], ["git", "submodule", "sync"], - ["git", "submodule", "init"], - ["git", "submodule", "update"], + ["git", "submodule", "update", "--init", "--recursive"], + ["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"], ] r = [run(cmd, OVERLAY_MERGED) for cmd in cmds] cloudlog.info("git reset success: %s", '\n'.join(r)) From 241d88c018d2acae4dbc71b5a033644959e2b24a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 4 Nov 2022 11:09:14 +0800 Subject: [PATCH 0175/1179] Cabana: update viewport after mouse released (#26355) update viewport after mouse released --- tools/cabana/chartswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5bf66ebb2d..7540abbcb2 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -410,6 +410,7 @@ 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(); From 384f9402374e341843f503f871421a7b43437444 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 3 Nov 2022 23:07:29 -0700 Subject: [PATCH 0176/1179] ui: fix disappearing path with wide cam (#26354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * split lat long icons * no overriding border status, consider steering pressed for lat icon, spacing for readability * add engageable back add engageable back add engageable back * all the debugging code 🙃 * revert that stuff * only the fix * comment comment * fix dat * explicit Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/ui.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 821064f81f..e1ef5192b6 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -63,6 +63,8 @@ void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Rea right_points.reserve(max_idx + 1); for (int i = 0; i <= max_idx; i++) { + // highly negative x positions cause flickering, clip to zy plane of camera + if (line_x[i] < 0) continue; QPointF left, right; bool l = calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off, &left); bool r = calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off, &right); From aebb08e10542758c458c3abb219f8b57485e0b61 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 4 Nov 2022 07:43:30 +0100 Subject: [PATCH 0177/1179] locationd: add gps sanity check for quectel gps (#26352) * update check * . * . * remove gps kf time check for gps ok * upsi * dont use gps_mode * update refs * Update selfdrive/locationd/locationd.cc Co-authored-by: Shane Smiskol Co-authored-by: Kurt Nistelberger Co-authored-by: Cameron Clough Co-authored-by: Shane Smiskol --- selfdrive/locationd/locationd.cc | 20 ++++++++++++++------ selfdrive/locationd/locationd.h | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index e156af5d64..8d9e247655 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -270,15 +270,22 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R bool gps_lat_lng_alt_insane = ((std::abs(log.getLatitude()) > 90) || (std::abs(log.getLongitude()) > 180) || (std::abs(log.getAltitude()) > ALTITUDE_SANITY_CHECK)); bool gps_vel_insane = (floatlist2vector(log.getVNED()).norm() > TRANS_SANITY_CHECK); - if (gps_invalid_flag || gps_unreasonable || gps_accuracy_insane || gps_lat_lng_alt_insane || gps_vel_insane) { + // quectel gps verticalAccuracy is clipped to 500 + bool gps_accuracy_insane_quectel = false; + if (!ublox_available) { + gps_accuracy_insane_quectel = log.getVerticalAccuracy() == 500; + } + + if (gps_invalid_flag || gps_unreasonable || gps_accuracy_insane || gps_lat_lng_alt_insane || gps_vel_insane || gps_accuracy_insane_quectel) { + this->gps_valid = false; this->determine_gps_mode(current_time); return; } - + double sensor_time = current_time - sensor_time_offset; // Process message - this->last_gps_fix = sensor_time; + this->gps_valid = true; this->gps_mode = true; Geodetic geodetic = { log.getLatitude(), log.getLongitude(), log.getAltitude() }; this->converter = std::make_unique(geodetic); @@ -476,9 +483,8 @@ kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_build return msg_builder.toBytes(); } - bool Localizer::isGpsOK() { - return this->kf->get_filter_time() - this->last_gps_fix < 1.0; + return this->gps_valid; } void Localizer::determine_gps_mode(double current_time) { @@ -498,8 +504,10 @@ void Localizer::determine_gps_mode(double current_time) { } int Localizer::locationd_thread() { + ublox_available = Params().getBool("UbloxAvailable", true); + const char* gps_location_socket; - if (Params().getBool("UbloxAvailable", true)) { + if (ublox_available) { gps_location_socket = "gpsLocationExternal"; } else { gps_location_socket = "gpsLocation"; diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index 280296b06c..d6bb5347c5 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -68,8 +68,9 @@ private: std::unique_ptr converter; int64_t unix_timestamp_millis = 0; - double last_gps_fix = 0; double reset_tracker = 0.0; bool device_fell = false; bool gps_mode = false; + bool gps_valid = false; + bool ublox_available = true; }; diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 68bd35c38c..8eae3ce8b4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -01b24beff6855e8c4d2fb0efeeefafb46343e013 +6abe3ec1ee19710bdd89ce2882b9503d4aff8e7f From 81f6ebebaaeda467fd7a4552711cc1109b33ddd5 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Fri, 4 Nov 2022 01:32:29 -0700 Subject: [PATCH 0178/1179] [paramsd] Prevent low speed drifting (#26360) * lower active speed for paramsd observations * update refs --- selfdrive/locationd/paramsd.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index 86672b0460..9bd4ed0837 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -92,7 +92,7 @@ class ParamsLearner: self.speed = msg.vEgo in_linear_region = abs(self.steering_angle) < 45 or not self.steering_pressed - self.active = self.speed > 5 and in_linear_region + self.active = self.speed > 1 and in_linear_region if self.active: self.kf.predict_and_observe(t, ObservationKind.STEER_ANGLE, np.array([[math.radians(msg.steeringAngleDeg)]])) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 8eae3ce8b4..40f3c522de 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -6abe3ec1ee19710bdd89ce2882b9503d4aff8e7f +2ba23c5d1c4e0c34295d38f31ed35e3482608b16 \ No newline at end of file From 033ffa4a88bd4632e0e1ba5c4bcd4c4ba43e47bc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 4 Nov 2022 02:30:14 -0700 Subject: [PATCH 0179/1179] Update comment in ui.cc --- selfdrive/ui/ui.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index e1ef5192b6..945218ec11 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -63,7 +63,7 @@ void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Rea right_points.reserve(max_idx + 1); for (int i = 0; i <= max_idx; i++) { - // highly negative x positions cause flickering, clip to zy plane of camera + // highly negative x positions are drawn above the frame and cause flickering, clip to zy plane of camera if (line_x[i] < 0) continue; QPointF left, right; bool l = calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off, &left); From 0e3edf7877e2a219ae67f7e71d36d8458d50f7e4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 5 Nov 2022 02:16:15 +0800 Subject: [PATCH 0180/1179] Cabana: fix signal list glitch (#26357) * fix signal list glitch * fix glitch when open new msg * reduce spacing * fix binaryview glitch * spacing 3 * create form on demand * dont close form after save * remove timer * remove sizepolicy * cleanup --- tools/cabana/binaryview.cc | 11 +++---- tools/cabana/binaryview.h | 5 ++- tools/cabana/detailwidget.cc | 61 +++++++++++++++++------------------- tools/cabana/detailwidget.h | 1 + tools/cabana/signaledit.cc | 55 +++++++++++++++++++------------- tools/cabana/signaledit.h | 12 ++++--- 6 files changed, 76 insertions(+), 69 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 875bd034ec..ba50b101fc 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -11,7 +11,7 @@ // BinaryView -const int CELL_HEIGHT = 30; +const int CELL_HEIGHT = 26; BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { model = new BinaryViewModel(this); @@ -105,15 +105,9 @@ void BinaryView::leaveEvent(QEvent *event) { } void BinaryView::setMessage(const QString &message_id) { - msg_id = message_id; model->setMessage(message_id); clearSelection(); updateState(); - updateGeometry(); -} - -void BinaryView::updateState() { - model->updateState(); } const Signal *BinaryView::getResizingSignal() const { @@ -176,6 +170,9 @@ void BinaryViewModel::setMessage(const QString &message_id) { items[idx].sigs.push_back(&dbc_msg->sigs[i]); } } + } else { + row_count = can->lastMessage(msg_id).dat.size(); + items.resize(row_count * column_count); } endResetModel(); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 0f58e9ed20..a907a673bf 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -57,10 +57,10 @@ class BinaryView : public QTableView { public: BinaryView(QWidget *parent = nullptr); void setMessage(const QString &message_id); - void updateState(); void highlight(const Signal *sig); - const Signal *hoveredSignal() const { return hovered_sig; } QSet getOverlappingSignals() const; + inline const Signal *hoveredSignal() const { return hovered_sig; } + inline void updateState() { model->updateState(); } signals: void signalHovered(const Signal *sig); @@ -75,7 +75,6 @@ private: void leaveEvent(QEvent *event) override; const Signal *getResizingSignal() const; - QString msg_id; QModelIndex anchor_index; BinaryViewModel *model; BinaryItemDelegate *delegate; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 9bbc442154..f3e3438229 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -31,7 +31,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QFrame *title_frame = new QFrame(this); QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); title_frame->setFrameShape(QFrame::StyledPanel); - title_frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); // message title QHBoxLayout *title_layout = new QHBoxLayout(); @@ -80,7 +79,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart // signals signals_container = new QWidget(this); signals_container->setLayout(new QVBoxLayout); - signals_container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); container_layout->addWidget(signals_container); // history log @@ -147,32 +145,35 @@ void DetailWidget::setMessage(const QString &message_id) { void DetailWidget::dbcMsgChanged(int show_form_idx) { if (msg_id.isEmpty()) return; - warning_widget->hide(); + setUpdatesEnabled(false); QStringList warnings; + for (auto f : signal_list) f->hide(); - clearLayout(signals_container->layout()); - QString msg_name = tr("untitled"); - if (auto msg = dbc()->msg(msg_id)) { + const Msg *msg = dbc()->msg(msg_id); + if (msg) { for (int i = 0; i < msg->sigs.size(); ++i) { - auto form = new SignalEdit(i, msg_id, &(msg->sigs[i])); - form->setChartOpened(charts->isChartOpened(msg_id, &(msg->sigs[i]))); - signals_container->layout()->addWidget(form); - QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); - QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); - QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); - QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); - QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); - QObject::connect(form, &SignalEdit::showChart, [this, sig = &msg->sigs[i]](bool show) { charts->showChart(msg_id, sig, show); }); - if (i == show_form_idx) { - QTimer::singleShot(0, [=]() { emit form->showFormClicked(); }); + SignalEdit *form = i < signal_list.size() ? signal_list[i] : nullptr; + if (!form) { + form = new SignalEdit(i); + QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); + QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); + QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); + QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); + QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); + QObject::connect(form, &SignalEdit::showChart, charts, &ChartsWidget::showChart); + signals_container->layout()->addWidget(form); + signal_list.push_back(form); } + form->setSignal(msg_id, &(msg->sigs[i]), i == show_form_idx); + form->setChartOpened(charts->isChartOpened(msg_id, &(msg->sigs[i]))); + form->show(); } - msg_name = msg->name.c_str(); if (msg->size != can->lastMessage(msg_id).dat.size()) warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } + edit_btn->setVisible(true); - name_label->setText(msg_name); + name_label->setText(msg ? msg->name.c_str() : "untitled"); binary_view->setMessage(msg_id); history_log->setMessage(msg_id); @@ -183,10 +184,9 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); } - if (!warnings.isEmpty()) { - warning_label->setText(warnings.join('\n')); - warning_widget->show(); - } + warning_label->setText(warnings.join('\n')); + warning_widget->setVisible(!warnings.isEmpty()); + setUpdatesEnabled(true); } void DetailWidget::updateState() { @@ -199,18 +199,15 @@ void DetailWidget::updateState() { void DetailWidget::showForm() { SignalEdit *sender = qobject_cast(QObject::sender()); - for (auto f : signals_container->findChildren()) { + setUpdatesEnabled(false); + for (auto f : signal_list) f->setFormVisible(f == sender && !f->isFormVisible()); - if (f == sender) - QTimer::singleShot(0, [=]() { scroll->ensureWidgetVisible(f); }); - } + QTimer::singleShot(1, [this]() { setUpdatesEnabled(true); }); } void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool opened) { - if (id == msg_id) { - for (auto f : signals_container->findChildren()) - if (f->sig == sig) f->setChartOpened(opened); - } + for (auto f : signal_list) + if (f->msg_id == id && f->sig == sig) f->setChartOpened(opened); } void DetailWidget::editMsg() { @@ -265,7 +262,7 @@ void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) { dbc()->updateSignal(msg_id, sig->name.c_str(), new_sig); // update binary view and history log - dbcMsgChanged(); + updateState(); } void DetailWidget::removeSignal(const Signal *sig) { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index d8784f3f14..ce3468e472 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -50,4 +50,5 @@ private: BinaryView *binary_view; QScrollArea *scroll; ChartsWidget *charts; + QList signal_list; }; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index ef0a85eba3..ee91887d0a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -13,40 +13,37 @@ // SignalForm -SignalForm::SignalForm(const Signal &sig, QWidget *parent) : QWidget(parent) { +SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { QFormLayout *form_layout = new QFormLayout(this); + form_layout->setContentsMargins(0, 0, 0, 0); - name = new QLineEdit(sig.name.c_str()); + name = new QLineEdit(); form_layout->addRow(tr("Name"), name); size = new QSpinBox(); size->setMinimum(1); - size->setValue(sig.size); form_layout->addRow(tr("Size"), size); endianness = new QComboBox(); endianness->addItems({"Little", "Big"}); - 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))); + ; + form_layout->addRow(tr("lsb"), lsb = new QLabel()); + form_layout->addRow(tr("msb"), msb = new QLabel()); sign = new QComboBox(); sign->addItems({"Signed", "Unsigned"}); - sign->setCurrentIndex(sig.is_signed ? 0 : 1); form_layout->addRow(tr("sign"), sign); auto double_validator = new QDoubleValidator(this); factor = new QLineEdit(); factor->setValidator(double_validator); - factor->setText(QString::number(sig.factor)); form_layout->addRow(tr("Factor"), factor); offset = new QLineEdit(); offset->setValidator(double_validator); - offset->setText(QString::number(sig.offset)); form_layout->addRow(tr("Offset"), offset); // TODO: parse the following parameters in opendbc @@ -66,18 +63,15 @@ SignalForm::SignalForm(const Signal &sig, QWidget *parent) : QWidget(parent) { // SignalEdit -SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWidget *parent) : msg_id(msg_id), sig(sig), form_idx(index), QWidget(parent) { +SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); // title bar QHBoxLayout *title_layout = new QHBoxLayout(); - icon = new QLabel(">"); - icon->setStyleSheet("font-weight:bold"); + icon = new QLabel(); 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(getColor(index))); title_layout->addWidget(title, 1); @@ -96,9 +90,6 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWid // 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(); QPushButton *remove_btn = new QPushButton(tr("Remove Signal")); h->addWidget(remove_btn); @@ -106,8 +97,6 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWid QPushButton *save_btn = new QPushButton(tr("Save")); h->addWidget(save_btn); v_layout->addLayout(h); - - form_container->setVisible(false); main_layout->addWidget(form_container); // bottom line @@ -119,11 +108,19 @@ SignalEdit::SignalEdit(int index, const QString &msg_id, const Signal *sig, QWid QObject::connect(remove_btn, &QPushButton::clicked, [this]() { emit remove(this->sig); }); QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); QObject::connect(save_btn, &QPushButton::clicked, this, &SignalEdit::saveSignal); - QObject::connect(plot_btn, &QPushButton::clicked, [this]() { emit showChart(!chart_opened); }); - QObject::connect(seek_btn, &QPushButton::clicked, [this, msg_id]() { - SignalFindDlg dlg(msg_id, this->sig, this); + QObject::connect(plot_btn, &QPushButton::clicked, [this]() { emit showChart(msg_id, sig, !chart_opened); }); + QObject::connect(seek_btn, &QPushButton::clicked, [this]() { + SignalFindDlg dlg(msg_id, sig, this); dlg.exec(); }); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); +} + +void SignalEdit::setSignal(const QString &message_id, const Signal *signal, bool show_form) { + msg_id = message_id; + sig = signal; + title->setText(QString("%1. %2").arg(form_idx + 1).arg(sig->name.c_str())); + setFormVisible(show_form); } void SignalEdit::saveSignal() { @@ -152,6 +149,20 @@ void SignalEdit::setChartOpened(bool opened) { } void SignalEdit::setFormVisible(bool visible) { + if (visible) { + if (!form) { + form = new SignalForm(this); + ((QVBoxLayout *)form_container->layout())->insertWidget(0, form); + } + form->name->setText(sig->name.c_str()); + form->size->setValue(sig->size); + form->endianness->setCurrentIndex(sig->is_little_endian ? 0 : 1); + form->sign->setCurrentIndex(sig->is_signed ? 0 : 1); + form->factor->setText(QString::number(sig->factor)); + form->offset->setText(QString::number(sig->offset)); + form->msb->setText(QString::number(sig->msb)); + form->lsb->setText(QString::number(sig->lsb)); + } form_container->setVisible(visible); icon->setText(visible ? "▼" : ">"); } diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index e3d38d5b25..dce9d27479 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -14,9 +14,10 @@ class SignalForm : public QWidget { public: - SignalForm(const Signal &sig, QWidget *parent); + SignalForm(QWidget *parent); QLineEdit *name, *unit, *comment, *val_desc, *offset, *factor, *min_val, *max_val; + QLabel *lsb, *msb; QSpinBox *size; QComboBox *sign, *endianness; }; @@ -25,16 +26,18 @@ class SignalEdit : public QWidget { Q_OBJECT public: - SignalEdit(int index, const QString &msg_id, const Signal *sig, QWidget *parent = nullptr); + SignalEdit(int index, QWidget *parent = nullptr); + void setSignal(const QString &msg_id, const Signal *sig, bool show_form); void setChartOpened(bool opened); void setFormVisible(bool show); void signalHovered(const Signal *sig); inline bool isFormVisible() const { return form_container->isVisible(); } const Signal *sig = nullptr; + QString msg_id; signals: void highlight(const Signal *sig); - void showChart(bool show); + void showChart(const QString &name, const Signal *sig, bool show); void showFormClicked(); void remove(const Signal *sig); void save(const Signal *sig, const Signal &new_sig); @@ -44,12 +47,11 @@ protected: void leaveEvent(QEvent *event) override; void saveSignal(); - SignalForm *form; + SignalForm *form = nullptr; ElidedLabel *title; QWidget *form_container; QLabel *icon; int form_idx = 0; - QString msg_id; bool chart_opened = false; QPushButton *plot_btn; }; From 9382d5528013417e5261050bd6ccfd6eedf8d51c Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:45:35 -0400 Subject: [PATCH 0181/1179] VW MQB: Enable experimental long (#26359) * VW MQB: Harness updates * don't need the variant footnote * VW MQB: Enable experimental long * autogen doc fixes * rename that --- docs/CARS.md | 95 ++++++++++++++------------- selfdrive/car/volkswagen/interface.py | 10 +-- selfdrive/car/volkswagen/values.py | 21 +++--- 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index fa1b54c1c3..55413e208b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -11,12 +11,12 @@ A supported vehicle is one that just works when you install a comma three. All s |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| @@ -129,8 +129,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| @@ -141,13 +141,13 @@ A supported vehicle is one that just works when you install a comma three. All s |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Škoda|Kamiq 2021[6](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| -|Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Kamiq 2021[6](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| +|Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| @@ -188,37 +188,37 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat 2015-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| -|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[8](#footnotes)| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat 2015-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| +|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).
@@ -228,7 +228,8 @@ A supported vehicle is one that just works when you install a comma three. All s 5openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
6Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
7Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
-8Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
+8Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC.
+9Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
## Community Maintained Cars Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index ca6d1fa7f8..816e7fcf34 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -27,12 +27,14 @@ class CarInterface(CarInterfaceBase): ret.carName = "volkswagen" ret.radarOffCan = True + use_off_car_defaults = len(fingerprint[0]) == 0 # Pick sensible carParams during offline doc generation/CI jobs + if candidate in PQ_CARS: # Set global PQ35/PQ46/NMS parameters ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagenPq)] ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1 - if 0x440 in fingerprint[0] or len(fingerprint[0]) == 0: # Getriebe_1, or empty FP for CI/docs generation + if 0x440 in fingerprint[0] or use_off_car_defaults: # Getriebe_1 ret.transmissionType = TransmissionType.automatic else: ret.transmissionType = TransmissionType.manual @@ -55,7 +57,7 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagen)] ret.enableBsm = 0x30F in fingerprint[0] # SWA_01 - if 0xAD in fingerprint[0] or len(fingerprint[0]) == 0: # Getriebe_11, or empty FP for CI/docs generation + if 0xAD in fingerprint[0] or use_off_car_defaults: # Getriebe_11 ret.transmissionType = TransmissionType.automatic elif 0x187 in fingerprint[0]: # EV_Gearshift ret.transmissionType = TransmissionType.direct @@ -81,8 +83,8 @@ class CarInterface(CarInterfaceBase): # Global longitudinal tuning defaults, can be overridden per-vehicle - ret.experimentalLongitudinalAvailable = ret.networkLocation == NetworkLocation.gateway and False # Disabled for now - if experimental_long and False: # Disabled for now + ret.experimentalLongitudinalAvailable = ret.networkLocation == NetworkLocation.gateway or use_off_car_defaults + if experimental_long: # Proof-of-concept, prep for E2E only. No radar points available. Panda ALLOW_DEBUG firmware required. ret.openpilotLongitudinalControl = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_VOLKSWAGEN_LONG_CONTROL diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 74b111a99e..babaffbcbe 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1,5 +1,5 @@ from collections import defaultdict, namedtuple -from dataclasses import dataclass +from dataclasses import dataclass, field from enum import Enum from typing import Dict, List, Union @@ -151,6 +151,10 @@ class Footnote(Enum): PASSAT = CarFootnote( "Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.", Column.MODEL) + VW_EXP_LONG = CarFootnote ( + "Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness " + + "are limited to using stock ACC.", + Column.LONGITUDINAL) VW_MQB_A0 = CarFootnote( "Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot " + "in software, but doesn't yet have a harness available from the comma store.", @@ -161,6 +165,7 @@ class Footnote(Enum): class VWCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC) & Lane Assist" harness: Enum = Harness.j533 + footnotes: List[Enum] = field(default_factory=lambda: [Footnote.VW_EXP_LONG]) CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { @@ -192,28 +197,28 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { VWCarInfo("Volkswagen Jetta GLI 2021-22"), ], CAR.PASSAT_MK8: [ - VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.PASSAT]), + VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.VW_EXP_LONG, Footnote.PASSAT]), VWCarInfo("Volkswagen Passat Alltrack 2015-22"), VWCarInfo("Volkswagen Passat GTE 2015-22"), ], CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22"), CAR.POLO_MK6: [ - VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_MQB_A0]), - VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_MQB_A0]), + VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), + VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), ], CAR.SHARAN_MK2: [ VWCarInfo("Volkswagen Sharan 2018-22"), VWCarInfo("SEAT Alhambra 2018-20"), ], CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022"), - CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_MQB_A0]), + CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22"), CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"), CAR.TRANSPORTER_T61: [ VWCarInfo("Volkswagen Caravelle 2020"), VWCarInfo("Volkswagen California 2021"), ], - CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_MQB_A0]), + CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), CAR.AUDI_A3_MK3: [ VWCarInfo("Audi A3 2014-19"), VWCarInfo("Audi A3 Sportback e-tron 2017-18"), @@ -224,10 +229,10 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2019-23"), CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018"), CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20"), - CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_MQB_A0, Footnote.KAMIQ]), + CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0, Footnote.KAMIQ]), CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21"), CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"), - CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_MQB_A0]), + CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-18"), CAR.SKODA_OCTAVIA_MK3: [ VWCarInfo("Škoda Octavia 2015, 2018-19"), From 615198bfd09586a763955f13a27af9a84d5b997d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 4 Nov 2022 12:46:06 -0700 Subject: [PATCH 0182/1179] bump panda (#26362) --- panda | 2 +- poetry.lock | 63 +++++++++++++++++++++++++++++++++----------------- pyproject.toml | 1 + 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/panda b/panda index 9147cba1af..0b86dfa5fb 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 9147cba1af0a8d72379242eb1ce0bfd42ab8075e +Subproject commit 0b86dfa5fbfcb77a127f980f81484aa7558e8c1e diff --git a/poetry.lock b/poetry.lock index 2dff4fecf1..d79a3f035f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -230,7 +230,7 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "av" @@ -531,7 +531,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode_backport = ["unicodedata2"] +unicode-backport = ["unicodedata2"] [[package]] name = "cleo" @@ -1410,7 +1410,7 @@ notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test_extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] [[package]] name = "ipython-genutils" @@ -1459,9 +1459,9 @@ python-versions = ">=3.6.1,<4.0" [package.extras] colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +pipfile-deprecated-finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] -requirements_deprecated_finder = ["pip-api", "pipreqs"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "itsdangerous" @@ -1892,7 +1892,7 @@ mdurl = ">=0.1,<1.0" [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"] -code_style = ["pre-commit (==2.6)"] +code-style = ["pre-commit (==2.6)"] compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"] linkify = ["linkify-it-py (>=1.0,<2.0)"] plugins = ["mdit-py-plugins"] @@ -1959,7 +1959,7 @@ python-versions = ">=3.7" markdown-it-py = ">=1.0.0,<3.0.0" [package.extras] -code_style = ["pre-commit"] +code-style = ["pre-commit"] rtd = ["attrs", "myst-parser (>=0.16.1,<0.17.0)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] @@ -2169,7 +2169,7 @@ sphinx = ">=4,<6" typing-extensions = "*" [package.extras] -code_style = ["pre-commit (>=2.12,<3.0)"] +code-style = ["pre-commit (>=2.12,<3.0)"] linkify = ["linkify-it-py (>=1.0,<2.0)"] rtd = ["ipython", "sphinx-book-theme", "sphinx-design", "sphinxcontrib.mermaid (>=0.7.1,<0.8.0)", "sphinxext-opengraph (>=0.6.3,<0.7.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=6,<7)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx (<5.2)", "sphinx-pytest"] @@ -3193,7 +3193,7 @@ optional = false python-versions = ">=3.6" [package.extras] -asyncio_client = ["aiohttp (>=3.4)"] +asyncio-client = ["aiohttp (>=3.4)"] client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] @@ -3217,7 +3217,7 @@ bidict = ">=0.21.0" python-engineio = ">=4.3.0" [package.extras] -asyncio_client = ["aiohttp (>=3.4)"] +asyncio-client = ["aiohttp (>=3.4)"] client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] @@ -3393,7 +3393,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-oauthlib" @@ -3584,7 +3584,7 @@ falcon = ["falcon (>=1.4)"] fastapi = ["fastapi (>=0.79.0)"] flask = ["blinker (>=1.1)", "flask (>=0.11)"] httpx = ["httpx (>=0.16.0)"] -pure_eval = ["asttokens", "executing", "pure-eval"] +pure-eval = ["asttokens", "executing", "pure-eval"] pyspark = ["pyspark (>=2.4.4)"] quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] rq = ["rq (>=0.6)"] @@ -3834,6 +3834,14 @@ python-versions = ">=3.5" lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] +[[package]] +name = "spidev" +version = "3.6" +description = "Python bindings for Linux SPI access through spidev" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "sqlalchemy" version = "1.4.42" @@ -3850,19 +3858,19 @@ aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql_pymssql = ["pymssql"] -mssql_pyodbc = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql_connector = ["mysql-connector-python"] +mysql-connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql_psycopg2binary = ["psycopg2-binary"] -postgresql_psycopg2cffi = ["psycopg2cffi"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] sqlcipher = ["sqlcipher3_binary"] @@ -4378,7 +4386,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "76f06d46b1c308e59968994e42193599d8ba3cab6d552460c9c48f282313b64d" +content-hash = "d2854112975a9d83a9540175b2d430487e40e0292d48a1ba6c591db60a08c136" [metadata.files] adal = [ @@ -5384,6 +5392,7 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6554,6 +6563,11 @@ pillow-avif-plugin = [ {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017e5e52cb4320414e8ce3e2089eae2cb87c22c73ff6012b17ae326fc5753b20"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a57136d4866de5dc80cfb24d66655955fbdd87acf1d11d88c8dc2ab41023e46"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:f339511d0fccb69e3a5e3af39f8fe6700b0a07279015006ea56f8f49e7fecff4"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05e821ecd90bb0b8d2dc7610625372cc47de9cb893d09662528bad572f669d1c"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33886a5f9796fe9a8a3bc25ccfdeba7db119adb50b7004f1928a14b07d0213a"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75b7ed186c2f740dd26e556f6a966c59a170b70263e429a2c81920fe444da8a7"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11aef6b79078b8dad25c928e5871c146ab94424472851d5bf539ba62abde9ac"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10696c536d68a14cefea3b98edb8d5a7ae29e8e07458f1d59c5d1cd780a8bf2a"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1a7291d6a5fb7336e72685a31d193e0b3a6bee9986c9ac4d8bd4b68dbe6d4f7f"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:14b9c5dbf237e7dc12f69819ea181a457b3bd4f59f8cd71d028d3635fd3bcab4"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:799cbfbeee831332d280c80df9ce16b5c3b1224c318264e97e89df8da32e870e"}, @@ -6942,11 +6956,13 @@ pyprof2calltree = [ ] pyproj = [ {file = "pyproj-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f343725566267a296b09ee7e591894f1fdc90f84f8ad5ec476aeb53bd4479c07"}, + {file = "pyproj-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5816807ca0bdc7256558770c6206a6783a3f02bcf844f94ee245f197bb5f7285"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e609903572a56cca758bbaee5c1663c3e829ddce5eec4f368e68277e37022b"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fd425ee8b6781c249c7adb7daa2e6c41ce573afabe4f380f5eecd913b56a3be"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954b068136518b3174d0a99448056e97af62b63392a95c420894f7de2229dae6"}, {file = "pyproj-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:4a23d84c5ffc383c7d9f0bde3a06fc1f6697b1b96725597f8f01e7b4bef0a2b5"}, {file = "pyproj-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f9c100fd0fd80edbc7e4daa303600a8cbef6f0de43d005617acb38276b88dc0"}, + {file = "pyproj-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa5171f700f174777a9e9ed8f4655583243967c0f9cf2c90e3f54e54ff740134"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a496d9057b2128db9d733e66b206f2d5954bbae6b800d412f562d780561478c"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52e54796e2d9554a5eb8f11df4748af1fbbc47f76aa234d6faf09216a84554c5"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a454a7c4423faa2a14e939d08ef293ee347fa529c9df79022b0585a6e1d8310c"}, @@ -6957,6 +6973,7 @@ pyproj = [ {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f80adda8c54b84271a93829477a01aa57bc178c834362e9f74e1de1b5033c74c"}, {file = "pyproj-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:221d8939685e0c43ee594c9f04b6a73a10e8e1cc0e85f28be0b4eb2f1bc8777d"}, {file = "pyproj-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d94afed99f31673d3d19fe750283621e193e2a53ca9e0443bf9d092c3905833b"}, + {file = "pyproj-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fff9c3a991508f16027be27d153f6c5583d03799443639d13c681e60f49e2d7"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85acf09e5a9e35cd9ee72989793adb7089b4e611be02a43d3d0bda50ad116b"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45554f47d1a12a84b0620e4abc08a2a1b5d9f273a4759eaef75e74788ec7162a"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f62c20656ac9b6076ebb213e9a635d52f4f01fef95310121d337e62e910cb6"}, @@ -7537,6 +7554,10 @@ sphinxcontrib-serializinghtml = [ {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, ] +spidev = [ + {file = "spidev-3.6-cp39-cp39-linux_armv7l.whl", hash = "sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5"}, + {file = "spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b"}, +] sqlalchemy = [ {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, diff --git a/pyproject.toml b/pyproject.toml index ebb7954536..7e76b9cdfc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ tqdm = "^4.64.0" urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" +spidev = "^3.6" [tool.poetry.group.dev.dependencies] From a7ced7c54b86107cb4095423158e28398aa62143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 4 Nov 2022 13:21:34 -0700 Subject: [PATCH 0183/1179] Longcontrol: faster transition from starting to stopping (#26361) * Never command accel when stopping * Update ref_commit --- selfdrive/controls/lib/longcontrol.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index db5bf4d3e6..92a4f1f99b 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -103,6 +103,7 @@ class LongControl: elif self.long_control_state == LongCtrlState.stopping: if output_accel > self.CP.stopAccel: + output_accel = min(output_accel, 0.0) output_accel -= self.CP.stoppingDecelRate * DT_CTRL self.reset(CS.vEgo) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 40f3c522de..a0cfd2201f 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -2ba23c5d1c4e0c34295d38f31ed35e3482608b16 \ No newline at end of file +89641653a0fc765105dc1c6a2a995cba2fb3f344 From d257e28479f49339e7f79491ff9d67e9ba034dfe Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 4 Nov 2022 13:52:24 -0700 Subject: [PATCH 0184/1179] ui: minor e2e path tweaks (#26351) * new e2e path * clean up * fix * 2.5 seconds feels disjointed --- selfdrive/ui/qt/onroad.cc | 17 ++++++++--------- selfdrive/ui/qt/onroad.h | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index d3bc931b67..85b55697be 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -170,7 +170,7 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { } -AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) { +AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), accel_filter(UI_FREQ, .5, 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}); @@ -463,19 +463,18 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { if (scene.end_to_end_long) { const auto &acceleration = (*s->sm)["modelV2"].getModelV2().getAcceleration(); float acceleration_future = 0; - if (acceleration.getZ().size() > 16) { - acceleration_future = acceleration.getX()[16]; // 2.5 seconds + if (acceleration.getZ().size() > 10) { + acceleration_future = acceleration.getX()[10]; // 1.0 second } - start_hue = 60; - // speed up: 120, slow down: 0 - end_hue = fmax(fmin(start_hue + acceleration_future * 30, 120), 0); + // speed up: 148, slow down: 0 + start_hue = fmax(fmin(60 + accel_filter.update(acceleration_future) * 80, 148), 0); // FIXME: painter.drawPolygon can be slow if hue is not rounded - end_hue = int(end_hue * 100 + 0.5) / 100; + start_hue = int(start_hue * 100 + 0.5) / 100; bg.setColorAt(0.0, QColor::fromHslF(start_hue / 360., 0.97, 0.56, 0.4)); - bg.setColorAt(0.5, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.35)); - bg.setColorAt(1.0, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.0)); + bg.setColorAt(0.75, QColor::fromHslF(63 / 360., 1.0, 0.68, 0.35)); + bg.setColorAt(1.0, QColor::fromHslF(63 / 360., 1.0, 0.68, 0.0)); } else { const auto &orientation = (*s->sm)["modelV2"].getModelV2().getOrientation(); float orientation_future = 0; diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 7edca6b3d5..1f6a49bf8c 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -87,6 +87,7 @@ protected: double prev_draw_t = 0; FirstOrderFilter fps_filter; + FirstOrderFilter accel_filter; }; // container for all onroad widgets From 2837e73a70b8b8faba7047db5124a582635439ff Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Fri, 4 Nov 2022 14:18:51 -0700 Subject: [PATCH 0185/1179] DM: compensate for non-calibrated pitch spread (#26348) --- selfdrive/monitoring/driver_monitor.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index a2dda5da9d..48163dcf2a 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -44,6 +44,7 @@ class DRIVER_MONITOR_SETTINGS(): self._POSE_YAW_THRESHOLD_SLACK = 0.5042 self._POSE_YAW_THRESHOLD_STRICT = self._POSE_YAW_THRESHOLD self._PITCH_NATURAL_OFFSET = 0.029 # initial value before offset is learned + self._PITCH_NATURAL_THRESHOLD = 0.449 self._YAW_NATURAL_OFFSET = 0.097 # initial value before offset is learned self._PITCH_MAX_OFFSET = 0.124 self._PITCH_MIN_OFFSET = -0.0881 @@ -197,7 +198,7 @@ class DriverStatus(): self.settings._YAW_MIN_OFFSET), self.settings._YAW_MAX_OFFSET) pitch_error = 0 if pitch_error > 0 else abs(pitch_error) # no positive pitch limit yaw_error = abs(yaw_error) - if pitch_error > self.settings._POSE_PITCH_THRESHOLD*self.pose.cfactor_pitch or \ + if pitch_error > (self.settings._POSE_PITCH_THRESHOLD*self.pose.cfactor_pitch if self.pose_calibrated else self.settings._PITCH_NATURAL_THRESHOLD) or \ yaw_error > self.settings._POSE_YAW_THRESHOLD*self.pose.cfactor_yaw: distracted_types.append(DistractedType.DISTRACTED_POSE) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a0cfd2201f..8bc13f37d4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -89641653a0fc765105dc1c6a2a995cba2fb3f344 +24a8d02b148b7f6d20f641d56a7bed71c244b6e3 \ No newline at end of file From 91a1f1a91e8ac321ad2a69c3a44f41464147fc19 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 4 Nov 2022 15:37:41 -0700 Subject: [PATCH 0186/1179] ui: toggle confirmation and dialog redesign (#26331) * toggle confirmation * change text * not for e2e * get current description * remove are you sure * merge rich text and confirmation dialogs * add some line breaks * font colour * fix padding a little * revert * updated toggle design --- selfdrive/ui/qt/offroad/settings.cc | 20 +++++++--- selfdrive/ui/qt/widgets/controls.h | 16 +++++++- selfdrive/ui/qt/widgets/input.cc | 50 ++++++------------------ selfdrive/ui/qt/widgets/input.h | 12 +----- selfdrive/ui/translations/main_ja.ts | 18 +++++---- selfdrive/ui/translations/main_ko.ts | 18 +++++---- selfdrive/ui/translations/main_pt-BR.ts | 18 +++++---- selfdrive/ui/translations/main_zh-CHS.ts | 18 +++++---- selfdrive/ui/translations/main_zh-CHT.ts | 18 +++++---- 9 files changed, 97 insertions(+), 91 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index ae878c5419..b154447eb8 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -27,49 +27,56 @@ #include "selfdrive/ui/qt/widgets/input.h" TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { - // param, title, desc, icon - std::vector> toggle_defs{ + // param, title, desc, icon, confirm + std::vector> toggle_defs{ { "OpenpilotEnabledToggle", tr("Enable openpilot"), tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), "../assets/offroad/icon_openpilot.png", + false, }, { "IsLdwEnabled", tr("Enable Lane Departure Warnings"), tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), "../assets/offroad/icon_warning.png", + false, }, { "IsMetric", tr("Use Metric System"), tr("Display speed in km/h instead of mph."), "../assets/offroad/icon_metric.png", + false, }, { "RecordFront", tr("Record and Upload Driver Camera"), tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), "../assets/offroad/icon_monitoring.png", + false, }, { "DisengageOnAccelerator", tr("Disengage On Accelerator Pedal"), tr("When enabled, pressing the accelerator pedal will disengage openpilot."), "../assets/offroad/icon_disengage_on_accelerator.svg", + false, }, { "EndToEndLong", tr("🌮 End-to-end longitudinal (extremely alpha) 🌮"), "", "../assets/offroad/icon_road.png", + false, }, { "ExperimentalLongitudinalEnabled", tr("Experimental openpilot longitudinal control"), tr("WARNING: openpilot longitudinal control is experimental for this car and will disable AEB."), "../assets/offroad/icon_speed_limit.png", + true, }, #ifdef ENABLE_MAPS { @@ -77,19 +84,20 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { tr("Show ETA in 24h Format"), tr("Use 24h format instead of am/pm"), "../assets/offroad/icon_metric.png", + false, }, { "NavSettingLeftSide", tr("Show Map on Left Side of UI"), tr("Show map on left side when in split screen view."), "../assets/offroad/icon_road.png", + false, }, #endif - }; - for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, this); + for (auto &[param, title, desc, icon, confirm] : toggle_defs) { + auto toggle = new ParamControl(param, title, desc, icon, confirm, this); bool locked = params.getBool((param + "Lock").toStdString()); toggle->setEnabled(!locked); @@ -181,7 +189,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { auto regulatoryBtn = new ButtonControl(tr("Regulatory"), tr("VIEW"), ""); connect(regulatoryBtn, &ButtonControl::clicked, [=]() { const std::string txt = util::read_file("../assets/offroad/fcc.html"); - RichTextDialog::alert(QString::fromStdString(txt), this); + ConfirmationDialog::rich(QString::fromStdString(txt), this); }); addItem(regulatoryBtn); } diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index f11f9baf59..243c078f85 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -7,6 +7,7 @@ #include #include "common/params.h" +#include "selfdrive/ui/qt/widgets/input.h" #include "selfdrive/ui/qt/widgets/toggle.h" QFrame *horizontal_line(QWidget *parent = nullptr); @@ -49,6 +50,10 @@ public: value->setText(val); } + const QString getDescription() { + return description->text(); + } + public slots: void showDescription() { description->setVisible(true); @@ -134,10 +139,17 @@ class ParamControl : public ToggleControl { Q_OBJECT public: - ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { + ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const bool confirm, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { key = param.toStdString(); QObject::connect(this, &ParamControl::toggleFlipped, [=](bool state) { - params.putBool(key, state); + QString content("

" + title + "



" + "

" + getDescription() + "

"); + ConfirmationDialog dialog(content, tr("Ok"), tr("Cancel"), true, this); + if (!confirm || !state || dialog.exec()) { + params.putBool(key, state); + } else { + toggle.togglePosition(); + } }); } diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index d703825885..897e4b5a05 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -183,17 +183,17 @@ void InputDialog::setMinLength(int length) { // ConfirmationDialog ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, - QWidget *parent) : QDialogBase(parent) { + const bool rich, QWidget *parent) : QDialogBase(parent) { QFrame *container = new QFrame(this); - container->setStyleSheet("QFrame { border-radius: 0; background-color: #ECECEC; }"); + container->setStyleSheet("QFrame { background-color: #1B1B1B; color: #C9C9C9; }"); QVBoxLayout *main_layout = new QVBoxLayout(container); - main_layout->setContentsMargins(32, 120, 32, 32); + main_layout->setContentsMargins(32, rich ? 32 : 120, 32, 32); QLabel *prompt = new QLabel(prompt_text, this); prompt->setWordWrap(true); - prompt->setAlignment(Qt::AlignHCenter); - prompt->setStyleSheet("font-size: 70px; font-weight: bold; color: black;"); - main_layout->addWidget(prompt, 1, Qt::AlignTop | Qt::AlignHCenter); + prompt->setAlignment(rich ? Qt::AlignLeft : Qt::AlignHCenter); + prompt->setStyleSheet((rich ? "font-size: 42px; font-weight: light;" : "font-size: 70px; font-weight: bold;") + QString(" margin: 45px;")); + main_layout->addWidget(rich ? (QWidget*)new ScrollView(prompt, this) : (QWidget*)prompt, 1, Qt::AlignTop); // cancel + confirm buttons QHBoxLayout *btn_layout = new QHBoxLayout(); @@ -213,49 +213,23 @@ ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString } QVBoxLayout *outer_layout = new QVBoxLayout(this); - outer_layout->setContentsMargins(210, 170, 210, 170); + int margin = rich ? 100 : 200; + outer_layout->setContentsMargins(margin, margin, margin, margin); outer_layout->addWidget(container); } bool ConfirmationDialog::alert(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Ok"), "", parent); + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Ok"), "", false, parent); return d.exec(); } bool ConfirmationDialog::confirm(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Ok"), tr("Cancel"), parent); + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Ok"), tr("Cancel"), false, parent); return d.exec(); } - -// RichTextDialog - -RichTextDialog::RichTextDialog(const QString &prompt_text, const QString &btn_text, - QWidget *parent) : QDialogBase(parent) { - QFrame *container = new QFrame(this); - container->setStyleSheet("QFrame { background-color: #1B1B1B; }"); - QVBoxLayout *main_layout = new QVBoxLayout(container); - main_layout->setContentsMargins(32, 32, 32, 32); - - QLabel *prompt = new QLabel(prompt_text, this); - prompt->setWordWrap(true); - prompt->setAlignment(Qt::AlignLeft); - prompt->setTextFormat(Qt::RichText); - prompt->setStyleSheet("font-size: 42px; font-weight: light; color: #C9C9C9; margin: 45px;"); - main_layout->addWidget(new ScrollView(prompt, this), 1, Qt::AlignTop); - - // confirm button - QPushButton* confirm_btn = new QPushButton(btn_text); - main_layout->addWidget(confirm_btn); - QObject::connect(confirm_btn, &QPushButton::clicked, this, &QDialog::accept); - - QVBoxLayout *outer_layout = new QVBoxLayout(this); - outer_layout->setContentsMargins(100, 100, 100, 100); - outer_layout->addWidget(container); -} - -bool RichTextDialog::alert(const QString &prompt_text, QWidget *parent) { - auto d = RichTextDialog(prompt_text, tr("Ok"), parent); +bool ConfirmationDialog::rich(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Ok"), "", true, parent); return d.exec(); } diff --git a/selfdrive/ui/qt/widgets/input.h b/selfdrive/ui/qt/widgets/input.h index 6c47a31d87..117e6ca05e 100644 --- a/selfdrive/ui/qt/widgets/input.h +++ b/selfdrive/ui/qt/widgets/input.h @@ -55,18 +55,10 @@ class ConfirmationDialog : public QDialogBase { public: explicit ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, - const QString &cancel_text, QWidget* parent); + const QString &cancel_text, const bool rich, QWidget* parent); static bool alert(const QString &prompt_text, QWidget *parent); static bool confirm(const QString &prompt_text, QWidget *parent); -}; - -// larger ConfirmationDialog for rich text -class RichTextDialog : public QDialogBase { - Q_OBJECT - -public: - explicit RichTextDialog(const QString &prompt_text, const QString &btn_text, QWidget* parent); - static bool alert(const QString &prompt_text, QWidget *parent); + static bool rich(const QString &prompt_text, QWidget *parent); }; class MultiOptionDialog : public QDialogBase { diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index a11333a54d..d3c55b5be4 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -463,6 +463,17 @@ location set 「connect.comma.ai」をホーム画面に追加して、アプリのように使うことができます。
+ + ParamControl + + Ok + OK + + + Cancel + キャンセル + + PrimeAdWidget @@ -585,13 +596,6 @@ location set 「data」パーティションをマウントできません。「確認」ボタンを押すとデバイスが初期化されます。 - - RichTextDialog - - Ok - OK - - SettingsWindow diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 021243595e..4112087f72 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -463,6 +463,17 @@ location set connect.comma.ai을 앱처럼 사용하려면 홈 화면에 바로가기를 만드십시오 + + ParamControl + + Ok + 확인 + + + Cancel + 취소 + + PrimeAdWidget @@ -585,13 +596,6 @@ location set 데이터 파티션을 마운트할 수 없습니다. 확인 버튼을 눌러 장치를 리셋합니다. - - RichTextDialog - - Ok - 확인 - - SettingsWindow diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 2afdaf3388..ab1946e6af 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -464,6 +464,17 @@ trabalho definido Salve connect.comma.ai como sua página inicial para utilizar como um app + + ParamControl + + Ok + OK + + + Cancel + Cancelar + + PrimeAdWidget @@ -589,13 +600,6 @@ trabalho definido Não foi possível montar a partição de dados. Pressione confirmar para resetar seu dispositivo. - - RichTextDialog - - Ok - Ok - - SettingsWindow diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 9e7c354444..2baae98669 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -461,6 +461,17 @@ location set 将 connect.comma.ai 收藏到您的主屏幕,以便像应用程序一样使用它 + + ParamControl + + Ok + 好的 + + + Cancel + 取消 + + PrimeAdWidget @@ -583,13 +594,6 @@ location set 无法挂载数据分区。 确认以重置您的设备。 - - RichTextDialog - - Ok - 好的 - - SettingsWindow diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 513135c7f4..44c231311a 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -463,6 +463,17 @@ location set 將 connect.comma.ai 加入您的主屏幕,以便像手機 App 一樣使用它 + + ParamControl + + Ok + 確定 + + + Cancel + 取消 + + PrimeAdWidget @@ -585,13 +596,6 @@ location set 無法掛載數據分區。請按確認重置您的設備。 - - RichTextDialog - - Ok - 確定 - - SettingsWindow From 31dbd21f07c90182472d00c2d4197947dc83861a Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 4 Nov 2022 19:32:40 -0400 Subject: [PATCH 0187/1179] Hyundai: Add FW for 2023 Ioniq 5 HDA2 (#26145) --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 55413e208b..9d279e918e 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -59,7 +59,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Ioniq 5 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| +|Hyundai|Ioniq 5 (with HDA II) 2022-23|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Ioniq 5 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4415679175..0df9850d0b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -143,7 +143,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a), CAR.IONIQ_5: [ HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022" , "Highway Driving Assist", harness=Harness.hyundai_k), - HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022", "Highway Driving Assist II", harness=Harness.hyundai_q), + HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", harness=Harness.hyundai_q), ], CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), @@ -1379,6 +1379,7 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', + b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', ], }, CAR.TUCSON_HYBRID_4TH_GEN: { From 06be96cae29bb347da2a9df43976613f3f2cc025 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 4 Nov 2022 16:36:27 -0700 Subject: [PATCH 0188/1179] boardd: prep for SPI + factor out USB (#26356) * merge origin/spi-panda * just prep * boardd: factor out USB comms * fix those * add to release files * little more --- release/files_common | 2 + selfdrive/boardd/SConscript | 4 +- selfdrive/boardd/boardd.cc | 18 +- selfdrive/boardd/panda.cc | 284 +++++--------------------------- selfdrive/boardd/panda.h | 45 ++--- selfdrive/boardd/panda_comms.cc | 232 ++++++++++++++++++++++++++ selfdrive/boardd/panda_comms.h | 51 ++++++ 7 files changed, 350 insertions(+), 286 deletions(-) create mode 100644 selfdrive/boardd/panda_comms.cc create mode 100644 selfdrive/boardd/panda_comms.h diff --git a/release/files_common b/release/files_common index e3c417040c..61d16a2088 100644 --- a/release/files_common +++ b/release/files_common @@ -90,6 +90,8 @@ selfdrive/boardd/boardd_api_impl.pyx selfdrive/boardd/can_list_to_can_capnp.cc selfdrive/boardd/panda.cc selfdrive/boardd/panda.h +selfdrive/boardd/panda_comms.h +selfdrive/boardd/panda_comms.cc selfdrive/boardd/set_time.py selfdrive/boardd/pandad.py diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript index dcbea03d3c..356b5de663 100644 --- a/selfdrive/boardd/SConscript +++ b/selfdrive/boardd/SConscript @@ -1,9 +1,9 @@ Import('env', 'envCython', 'common', 'cereal', 'messaging') libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'] -env.Program('boardd', ['main.cc', 'boardd.cc', 'panda.cc'], LIBS=libs) +env.Program('boardd', ['main.cc', 'boardd.cc', 'panda.cc', 'panda_comms.cc'], LIBS=libs) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) if GetOption('test'): - env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc', 'panda.cc'], LIBS=libs) + env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc', 'panda.cc', 'panda_comms.cc'], LIBS=libs) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 2d613b68ce..5496902252 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -19,8 +19,6 @@ #include #include -#include - #include "cereal/gen/cpp/car.capnp.h" #include "cereal/messaging/messaging.h" #include "common/params.h" @@ -67,7 +65,7 @@ static std::string get_time_str(const struct tm &time) { bool check_all_connected(const std::vector &pandas) { for (const auto& panda : pandas) { - if (!panda->connected) { + if (!panda->connected()) { do_exit = true; return false; } @@ -184,7 +182,7 @@ bool safety_setter_thread(std::vector pandas) { return true; } -Panda *usb_connect(std::string serial="", uint32_t index=0) { +Panda *connect(std::string serial="", uint32_t index=0) { std::unique_ptr panda; try { panda = std::make_unique(serial, (index * PANDA_BUS_CNT)); @@ -227,9 +225,9 @@ void can_send_thread(std::vector pandas, bool fake_send) { //Dont send if older than 1 second if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) { for (const auto& panda : pandas) { - LOGT("sending sendcan to panda: %s", (panda->usb_serial).c_str()); + LOGT("sending sendcan to panda: %s", (panda->hw_serial).c_str()); panda->can_send(event.getSendcan()); - LOGT("sendcan sent to panda: %s", (panda->usb_serial).c_str()); + LOGT("sendcan sent to panda: %s", (panda->hw_serial).c_str()); } } } @@ -357,7 +355,7 @@ std::optional send_panda_states(PubMaster *pm, const std::vector } #endif - if (!panda->comms_healthy) { + if (!panda->comms_healthy()) { evt.setValid(false); } @@ -433,7 +431,7 @@ void send_peripheral_state(PubMaster *pm, Panda *panda) { // build msg MessageBuilder msg; auto evt = msg.initEvent(); - evt.setValid(panda->comms_healthy); + evt.setValid(panda->comms_healthy()); auto ps = evt.initPeripheralState(); ps.setPandaType(panda->hw_type); @@ -526,7 +524,7 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) { FirstOrderFilter integ_lines_filter(0, 30.0, 0.05); - while (!do_exit && panda->connected) { + while (!do_exit && panda->connected()) { cnt++; sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update? @@ -595,7 +593,7 @@ void boardd_main_thread(std::vector serials) { // connect to all provided serials std::vector pandas; for (int i = 0; i < serials.size() && !do_exit; /**/) { - Panda *p = usb_connect(serials[i], i); + Panda *p = connect(serials[i], i); if (!p) { // send empty pandaState & peripheralState and try again send_empty_panda_state(&pm); diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 329ce91c44..e68558632e 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -4,75 +4,15 @@ #include #include -#include #include "cereal/messaging/messaging.h" #include "panda/board/dlc_to_len.h" -#include "common/gpio.h" #include "common/swaglog.h" #include "common/util.h" -static int init_usb_ctx(libusb_context **context) { - assert(context != nullptr); - - int err = libusb_init(context); - if (err != 0) { - LOGE("libusb initialization error"); - return err; - } - -#if LIBUSB_API_VERSION >= 0x01000106 - libusb_set_option(*context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); -#else - libusb_set_debug(*context, 3); -#endif - - return err; -} - - Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { - // init libusb - ssize_t num_devices; - libusb_device **dev_list = NULL; - int err = init_usb_ctx(&ctx); - if (err != 0) { goto fail; } - - // connect by serial - num_devices = libusb_get_device_list(ctx, &dev_list); - if (num_devices < 0) { goto fail; } - for (size_t i = 0; i < num_devices; ++i) { - libusb_device_descriptor desc; - libusb_get_device_descriptor(dev_list[i], &desc); - if (desc.idVendor == 0xbbaa && desc.idProduct == 0xddcc) { - int ret = libusb_open(dev_list[i], &dev_handle); - if (dev_handle == NULL || ret < 0) { goto fail; } - - unsigned char desc_serial[26] = { 0 }; - ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, desc_serial, std::size(desc_serial)); - if (ret < 0) { goto fail; } - - usb_serial = std::string((char *)desc_serial, ret).c_str(); - if (serial.empty() || serial == usb_serial) { - break; - } - libusb_close(dev_handle); - dev_handle = NULL; - } - } - if (dev_handle == NULL) goto fail; - libusb_free_device_list(dev_list, 1); - dev_list = nullptr; - - if (libusb_kernel_driver_active(dev_handle, 0) == 1) { - libusb_detach_kernel_driver(dev_handle, 0); - } - - err = libusb_set_configuration(dev_handle, 1); - if (err != 0) { goto fail; } - - err = libusb_claim_interface(dev_handle, 0); - if (err != 0) { goto fail; } + // TODO: support SPI here one day... + handle = std::make_unique(serial); hw_type = get_hw_type(); @@ -83,194 +23,44 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { (hw_type == cereal::PandaState::PandaType::DOS); return; - -fail: - if (dev_list != NULL) { - libusb_free_device_list(dev_list, 1); - } - cleanup(); - throw std::runtime_error("Error connecting to panda"); } -Panda::~Panda() { - std::lock_guard lk(usb_lock); - cleanup(); - connected = false; +bool Panda::connected() { + return handle->connected; } -void Panda::cleanup() { - if (dev_handle) { - libusb_release_interface(dev_handle, 0); - libusb_close(dev_handle); - } - - if (ctx) { - libusb_exit(ctx); - } +bool Panda::comms_healthy() { + return handle->comms_healthy; } std::vector Panda::list() { - // init libusb - ssize_t num_devices; - libusb_context *context = NULL; - libusb_device **dev_list = NULL; - std::vector serials; - - int err = init_usb_ctx(&context); - if (err != 0) { return serials; } - - num_devices = libusb_get_device_list(context, &dev_list); - if (num_devices < 0) { - LOGE("libusb can't get device list"); - goto finish; - } - for (size_t i = 0; i < num_devices; ++i) { - libusb_device *device = dev_list[i]; - libusb_device_descriptor desc; - libusb_get_device_descriptor(device, &desc); - if (desc.idVendor == 0xbbaa && desc.idProduct == 0xddcc) { - libusb_device_handle *handle = NULL; - int ret = libusb_open(device, &handle); - if (ret < 0) { goto finish; } - - unsigned char desc_serial[26] = { 0 }; - ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, desc_serial, std::size(desc_serial)); - libusb_close(handle); - if (ret < 0) { goto finish; } - - serials.push_back(std::string((char *)desc_serial, ret).c_str()); - } - } - -finish: - if (dev_list != NULL) { - libusb_free_device_list(dev_list, 1); - } - if (context) { - libusb_exit(context); - } - return serials; -} - -void Panda::handle_usb_issue(int err, const char func[]) { - LOGE_100("usb error %d \"%s\" in %s", err, libusb_strerror((enum libusb_error)err), func); - if (err == LIBUSB_ERROR_NO_DEVICE) { - LOGE("lost connection"); - connected = false; - } - // TODO: check other errors, is simply retrying okay? -} - -int Panda::usb_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout) { - int err; - const uint8_t bmRequestType = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE; - - if (!connected) { - return LIBUSB_ERROR_NO_DEVICE; - } - - std::lock_guard lk(usb_lock); - do { - err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, NULL, 0, timeout); - if (err < 0) handle_usb_issue(err, __func__); - } while (err < 0 && connected); - - return err; -} - -int Panda::usb_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) { - int err; - const uint8_t bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE; - - if (!connected) { - return LIBUSB_ERROR_NO_DEVICE; - } - - std::lock_guard lk(usb_lock); - do { - err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout); - if (err < 0) handle_usb_issue(err, __func__); - } while (err < 0 && connected); - - return err; -} - -int Panda::usb_bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { - int err; - int transferred = 0; - - if (!connected) { - return 0; - } - - std::lock_guard lk(usb_lock); - do { - // Try sending can messages. If the receive buffer on the panda is full it will NAK - // and libusb will try again. After 5ms, it will time out. We will drop the messages. - err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout); - - if (err == LIBUSB_ERROR_TIMEOUT) { - LOGW("Transmit buffer full"); - break; - } else if (err != 0 || length != transferred) { - handle_usb_issue(err, __func__); - } - } while(err != 0 && connected); - - return transferred; -} - -int Panda::usb_bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { - int err; - int transferred = 0; - - if (!connected) { - return 0; - } - - std::lock_guard lk(usb_lock); - - do { - err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout); - - if (err == LIBUSB_ERROR_TIMEOUT) { - break; // timeout is okay to exit, recv still happened - } else if (err == LIBUSB_ERROR_OVERFLOW) { - comms_healthy = false; - LOGE_100("overflow got 0x%x", transferred); - } else if (err != 0) { - handle_usb_issue(err, __func__); - } - - } while(err != 0 && connected); - - return transferred; + return PandaUsbHandle::list(); } void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param) { - usb_write(0xdc, (uint16_t)safety_model, safety_param); + handle->control_write(0xdc, (uint16_t)safety_model, safety_param); } void Panda::set_alternative_experience(uint16_t alternative_experience) { - usb_write(0xdf, alternative_experience, 0); + handle->control_write(0xdf, alternative_experience, 0); } cereal::PandaState::PandaType Panda::get_hw_type() { unsigned char hw_query[1] = {0}; - usb_read(0xc1, 0, 0, hw_query, 1); + handle->control_read(0xc1, 0, 0, hw_query, 1); return (cereal::PandaState::PandaType)(hw_query[0]); } void Panda::set_rtc(struct tm sys_time) { // tm struct has year defined as years since 1900 - usb_write(0xa1, (uint16_t)(1900 + sys_time.tm_year), 0); - usb_write(0xa2, (uint16_t)(1 + sys_time.tm_mon), 0); - usb_write(0xa3, (uint16_t)sys_time.tm_mday, 0); - // usb_write(0xa4, (uint16_t)(1 + sys_time.tm_wday), 0); - usb_write(0xa5, (uint16_t)sys_time.tm_hour, 0); - usb_write(0xa6, (uint16_t)sys_time.tm_min, 0); - usb_write(0xa7, (uint16_t)sys_time.tm_sec, 0); + handle->control_write(0xa1, (uint16_t)(1900 + sys_time.tm_year), 0); + handle->control_write(0xa2, (uint16_t)(1 + sys_time.tm_mon), 0); + handle->control_write(0xa3, (uint16_t)sys_time.tm_mday, 0); + // handle->control_write(0xa4, (uint16_t)(1 + sys_time.tm_wday), 0); + handle->control_write(0xa5, (uint16_t)sys_time.tm_hour, 0); + handle->control_write(0xa6, (uint16_t)sys_time.tm_min, 0); + handle->control_write(0xa7, (uint16_t)sys_time.tm_sec, 0); } struct tm Panda::get_rtc() { @@ -284,7 +74,7 @@ struct tm Panda::get_rtc() { uint8_t second; } rtc_time = {0}; - usb_read(0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time)); + handle->control_read(0xa0, 0, 0, (unsigned char*)&rtc_time, sizeof(rtc_time)); struct tm new_time = { 0 }; new_time.tm_year = rtc_time.year - 1900; // tm struct has year defined as years since 1900 @@ -298,70 +88,70 @@ struct tm Panda::get_rtc() { } void Panda::set_fan_speed(uint16_t fan_speed) { - usb_write(0xb1, fan_speed, 0); + handle->control_write(0xb1, fan_speed, 0); } uint16_t Panda::get_fan_speed() { uint16_t fan_speed_rpm = 0; - usb_read(0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm)); + handle->control_read(0xb2, 0, 0, (unsigned char*)&fan_speed_rpm, sizeof(fan_speed_rpm)); return fan_speed_rpm; } void Panda::set_ir_pwr(uint16_t ir_pwr) { - usb_write(0xb0, ir_pwr, 0); + handle->control_write(0xb0, ir_pwr, 0); } std::optional Panda::get_state() { health_t health {0}; - int err = usb_read(0xd2, 0, 0, (unsigned char*)&health, sizeof(health)); + int err = handle->control_read(0xd2, 0, 0, (unsigned char*)&health, sizeof(health)); return err >= 0 ? std::make_optional(health) : std::nullopt; } std::optional Panda::get_can_state(uint16_t can_number) { can_health_t can_health {0}; - int err = usb_read(0xc2, can_number, 0, (unsigned char*)&can_health, sizeof(can_health)); + int err = handle->control_read(0xc2, can_number, 0, (unsigned char*)&can_health, sizeof(can_health)); return err >= 0 ? std::make_optional(can_health) : std::nullopt; } void Panda::set_loopback(bool loopback) { - usb_write(0xe5, loopback, 0); + handle->control_write(0xe5, loopback, 0); } std::optional> Panda::get_firmware_version() { std::vector fw_sig_buf(128); - int read_1 = usb_read(0xd3, 0, 0, &fw_sig_buf[0], 64); - int read_2 = usb_read(0xd4, 0, 0, &fw_sig_buf[64], 64); + int read_1 = handle->control_read(0xd3, 0, 0, &fw_sig_buf[0], 64); + int read_2 = handle->control_read(0xd4, 0, 0, &fw_sig_buf[64], 64); return ((read_1 == 64) && (read_2 == 64)) ? std::make_optional(fw_sig_buf) : std::nullopt; } std::optional Panda::get_serial() { char serial_buf[17] = {'\0'}; - int err = usb_read(0xd0, 0, 0, (uint8_t*)serial_buf, 16); + int err = handle->control_read(0xd0, 0, 0, (uint8_t*)serial_buf, 16); return err >= 0 ? std::make_optional(serial_buf) : std::nullopt; } void Panda::set_power_saving(bool power_saving) { - usb_write(0xe7, power_saving, 0); + handle->control_write(0xe7, power_saving, 0); } void Panda::enable_deepsleep() { - usb_write(0xfb, 0, 0); + handle->control_write(0xfb, 0, 0); } void Panda::send_heartbeat(bool engaged) { - usb_write(0xf3, engaged, 0); + handle->control_write(0xf3, engaged, 0); } void Panda::set_can_speed_kbps(uint16_t bus, uint16_t speed) { - usb_write(0xde, bus, (speed * 10)); + handle->control_write(0xde, bus, (speed * 10)); } void Panda::set_data_speed_kbps(uint16_t bus, uint16_t speed) { - usb_write(0xf9, bus, (speed * 10)); + handle->control_write(0xf9, bus, (speed * 10)); } void Panda::set_canfd_non_iso(uint16_t bus, bool non_iso) { - usb_write(0xfc, bus, non_iso); + handle->control_write(0xfc, bus, non_iso); } static uint8_t len_to_dlc(uint8_t len) { @@ -422,14 +212,14 @@ void Panda::pack_can_buffer(const capnp::List::Reader &can_data void Panda::can_send(capnp::List::Reader can_data_list) { pack_can_buffer(can_data_list, [=](uint8_t* data, size_t size) { - usb_bulk_write(3, data, size, 5); + handle->bulk_write(3, data, size, 5); }); } bool Panda::can_receive(std::vector& out_vec) { uint8_t data[RECV_SIZE]; - int recv = usb_bulk_read(0x81, (uint8_t*)data, RECV_SIZE); - if (!comms_healthy) { + int recv = handle->bulk_read(0x81, (uint8_t*)data, RECV_SIZE); + if (!comms_healthy()) { return false; } if (recv == RECV_SIZE) { @@ -444,7 +234,7 @@ bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &o for (int i = 0; i < size; i += USBPACKET_MAX_SIZE) { if (data[i] != i / USBPACKET_MAX_SIZE) { LOGE("CAN: MALFORMED USB RECV PACKET"); - comms_healthy = false; + handle->comms_healthy = false; return false; } int chunk_len = std::min(USBPACKET_MAX_SIZE, (size - i)); diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index c7a0e7a6c1..5b3cbb9a3e 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -1,26 +1,26 @@ #pragma once -#include #include #include #include #include -#include +#include #include #include -#include - #include "cereal/gen/cpp/car.capnp.h" #include "cereal/gen/cpp/log.capnp.h" #include "panda/board/health.h" +#include "selfdrive/boardd/panda_comms.h" + -#define TIMEOUT 0 #define PANDA_CAN_CNT 3 #define PANDA_BUS_CNT 4 -#define RECV_SIZE (0x4000U) + #define USB_TX_SOFT_LIMIT (0x100U) #define USBPACKET_MAX_SIZE (0x40) + +#define RECV_SIZE (0x4000U) #define CANPACKET_HEAD_SIZE 5U #define CANPACKET_MAX_SIZE 72U #define CANPACKET_REJECTED (0xC0U) @@ -37,41 +37,32 @@ struct __attribute__((packed)) can_header { }; struct can_frame { - long address; - std::string dat; - long busTime; - long src; + long address; + std::string dat; + long busTime; + long src; }; + class Panda { - private: - libusb_context *ctx = NULL; - libusb_device_handle *dev_handle = NULL; - std::mutex usb_lock; +private: + std::unique_ptr handle; std::vector recv_buf; - void handle_usb_issue(int err, const char func[]); - void cleanup(); - public: +public: Panda(std::string serial="", uint32_t bus_offset=0); - ~Panda(); - std::string usb_serial; - std::atomic connected = true; - std::atomic comms_healthy = true; + std::string hw_serial; cereal::PandaState::PandaType hw_type = cereal::PandaState::PandaType::UNKNOWN; bool has_rtc = false; const uint32_t bus_offset; + bool connected(); + bool comms_healthy(); + // Static functions static std::vector list(); - // HW communication - int usb_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout=TIMEOUT); - int usb_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout=TIMEOUT); - int usb_bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); - int usb_bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); - // Panda functionality cereal::PandaState::PandaType get_hw_type(); void set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param=0U); diff --git a/selfdrive/boardd/panda_comms.cc b/selfdrive/boardd/panda_comms.cc new file mode 100644 index 0000000000..e73cb69318 --- /dev/null +++ b/selfdrive/boardd/panda_comms.cc @@ -0,0 +1,232 @@ +#include "selfdrive/boardd/panda.h" + +#include +#include + +#include "common/swaglog.h" + +static int init_usb_ctx(libusb_context **context) { + assert(context != nullptr); + + int err = libusb_init(context); + if (err != 0) { + LOGE("libusb initialization error"); + return err; + } + +#if LIBUSB_API_VERSION >= 0x01000106 + libusb_set_option(*context, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); +#else + libusb_set_debug(*context, 3); +#endif + + return err; +} + +PandaUsbHandle::PandaUsbHandle(std::string serial) : PandaCommsHandle(serial) { + // init libusb + ssize_t num_devices; + libusb_device **dev_list = NULL; + int err = init_usb_ctx(&ctx); + if (err != 0) { goto fail; } + + // connect by serial + num_devices = libusb_get_device_list(ctx, &dev_list); + if (num_devices < 0) { goto fail; } + for (size_t i = 0; i < num_devices; ++i) { + libusb_device_descriptor desc; + libusb_get_device_descriptor(dev_list[i], &desc); + if (desc.idVendor == 0xbbaa && desc.idProduct == 0xddcc) { + int ret = libusb_open(dev_list[i], &dev_handle); + if (dev_handle == NULL || ret < 0) { goto fail; } + + unsigned char desc_serial[26] = { 0 }; + ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, desc_serial, std::size(desc_serial)); + if (ret < 0) { goto fail; } + + auto hw_serial = std::string((char *)desc_serial, ret); + if (serial.empty() || serial == hw_serial) { + break; + } + libusb_close(dev_handle); + dev_handle = NULL; + } + } + if (dev_handle == NULL) goto fail; + libusb_free_device_list(dev_list, 1); + dev_list = nullptr; + + if (libusb_kernel_driver_active(dev_handle, 0) == 1) { + libusb_detach_kernel_driver(dev_handle, 0); + } + + err = libusb_set_configuration(dev_handle, 1); + if (err != 0) { goto fail; } + + err = libusb_claim_interface(dev_handle, 0); + if (err != 0) { goto fail; } + + return; + +fail: + if (dev_list != NULL) { + libusb_free_device_list(dev_list, 1); + } + cleanup(); + throw std::runtime_error("Error connecting to panda"); +} + +PandaUsbHandle::~PandaUsbHandle() { + std::lock_guard lk(hw_lock); + cleanup(); + connected = false; +} + +void PandaUsbHandle::cleanup() { + if (dev_handle) { + libusb_release_interface(dev_handle, 0); + libusb_close(dev_handle); + } + + if (ctx) { + libusb_exit(ctx); + } +} + +std::vector PandaUsbHandle::list() { + // init libusb + ssize_t num_devices; + libusb_context *context = NULL; + libusb_device **dev_list = NULL; + std::vector serials; + + int err = init_usb_ctx(&context); + if (err != 0) { return serials; } + + num_devices = libusb_get_device_list(context, &dev_list); + if (num_devices < 0) { + LOGE("libusb can't get device list"); + goto finish; + } + for (size_t i = 0; i < num_devices; ++i) { + libusb_device *device = dev_list[i]; + libusb_device_descriptor desc; + libusb_get_device_descriptor(device, &desc); + if (desc.idVendor == 0xbbaa && desc.idProduct == 0xddcc) { + libusb_device_handle *handle = NULL; + int ret = libusb_open(device, &handle); + if (ret < 0) { goto finish; } + + unsigned char desc_serial[26] = { 0 }; + ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, desc_serial, std::size(desc_serial)); + libusb_close(handle); + if (ret < 0) { goto finish; } + + serials.push_back(std::string((char *)desc_serial, ret).c_str()); + } + } + +finish: + if (dev_list != NULL) { + libusb_free_device_list(dev_list, 1); + } + if (context) { + libusb_exit(context); + } + return serials; +} + +void PandaUsbHandle::handle_usb_issue(int err, const char func[]) { + LOGE_100("usb error %d \"%s\" in %s", err, libusb_strerror((enum libusb_error)err), func); + if (err == LIBUSB_ERROR_NO_DEVICE) { + LOGE("lost connection"); + connected = false; + } + // TODO: check other errors, is simply retrying okay? +} + +int PandaUsbHandle::control_write(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout) { + int err; + const uint8_t bmRequestType = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE; + + if (!connected) { + return LIBUSB_ERROR_NO_DEVICE; + } + + std::lock_guard lk(hw_lock); + do { + err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, NULL, 0, timeout); + if (err < 0) handle_usb_issue(err, __func__); + } while (err < 0 && connected); + + return err; +} + +int PandaUsbHandle::control_read(uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) { + int err; + const uint8_t bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE; + + if (!connected) { + return LIBUSB_ERROR_NO_DEVICE; + } + + std::lock_guard lk(hw_lock); + do { + err = libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout); + if (err < 0) handle_usb_issue(err, __func__); + } while (err < 0 && connected); + + return err; +} + +int PandaUsbHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + int err; + int transferred = 0; + + if (!connected) { + return 0; + } + + std::lock_guard lk(hw_lock); + do { + // Try sending can messages. If the receive buffer on the panda is full it will NAK + // and libusb will try again. After 5ms, it will time out. We will drop the messages. + err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout); + + if (err == LIBUSB_ERROR_TIMEOUT) { + LOGW("Transmit buffer full"); + break; + } else if (err != 0 || length != transferred) { + handle_usb_issue(err, __func__); + } + } while(err != 0 && connected); + + return transferred; +} + +int PandaUsbHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + int err; + int transferred = 0; + + if (!connected) { + return 0; + } + + std::lock_guard lk(hw_lock); + + do { + err = libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, timeout); + + if (err == LIBUSB_ERROR_TIMEOUT) { + break; // timeout is okay to exit, recv still happened + } else if (err == LIBUSB_ERROR_OVERFLOW) { + comms_healthy = false; + LOGE_100("overflow got 0x%x", transferred); + } else if (err != 0) { + handle_usb_issue(err, __func__); + } + + } while(err != 0 && connected); + + return transferred; +} diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h new file mode 100644 index 0000000000..c5143b16b3 --- /dev/null +++ b/selfdrive/boardd/panda_comms.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#define TIMEOUT 0 + + +// comms base class +class PandaCommsHandle { +public: + PandaCommsHandle(std::string serial) {}; + virtual ~PandaCommsHandle() {}; + virtual void cleanup() = 0; + + std::atomic connected = true; + std::atomic comms_healthy = true; + static std::vector list(); + + // HW communication + virtual int control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout=TIMEOUT) = 0; + virtual int control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout=TIMEOUT) = 0; + virtual int bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; + virtual int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; + +protected: + std::mutex hw_lock; +}; + +class PandaUsbHandle : public PandaCommsHandle { +public: + PandaUsbHandle(std::string serial); + ~PandaUsbHandle(); + int control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout=TIMEOUT); + int control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout=TIMEOUT); + int bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); + int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); + void cleanup(); + + static std::vector list(); + +private: + libusb_context *ctx = NULL; + libusb_device_handle *dev_handle = NULL; + std::vector recv_buf; + void handle_usb_issue(int err, const char func[]); +}; From fa4a36800534ede59850f1d9be1cdd6f023d4707 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 5 Nov 2022 00:44:06 +0100 Subject: [PATCH 0189/1179] CI: add OX0C310 camerad box (#26318) * update jenkins file * . * revert * Update Jenkinsfile Co-authored-by: Adeeb Shihadeh Co-authored-by: Kurt Nistelberger Co-authored-by: Adeeb Shihadeh --- Jenkinsfile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ea62ff3c49..0d624954ea 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -137,10 +137,21 @@ pipeline { } } - stage('camerad') { + stage('camerad-ar') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { - phone_steps("tici-party", [ + phone_steps("tici-ar0321", [ + ["build", "cd selfdrive/manager && ./build.py"], + ["test camerad", "python system/camerad/test/test_camerad.py"], + ["test exposure", "python system/camerad/test/test_exposure.py"], + ]) + } + } + + stage('camerad-ox') { + agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } + steps { + phone_steps("tici-ox03c10", [ ["build", "cd selfdrive/manager && ./build.py"], ["test camerad", "python system/camerad/test/test_camerad.py"], ["test exposure", "python system/camerad/test/test_exposure.py"], From 1db915ec1f2a426782b90ab4a2e68c5d31d80a3e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 4 Nov 2022 17:03:41 -0700 Subject: [PATCH 0190/1179] Hyundai CAN-FD: remove check on unused msg (#26368) remove check on unused msg --- selfdrive/car/hyundai/carstate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 3cce581868..8ce6aada6b 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -443,7 +443,6 @@ class CarState(CarStateBase): checks = [ ("WHEEL_SPEEDS", 100), ("GEAR_SHIFTER", 100), - ("BRAKE", 100), ("STEERING_SENSORS", 100), ("MDPS", 100), ("TCS", 50), From b22fc70f52f3a9b62c718011819126abd7552f9c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 4 Nov 2022 17:06:34 -0700 Subject: [PATCH 0191/1179] Hyundai CAN-FD: support ICE alt gears (#26367) * Hyundai: Car Port for Santa Cruz 2022 * bump opendbc * New struct and params for CAN-FD ICE models * fixup! New struct and params for CAN-FD ICE models * bump panda * bump panda * HKG: Car Port for Sportage 2023 * fixup! HKG: Car Port for Sportage 2023 * Kia Sportage 2023: Add FW versions * Longitudinal Control: ICE CAN-FD models * fixup! Longitudinal Control: ICE CAN-FD models * bump panda * fixup! Longitudinal Control: ICE CAN-FD models * Update car info * fixup! Longitudinal Control: ICE CAN-FD models * Gate radar disable behind HDA2 only * Gate radar disable behind camera SCC cars * Update CARS.md * Add FW versions for Santa Cruz 2021 * Test route for Kia Sportage 2023 (openpilot longitudinal enabled) * Test route for Santa Cruz 2021 (openpilot longitudinal enabled) * fixup! Kia Sportage 2023: Add FW versions * HKG: Car Port for Genesis GV70 2023 thanks to @zunichky! Co-authored-by: kyle zunich * Update car info * Add torque param for GENESIS GV70 1ST GEN * Fix CARS.md * Update test route * Remove unnecessary HDA2 checks * Add additional FW versions for Sportage 2023 * Fix Kia Sportage supported MY * Fix MISRA violation * Fix release note * Use IntFlag to gate camera SCC for CAN-FD * Parse 0x1A0 on bus 4 dynamically * bump panda * Car code cleanup * Typo * Add additional 0x1A0 signals to bus 4 * Fix weird bitwise logic * Check 0x1a0 after safety config is set * Revert "Check 0x1a0 after safety config is set" This reverts commit 141bbf79792bcde9cfadbc0680654acf61d8d16f. * Check car list instead * Add GV70 2022 test route * Add fwdRadar FW version for GV70 2022 * Fix CARS.md * Fix CARS.md * Fix CARS.md * new santa cruz route * bump panda to commaai/panda#1031 * bumppanda * some clean up * lets refactor CAMERA_SCC_CAR in another pr * minor clean up * revert car stuff * revert panda * revvy * revvy * it's all ice * revert * revert Co-authored-by: Jason Wen Co-authored-by: kyle zunich Co-authored-by: Adeeb Shihadeh Co-authored-by: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> --- selfdrive/car/hyundai/carstate.py | 10 ++++++---- selfdrive/car/hyundai/interface.py | 3 +++ selfdrive/car/hyundai/values.py | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 8ce6aada6b..e83b83f432 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -21,8 +21,9 @@ class CarState(CarStateBase): self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES) self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES) + self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else "GEAR_SHIFTER" if CP.carFingerprint in CANFD_CAR: - self.shifter_values = can_define.dv["GEAR_SHIFTER"]["GEAR"] + self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"] elif self.CP.carFingerprint in FEATURES["use_cluster_gears"]: self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"] elif self.CP.carFingerprint in FEATURES["use_tcu_gears"]: @@ -164,7 +165,7 @@ class CarState(CarStateBase): ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1 ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT_LATCHED"] == 0 - gear = cp.vl["GEAR_SHIFTER"]["GEAR"] + gear = cp.vl[self.gear_msg_canfd]["GEAR"] ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear)) # TODO: figure out positions @@ -411,13 +412,14 @@ class CarState(CarStateBase): def get_can_parser_canfd(CP): cruise_btn_msg = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" + gear_msg = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else "GEAR_SHIFTER" signals = [ ("WHEEL_SPEED_1", "WHEEL_SPEEDS"), ("WHEEL_SPEED_2", "WHEEL_SPEEDS"), ("WHEEL_SPEED_3", "WHEEL_SPEEDS"), ("WHEEL_SPEED_4", "WHEEL_SPEEDS"), - ("GEAR", "GEAR_SHIFTER"), + ("GEAR", gear_msg), ("STEERING_RATE", "STEERING_SENSORS"), ("STEERING_ANGLE", "STEERING_SENSORS"), @@ -442,7 +444,7 @@ class CarState(CarStateBase): checks = [ ("WHEEL_SPEEDS", 100), - ("GEAR_SHIFTER", 100), + (gear_msg, 100), ("STEERING_SENSORS", 100), ("MDPS", 100), ("TCS", 50), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 4b4d51f3f1..7587cfe146 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -41,6 +41,9 @@ class CarInterface(CarInterfaceBase): # non-HDA2 if 0x1cf not in fingerprint[4]: ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value + # ICE cars do not have 0x130; GEARS message on 0x40 instead + if 0x130 not in fingerprint[4]: + ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value ret.steerActuatorDelay = 0.1 # Default delay ret.steerLimitTimer = 0.4 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 0df9850d0b..5940036aac 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -47,6 +47,7 @@ class CarControllerParams: class HyundaiFlags(IntFlag): CANFD_HDA2 = 1 CANFD_ALT_BUTTONS = 2 + CANFD_ALT_GEARS = 4 class CAR: From e78280da12c799ca7b5e391c53421607a5df617c Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 4 Nov 2022 17:27:58 -0700 Subject: [PATCH 0192/1179] ui: set dialog confirm button text (#26365) * ui: set dialog confirm button text * short * blue confirm --- selfdrive/ui/qt/offroad/networking.cc | 2 +- selfdrive/ui/qt/offroad/settings.cc | 8 ++++---- selfdrive/ui/qt/offroad/software_settings.cc | 2 +- selfdrive/ui/qt/widgets/input.cc | 11 ++++++++--- selfdrive/ui/qt/widgets/input.h | 2 +- selfdrive/ui/translations/main_ja.ts | 16 ++++++++++++++++ selfdrive/ui/translations/main_ko.ts | 16 ++++++++++++++++ selfdrive/ui/translations/main_pt-BR.ts | 16 ++++++++++++++++ selfdrive/ui/translations/main_zh-CHS.ts | 16 ++++++++++++++++ selfdrive/ui/translations/main_zh-CHT.ts | 16 ++++++++++++++++ 10 files changed, 95 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index 13697adfb5..d69d67edeb 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -314,7 +314,7 @@ void WifiUI::refresh() { QPushButton *forgetBtn = new QPushButton(tr("FORGET")); forgetBtn->setObjectName("forgetBtn"); QObject::connect(forgetBtn, &QPushButton::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Forget Wi-Fi Network \"%1\"?").arg(QString::fromUtf8(network.ssid)), this)) { + if (ConfirmationDialog::confirm(tr("Forget Wi-Fi Network \"%1\"?").arg(QString::fromUtf8(network.ssid)), tr("Forget"), this)) { wifi->forgetConnection(network.ssid); } }); diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index b154447eb8..51b5ce6bd7 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -169,7 +169,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { auto resetCalibBtn = new ButtonControl(tr("Reset Calibration"), tr("RESET"), ""); connect(resetCalibBtn, &ButtonControl::showDescriptionEvent, this, &DevicePanel::updateCalibDescription); connect(resetCalibBtn, &ButtonControl::clicked, [&]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), this)) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reset calibration?"), tr("Reset"), this)) { params.remove("CalibrationParams"); } }); @@ -178,7 +178,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { if (!params.getBool("Passive")) { auto retrainingBtn = new ButtonControl(tr("Review Training Guide"), tr("REVIEW"), tr("Review the rules, features, and limitations of openpilot")); connect(retrainingBtn, &ButtonControl::clicked, [=]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), this)) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) { emit reviewTrainingGuide(); } }); @@ -266,7 +266,7 @@ void DevicePanel::updateCalibDescription() { void DevicePanel::reboot() { if (!uiState()->engaged()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reboot?"), this)) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reboot?"), tr("Reboot"), this)) { // Check engaged again in case it changed while the dialog was open if (!uiState()->engaged()) { Params().putBool("DoReboot", true); @@ -279,7 +279,7 @@ void DevicePanel::reboot() { void DevicePanel::poweroff() { if (!uiState()->engaged()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), this)) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), tr("Power Off"), this)) { // Check engaged again in case it changed while the dialog was open if (!uiState()->engaged()) { Params().putBool("DoShutdown", true); diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index e08a02a4d6..12d62e63fb 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -77,7 +77,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { // uninstall button auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL")); connect(uninstallBtn, &ButtonControl::clicked, [&]() { - if (ConfirmationDialog::confirm(tr("Are you sure you want to uninstall?"), this)) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to uninstall?"), tr("Uninstall"), this)) { params.putBool("DoUninstall", true); } }); diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index 897e4b5a05..75453e1b90 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -185,7 +185,11 @@ void InputDialog::setMinLength(int length) { ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, const bool rich, QWidget *parent) : QDialogBase(parent) { QFrame *container = new QFrame(this); - container->setStyleSheet("QFrame { background-color: #1B1B1B; color: #C9C9C9; }"); + container->setStyleSheet(R"( + QFrame { background-color: #1B1B1B; color: #C9C9C9; } + #confirm_btn { background-color: #465BEA; } + #confirm_btn:pressed { background-color: #3049F4; } + )"); QVBoxLayout *main_layout = new QVBoxLayout(container); main_layout->setContentsMargins(32, rich ? 32 : 120, 32, 32); @@ -208,6 +212,7 @@ ConfirmationDialog::ConfirmationDialog(const QString &prompt_text, const QString if (confirm_text.length()) { QPushButton* confirm_btn = new QPushButton(confirm_text); + confirm_btn->setObjectName("confirm_btn"); btn_layout->addWidget(confirm_btn); QObject::connect(confirm_btn, &QPushButton::clicked, this, &ConfirmationDialog::accept); } @@ -223,8 +228,8 @@ bool ConfirmationDialog::alert(const QString &prompt_text, QWidget *parent) { return d.exec(); } -bool ConfirmationDialog::confirm(const QString &prompt_text, QWidget *parent) { - ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Ok"), tr("Cancel"), false, parent); +bool ConfirmationDialog::confirm(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Cancel"), false, parent); return d.exec(); } diff --git a/selfdrive/ui/qt/widgets/input.h b/selfdrive/ui/qt/widgets/input.h index 117e6ca05e..e6c0fba86d 100644 --- a/selfdrive/ui/qt/widgets/input.h +++ b/selfdrive/ui/qt/widgets/input.h @@ -57,7 +57,7 @@ public: explicit ConfirmationDialog(const QString &prompt_text, const QString &confirm_text, const QString &cancel_text, const bool rich, QWidget* parent); static bool alert(const QString &prompt_text, QWidget *parent); - static bool confirm(const QString &prompt_text, QWidget *parent); + static bool confirm(const QString &prompt_text, const QString &confirm_text, QWidget *parent); static bool rich(const QString &prompt_text, QWidget *parent); }; diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index d3c55b5be4..5ee2d86756 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -238,6 +238,14 @@ Disengage to Power Off openpilot をキャンセルしてシャットダウンができます + + Reset + + + + Review + + DriveStats @@ -854,6 +862,10 @@ location set CHECK 確認
+ + Uninstall + +
SshControl @@ -1056,5 +1068,9 @@ location set Forget Wi-Fi Network "%1"? Wi-Fiネットワーク%1を削除してもよろしいですか?
+ + Forget + +
diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 4112087f72..397b43f545 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -238,6 +238,14 @@ Disengage to Power Off 전원을 종료하려면 해제하세요 + + Reset + + + + Review + +
DriveStats @@ -854,6 +862,10 @@ location set CHECK 확인 + + Uninstall + + SshControl @@ -1056,5 +1068,9 @@ location set Forget Wi-Fi Network "%1"? wifi 네트워크 저장안함 "%1"? + + Forget + + diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index ab1946e6af..6774555b73 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -238,6 +238,14 @@ Disengage to Power Off Desacione para Desligar + + Reset + + + + Review + +
DriveStats @@ -858,6 +866,10 @@ trabalho definido CHECK VERIFICAR + + Uninstall + + SshControl @@ -1060,5 +1072,9 @@ trabalho definido Forget Wi-Fi Network "%1"? Esquecer Rede Wi-Fi "%1"? + + Forget + + diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 2baae98669..6189a235e8 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -238,6 +238,14 @@ Disengage to Power Off 取消openpilot以关机 + + Reset + + + + Review + +
DriveStats @@ -852,6 +860,10 @@ location set CHECK 查看 + + Uninstall + + SshControl @@ -1054,5 +1066,9 @@ location set Forget Wi-Fi Network "%1"? 忘记WiFi网络 "%1"? + + Forget + + diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 44c231311a..0b0dbe4ae5 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -238,6 +238,14 @@ Disengage to Power Off 請先取消控車才能關機 + + Reset + + + + Review + +
DriveStats @@ -854,6 +862,10 @@ location set CHECK 檢查 + + Uninstall + + SshControl @@ -1056,5 +1068,9 @@ location set Forget Wi-Fi Network "%1"? 清除 Wi-Fi 網路 "%1"? + + Forget + + From e4342b5e169127cc17c659665e038b22eb995f23 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 4 Nov 2022 21:44:38 -0400 Subject: [PATCH 0193/1179] Hyundai CAN-FD: support 2023 Kia Sportage & 2022 Hyundai Santa Cruz (#25434) * Hyundai: Car Port for Santa Cruz 2022 * bump opendbc * New struct and params for CAN-FD ICE models * fixup! New struct and params for CAN-FD ICE models * bump panda * bump panda * HKG: Car Port for Sportage 2023 * fixup! HKG: Car Port for Sportage 2023 * Kia Sportage 2023: Add FW versions * Longitudinal Control: ICE CAN-FD models * fixup! Longitudinal Control: ICE CAN-FD models * bump panda * fixup! Longitudinal Control: ICE CAN-FD models * Update car info * fixup! Longitudinal Control: ICE CAN-FD models * Gate radar disable behind HDA2 only * Gate radar disable behind camera SCC cars * Update CARS.md * Add FW versions for Santa Cruz 2021 * Test route for Kia Sportage 2023 (openpilot longitudinal enabled) * Test route for Santa Cruz 2021 (openpilot longitudinal enabled) * fixup! Kia Sportage 2023: Add FW versions * HKG: Car Port for Genesis GV70 2023 thanks to @zunichky! Co-authored-by: kyle zunich * Update car info * Add torque param for GENESIS GV70 1ST GEN * Fix CARS.md * Update test route * Remove unnecessary HDA2 checks * Add additional FW versions for Sportage 2023 * Fix Kia Sportage supported MY * Fix MISRA violation * Fix release note * Use IntFlag to gate camera SCC for CAN-FD * Parse 0x1A0 on bus 4 dynamically * bump panda * Car code cleanup * Typo * Add additional 0x1A0 signals to bus 4 * Fix weird bitwise logic * Check 0x1a0 after safety config is set * Revert "Check 0x1a0 after safety config is set" This reverts commit 141bbf79792bcde9cfadbc0680654acf61d8d16f. * Check car list instead * Add GV70 2022 test route * Add fwdRadar FW version for GV70 2022 * Fix CARS.md * Fix CARS.md * Fix CARS.md * new santa cruz route * bump panda to commaai/panda#1031 * bumppanda * some clean up * lets refactor CAMERA_SCC_CAR in another pr * minor clean up * update docs! * GV70 is a radar-SCC car :( (another PR) * fix removed sportage hybrid versions * update docs Co-authored-by: kyle zunich Co-authored-by: Adeeb Shihadeh Co-authored-by: sshane --- RELEASES.md | 2 ++ docs/CARS.md | 4 +++- panda | 2 +- selfdrive/car/hyundai/carstate.py | 21 +++++++++++++++----- selfdrive/car/hyundai/interface.py | 8 ++++++++ selfdrive/car/hyundai/values.py | 26 ++++++++++++++++++++++++- selfdrive/car/tests/routes.py | 2 ++ selfdrive/car/torque_data/override.yaml | 2 ++ 8 files changed, 59 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 744168c8fb..83b3ac46f4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -15,6 +15,8 @@ Version 0.8.17 (2022-XX-XX) * Added button to bookmark events while driving; view them later in comma connect * AGNOS 6 * tools: new and improved cabana thanks to deanlee! +* Hyundai Santa Cruz 2021-22 support thanks to sunnyhaibin! +* Kia Sportage 2023 support thanks to sunnyhaibin! * Kia Sportage Hybrid 2023 support thanks to sunnyhaibin! Version 0.8.16 (2022-08-26) diff --git a/docs/CARS.md b/docs/CARS.md index 9d279e918e..c347868968 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 211 Supported Cars +# 213 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -72,6 +72,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I| |Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Hyundai|Santa Cruz 2021-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D| |Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| @@ -102,6 +103,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Kia|Sportage 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Telluride 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| diff --git a/panda b/panda index 0b86dfa5fb..f3fc343262 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 0b86dfa5fbfcb77a127f980f81484aa7558e8c1e +Subproject commit f3fc343262818801f037e9dca1a96ca99d7e64c5 diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index e83b83f432..7cf1515fda 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -155,11 +155,15 @@ class CarState(CarStateBase): def update_canfd(self, cp, cp_cam): ret = car.CarState.new_message() - if self.CP.carFingerprint in EV_CAR: - ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255. - elif self.CP.carFingerprint in HYBRID_CAR: - ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023. - ret.gasPressed = ret.gas > 1e-5 + if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR): + if self.CP.carFingerprint in EV_CAR: + ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255. + else: + ret.gas = cp.vl["ACCELERATOR_ALT"]["ACCELERATOR_PEDAL"] / 1023. + ret.gasPressed = ret.gas > 1e-5 + else: + ret.gasPressed = bool(cp.vl["ACCELERATOR_BRAKE_ALT"]["ACCELERATOR_PEDAL_PRESSED"]) + ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1 ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR_OPEN"] == 1 @@ -487,6 +491,13 @@ class CarState(CarStateBase): checks += [ ("ACCELERATOR_ALT", 100), ] + else: + signals += [ + ("ACCELERATOR_PEDAL_PRESSED", "ACCELERATOR_BRAKE_ALT"), + ] + checks += [ + ("ACCELERATOR_BRAKE_ALT", 100), + ] bus = 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4 return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, bus) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 7587cfe146..6c8d0076f1 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -123,6 +123,10 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.756 ret.steerRatio = 16. tire_stiffness_factor = 0.385 + elif candidate == CAR.SANTA_CRUZ_1ST_GEN: + ret.mass = 1870. + STD_CARGO_KG # weight from Limited trim - the only supported trim + ret.wheelbase = 3.000 + ret.steerRatio = 14.2 # steering ratio according to Hyundai News https://www.hyundainews.com/assets/documents/original/48035-2022SantaCruzProductGuideSpecsv2081521.pdf # Kia elif candidate == CAR.KIA_SORENTO: @@ -141,6 +145,10 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.63 ret.steerRatio = 14.56 tire_stiffness_factor = 1 + elif candidate == CAR.KIA_SPORTAGE_5TH_GEN: + ret.mass = 1700. + STD_CARGO_KG # weight from SX and above trims, average of FWD and AWD versions + ret.wheelbase = 2.756 + ret.steerRatio = 13.6 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sportage/2023/specifications elif candidate in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H): ret.mass = 3558. * CV.LB_TO_KG ret.wheelbase = 2.80 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 5940036aac..536af7cf01 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -78,6 +78,7 @@ class CAR: SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021" IONIQ_5 = "HYUNDAI IONIQ 5 2022" TUCSON_HYBRID_4TH_GEN = "HYUNDAI TUCSON HYBRID 4TH GEN" + SANTA_CRUZ_1ST_GEN = "HYUNDAI SANTA CRUZ 1ST GEN" # Kia KIA_FORTE = "KIA FORTE E 2018 & GT 2021" @@ -89,6 +90,7 @@ class CAR: KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" KIA_SELTOS = "KIA SELTOS 2021" + KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN" KIA_SORENTO = "KIA SORENTO GT LINE 2018" KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN" KIA_STINGER = "KIA STINGER GT2 2018" @@ -147,6 +149,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", harness=Harness.hyundai_q), ], CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), + CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_n), # Kia CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), @@ -169,6 +172,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Optima Hybrid 2019"), ], CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", harness=Harness.hyundai_a), + CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", "Smart Cruise Control (SCC)", harness=Harness.hyundai_n), CAR.KIA_SORENTO: [ HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), @@ -1400,6 +1404,24 @@ FW_VERSIONS = { b'\xf1\x00NQ5__ 1.01 1.03 99110-CH000 ', ], }, + CAR.SANTA_CRUZ_1ST_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW000 14M', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00NX4__ 1.00 1.00 99110-K5000 ', + ], + }, + CAR.KIA_SPORTAGE_5TH_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662', + b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00NQ5__ 1.00 1.02 99110-P1000 ', + b'\xf1\x00NQ5__ 1.00 1.03 99110-P1000 ', + ], + }, } CHECKSUM = { @@ -1417,7 +1439,7 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN} # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } @@ -1474,5 +1496,7 @@ DBC = { CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.IONIQ_5: dbc_dict('hyundai_canfd', None), + CAR.SANTA_CRUZ_1ST_GEN: dbc_dict('hyundai_canfd', None), + CAR.KIA_SPORTAGE_5TH_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index d833203427..bf949d3492 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -82,6 +82,7 @@ routes = [ CarTestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS), CarTestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70), CarTestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80), + CarTestRoute("f0709d2bc6ca451f|2022-10-15--08-13-54", HYUNDAI.SANTA_CRUZ_1ST_GEN), CarTestRoute("4dbd55df87507948|2022-03-01--09-45-38", HYUNDAI.SANTA_FE), CarTestRoute("bf43d9df2b660eb0|2021-09-23--14-16-37", HYUNDAI.SANTA_FE_2022), CarTestRoute("37398f32561a23ad|2021-11-18--00-11-35", HYUNDAI.SANTA_FE_HEV_2022), @@ -117,6 +118,7 @@ routes = [ CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV), CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE), + CarTestRoute("192283cdbb7a58c2|2022-10-15--01-43-18", HYUNDAI.KIA_SPORTAGE_5TH_GEN), CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA), CarTestRoute("734ef96182ddf940|2022-10-02--16-41-44", HYUNDAI.ELANTRA), # 2019 Elantra GT CarTestRoute("82e9cdd3f43bf83e|2021-05-15--02-42-51", HYUNDAI.ELANTRA_2021), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 460b9a9097..c5a316aaaf 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -31,6 +31,8 @@ CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05] VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1] VOLKSWAGEN SHARAN 2ND GEN: [2.5, 2.5, 0.1] HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0] +HYUNDAI SANTA CRUZ 1ST GEN: [2.7, 2.7, 0.0] +KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.0] KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.0] # Dashcam or fallback configured as ideal car From e4cd8a15db6b0e16e06485924395d725ecdc23df Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 5 Nov 2022 04:36:44 +0100 Subject: [PATCH 0194/1179] sensord: lsm self test (#25855) * lsm self test v1 * add lsm6ds3 accel self test * add self test for lsm6ds3 gyro * add c variant self test * code CleanUp * address PR comments Co-authored-by: Kurt Nistelberger --- selfdrive/sensord/sensors/lsm6ds3_accel.cc | 133 +++++++++++++++++++++ selfdrive/sensord/sensors/lsm6ds3_accel.h | 18 ++- selfdrive/sensord/sensors/lsm6ds3_gyro.cc | 115 +++++++++++++++++- selfdrive/sensord/sensors/lsm6ds3_gyro.h | 12 ++ selfdrive/sensord/tests/test_sensord.py | 5 + 5 files changed, 281 insertions(+), 2 deletions(-) diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.cc b/selfdrive/sensord/sensors/lsm6ds3_accel.cc index 27cd4d0c70..c19e3de7ed 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_accel.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_accel.cc @@ -1,17 +1,132 @@ #include "lsm6ds3_accel.h" #include +#include +#include #include "common/swaglog.h" #include "common/timing.h" +#include "common/util.h" LSM6DS3_Accel::LSM6DS3_Accel(I2CBus *bus, int gpio_nr, bool shared_gpio) : I2CSensor(bus, gpio_nr, shared_gpio) {} +void LSM6DS3_Accel::wait_for_data_ready() { + uint8_t drdy = 0; + uint8_t buffer[6]; + + do { + read_register(LSM6DS3_ACCEL_I2C_REG_STAT_REG, &drdy, sizeof(drdy)); + drdy &= LSM6DS3_ACCEL_DRDY_XLDA; + } while (drdy == 0); + + read_register(LSM6DS3_ACCEL_I2C_REG_OUTX_L_XL, buffer, sizeof(buffer)); +} + +void LSM6DS3_Accel::read_and_avg_data(float* out_buf) { + uint8_t drdy = 0; + uint8_t buffer[6]; + + float scaling = 0.061f; + if (source == cereal::SensorEventData::SensorSource::LSM6DS3TRC) { + scaling = 0.122f; + } + + for (int i = 0; i < 5; i++) { + do { + read_register(LSM6DS3_ACCEL_I2C_REG_STAT_REG, &drdy, sizeof(drdy)); + drdy &= LSM6DS3_ACCEL_DRDY_XLDA; + } while (drdy == 0); + + int len = read_register(LSM6DS3_ACCEL_I2C_REG_OUTX_L_XL, buffer, sizeof(buffer)); + assert(len == sizeof(buffer)); + + for (int j = 0; j < 3; j++) { + out_buf[j] += (float)read_16_bit(buffer[j*2], buffer[j*2+1]) * scaling; + } + } + + for (int i = 0; i < 3; i++) { + out_buf[i] /= 5.0f; + } +} + +int LSM6DS3_Accel::self_test(int test_type) { + float val_st_off[3] = {0}; + float val_st_on[3] = {0}; + float test_val[3] = {0}; + uint8_t ODR_FS_MO = LSM6DS3_ACCEL_ODR_52HZ; // full scale: +-2g, ODR: 52Hz + + // prepare sensor for self-test + + // enable block data update and automatic increment + int ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL3_C, LSM6DS3_ACCEL_IF_INC_BDU); + if (ret < 0) { + return ret; + } + + if (source == cereal::SensorEventData::SensorSource::LSM6DS3TRC) { + ODR_FS_MO = LSM6DS3_ACCEL_FS_4G | LSM6DS3_ACCEL_ODR_52HZ; + } + ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL1_XL, ODR_FS_MO); + if (ret < 0) { + return ret; + } + + // wait for stable output, and discard first values + util::sleep_for(100); + wait_for_data_ready(); + read_and_avg_data(val_st_off); + + // enable Self Test positive (or negative) + ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL5_C, test_type); + if (ret < 0) { + return ret; + } + + // wait for stable output, and discard first values + util::sleep_for(100); + wait_for_data_ready(); + read_and_avg_data(val_st_on); + + // disable sensor + ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL1_XL, 0); + if (ret < 0) { + return ret; + } + + // disable self test + ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL5_C, 0); + if (ret < 0) { + return ret; + } + + // calculate the mg values for self test + for (int i = 0; i < 3; i++) { + test_val[i] = fabs(val_st_on[i] - val_st_off[i]); + } + + // verify test result + for (int i = 0; i < 3; i++) { + if ((LSM6DS3_ACCEL_MIN_ST_LIMIT_mg > test_val[i]) || + (test_val[i] > LSM6DS3_ACCEL_MAX_ST_LIMIT_mg)) { + return -1; + } + } + + return ret; +} + int LSM6DS3_Accel::init() { int ret = 0; uint8_t buffer[1]; uint8_t value = 0; + bool do_self_test = false; + + const char* env_lsm_selftest =env_lsm_selftest = std::getenv("LSM_SELF_TEST"); + if (env_lsm_selftest != nullptr && strncmp(env_lsm_selftest, "1", 1) == 0) { + do_self_test = true; + } ret = read_register(LSM6DS3_ACCEL_I2C_REG_ID, buffer, 1); if(ret < 0) { @@ -29,11 +144,29 @@ int LSM6DS3_Accel::init() { source = cereal::SensorEventData::SensorSource::LSM6DS3TRC; } + ret = self_test(LSM6DS3_ACCEL_POSITIVE_TEST); + if (ret < 0) { + LOGE("LSM6DS3 accel positive self-test failed!"); + if (do_self_test) goto fail; + } + + ret = self_test(LSM6DS3_ACCEL_NEGATIVE_TEST); + if (ret < 0) { + LOGE("LSM6DS3 accel negative self-test failed!"); + if (do_self_test) goto fail; + } + ret = init_gpio(); if (ret < 0) { goto fail; } + // enable continuous update, and automatic increase + ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL3_C, LSM6DS3_ACCEL_IF_INC); + if (ret < 0) { + goto fail; + } + // TODO: set scale and bandwidth. Default is +- 2G, 50 Hz ret = set_register(LSM6DS3_ACCEL_I2C_REG_CTRL1_XL, LSM6DS3_ACCEL_ODR_104HZ); if (ret < 0) { diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.h b/selfdrive/sensord/sensors/lsm6ds3_accel.h index 84084fc916..c3f66f5803 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_accel.h +++ b/selfdrive/sensord/sensors/lsm6ds3_accel.h @@ -10,21 +10,37 @@ #define LSM6DS3_ACCEL_I2C_REG_ID 0x0F #define LSM6DS3_ACCEL_I2C_REG_INT1_CTRL 0x0D #define LSM6DS3_ACCEL_I2C_REG_CTRL1_XL 0x10 +#define LSM6DS3_ACCEL_I2C_REG_CTRL3_C 0x12 +#define LSM6DS3_ACCEL_I2C_REG_CTRL5_C 0x14 +#define LSM6DS3_ACCEL_I2C_REG_CTR9_XL 0x18 #define LSM6DS3_ACCEL_I2C_REG_STAT_REG 0x1E #define LSM6DS3_ACCEL_I2C_REG_OUTX_L_XL 0x28 // Constants #define LSM6DS3_ACCEL_CHIP_ID 0x69 #define LSM6DS3TRC_ACCEL_CHIP_ID 0x6A +#define LSM6DS3_ACCEL_FS_4G (0b10 << 2) +#define LSM6DS3_ACCEL_ODR_52HZ (0b0011 << 4) #define LSM6DS3_ACCEL_ODR_104HZ (0b0100 << 4) #define LSM6DS3_ACCEL_INT1_DRDY_XL 0b1 #define LSM6DS3_ACCEL_DRDY_XLDA 0b1 #define LSM6DS3_ACCEL_DRDY_PULSE_MODE (1 << 7) - +#define LSM6DS3_ACCEL_IF_INC 0b00000100 +#define LSM6DS3_ACCEL_IF_INC_BDU 0b01000100 +#define LSM6DS3_ACCEL_XYZ_DEN 0b11100000 +#define LSM6DS3_ACCEL_POSITIVE_TEST 0b01 +#define LSM6DS3_ACCEL_NEGATIVE_TEST 0b10 +#define LSM6DS3_ACCEL_MIN_ST_LIMIT_mg 90.0f +#define LSM6DS3_ACCEL_MAX_ST_LIMIT_mg 1700.0f class LSM6DS3_Accel : public I2CSensor { uint8_t get_device_address() {return LSM6DS3_ACCEL_I2C_ADDR;} cereal::SensorEventData::SensorSource source = cereal::SensorEventData::SensorSource::LSM6DS3; + + // self test functions + int self_test(int test_type); + void wait_for_data_ready(); + void read_and_avg_data(float* val_st_off); public: LSM6DS3_Accel(I2CBus *bus, int gpio_nr = 0, bool shared_gpio = false); int init(); diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc b/selfdrive/sensord/sensors/lsm6ds3_gyro.cc index 014a72bb73..f306be0fe8 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_gyro.cc @@ -2,19 +2,120 @@ #include #include +#include #include "common/swaglog.h" #include "common/timing.h" +#include "common/util.h" #define DEG2RAD(x) ((x) * M_PI / 180.0) LSM6DS3_Gyro::LSM6DS3_Gyro(I2CBus *bus, int gpio_nr, bool shared_gpio) : I2CSensor(bus, gpio_nr, shared_gpio) {} +void LSM6DS3_Gyro::wait_for_data_ready() { + uint8_t drdy = 0; + uint8_t buffer[6]; + + do { + read_register(LSM6DS3_GYRO_I2C_REG_STAT_REG, &drdy, sizeof(drdy)); + drdy &= LSM6DS3_GYRO_DRDY_GDA; + } while (drdy == 0); + + read_register(LSM6DS3_GYRO_I2C_REG_OUTX_L_G, buffer, sizeof(buffer)); +} + +void LSM6DS3_Gyro::read_and_avg_data(float* out_buf) { + uint8_t drdy = 0; + uint8_t buffer[6]; + + for (int i = 0; i < 5; i++) { + do { + read_register(LSM6DS3_GYRO_I2C_REG_STAT_REG, &drdy, sizeof(drdy)); + drdy &= LSM6DS3_GYRO_DRDY_GDA; + } while (drdy == 0); + + int len = read_register(LSM6DS3_GYRO_I2C_REG_OUTX_L_G, buffer, sizeof(buffer)); + assert(len == sizeof(buffer)); + + for (int j = 0; j < 3; j++) { + out_buf[j] += (float)read_16_bit(buffer[j*2], buffer[j*2+1]) * 70.0f; + } + } + + // calculate the mg average values + for (int i = 0; i < 3; i++) { + out_buf[i] /= 5.0f; + } +} + +int LSM6DS3_Gyro::self_test(int test_type) { + float val_st_off[3] = {0}; + float val_st_on[3] = {0}; + float test_val[3] = {0}; + + // prepare sensor for self-test + + // full scale: 2000dps, ODR: 208Hz + int ret = set_register(LSM6DS3_GYRO_I2C_REG_CTRL2_G, LSM6DS3_GYRO_ODR_208HZ | LSM6DS3_GYRO_FS_2000dps); + if (ret < 0) { + return ret; + } + + // wait for stable output, and discard first values + util::sleep_for(150); + wait_for_data_ready(); + read_and_avg_data(val_st_off); + + // enable Self Test positive (or negative) + ret = set_register(LSM6DS3_GYRO_I2C_REG_CTRL5_C, test_type); + if (ret < 0) { + return ret; + } + + // wait for stable output, and discard first values + util::sleep_for(50); + wait_for_data_ready(); + read_and_avg_data(val_st_on); + + // disable sensor + ret = set_register(LSM6DS3_GYRO_I2C_REG_CTRL2_G, 0); + if (ret < 0) { + return ret; + } + + // disable self test + ret = set_register(LSM6DS3_GYRO_I2C_REG_CTRL5_C, 0); + if (ret < 0) { + return ret; + } + + // calculate the mg values for self test + for (int i = 0; i < 3; i++) { + test_val[i] = fabs(val_st_on[i] - val_st_off[i]); + } + + // verify test result + for (int i = 0; i < 3; i++) { + if ((LSM6DS3_GYRO_MIN_ST_LIMIT_mdps > test_val[i]) || + (test_val[i] > LSM6DS3_GYRO_MAX_ST_LIMIT_mdps)) { + return -1; + } + } + + return ret; +} + int LSM6DS3_Gyro::init() { int ret = 0; uint8_t buffer[1]; uint8_t value = 0; + bool do_self_test = false; + + const char* env_lsm_selftest =env_lsm_selftest = std::getenv("LSM_SELF_TEST"); + if (env_lsm_selftest != nullptr && strncmp(env_lsm_selftest, "1", 1) == 0) { + do_self_test = true; + } ret = read_register(LSM6DS3_GYRO_I2C_REG_ID, buffer, 1); if(ret < 0) { @@ -37,6 +138,18 @@ int LSM6DS3_Gyro::init() { goto fail; } + ret = self_test(LSM6DS3_GYRO_POSITIVE_TEST); + if (ret < 0 ) { + LOGE("LSM6DS3 gyro positive self-test failed!"); + if (do_self_test) goto fail; + } + + ret = self_test(LSM6DS3_GYRO_NEGATIVE_TEST); + if (ret < 0) { + LOGE("LSM6DS3 gyro negative self-test failed!"); + if (do_self_test) goto fail; + } + // TODO: set scale. Default is +- 250 deg/s ret = set_register(LSM6DS3_GYRO_I2C_REG_CTRL2_G, LSM6DS3_GYRO_ODR_104HZ); if (ret < 0) { @@ -65,7 +178,7 @@ fail: int LSM6DS3_Gyro::shutdown() { int ret = 0; - // disable data ready interrupt for accel on INT1 + // disable data ready interrupt for gyro on INT1 uint8_t value = 0; ret = read_register(LSM6DS3_GYRO_I2C_REG_INT1_CTRL, &value, 1); if (ret < 0) { diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.h b/selfdrive/sensord/sensors/lsm6ds3_gyro.h index 6c61ffcef2..220e6b0cec 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_gyro.h +++ b/selfdrive/sensord/sensors/lsm6ds3_gyro.h @@ -10,21 +10,33 @@ #define LSM6DS3_GYRO_I2C_REG_ID 0x0F #define LSM6DS3_GYRO_I2C_REG_INT1_CTRL 0x0D #define LSM6DS3_GYRO_I2C_REG_CTRL2_G 0x11 +#define LSM6DS3_GYRO_I2C_REG_CTRL5_C 0x14 #define LSM6DS3_GYRO_I2C_REG_STAT_REG 0x1E #define LSM6DS3_GYRO_I2C_REG_OUTX_L_G 0x22 +#define LSM6DS3_GYRO_POSITIVE_TEST (0b01 << 2) +#define LSM6DS3_GYRO_NEGATIVE_TEST (0b11 << 2) // Constants #define LSM6DS3_GYRO_CHIP_ID 0x69 #define LSM6DS3TRC_GYRO_CHIP_ID 0x6A +#define LSM6DS3_GYRO_FS_2000dps (0b11 << 2) #define LSM6DS3_GYRO_ODR_104HZ (0b0100 << 4) +#define LSM6DS3_GYRO_ODR_208HZ (0b0101 << 4) #define LSM6DS3_GYRO_INT1_DRDY_G 0b10 #define LSM6DS3_GYRO_DRDY_GDA 0b10 #define LSM6DS3_GYRO_DRDY_PULSE_MODE (1 << 7) +#define LSM6DS3_GYRO_MIN_ST_LIMIT_mdps 150000.0f +#define LSM6DS3_GYRO_MAX_ST_LIMIT_mdps 700000.0f class LSM6DS3_Gyro : public I2CSensor { uint8_t get_device_address() {return LSM6DS3_GYRO_I2C_ADDR;} cereal::SensorEventData::SensorSource source = cereal::SensorEventData::SensorSource::LSM6DS3; + + // self test functions + int self_test(int test_type); + void wait_for_data_ready(); + void read_and_avg_data(float* val_st_off); public: LSM6DS3_Gyro(I2CBus *bus, int gpio_nr = 0, bool shared_gpio = false); int init(); diff --git a/selfdrive/sensord/tests/test_sensord.py b/selfdrive/sensord/tests/test_sensord.py index 82bd28446b..c6fe33129a 100755 --- a/selfdrive/sensord/tests/test_sensord.py +++ b/selfdrive/sensord/tests/test_sensord.py @@ -104,6 +104,9 @@ class TestSensord(unittest.TestCase): # make sure gpiochip0 is readable HARDWARE.initialize_hardware() + # enable LSM self test + os.environ["LSM_SELF_TEST"] = "1" + # read initial sensor values every test case can use os.system("pkill -f ./_sensord") try: @@ -118,6 +121,8 @@ class TestSensord(unittest.TestCase): @classmethod def tearDownClass(cls): managed_processes["sensord"].stop() + if "LSM_SELF_TEST" in os.environ: + del os.environ['LSM_SELF_TEST'] def tearDown(self): managed_processes["sensord"].stop() From 0b385a5650c4e0b06eb83e44bdba3fcff117beeb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 4 Nov 2022 21:04:53 -0700 Subject: [PATCH 0195/1179] ui: fade to default path color when inactive (#26375) * fade to default path color when inactive * long! --- selfdrive/ui/qt/onroad.cc | 2 +- selfdrive/ui/ui.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 85b55697be..c4e4beb76a 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -463,7 +463,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { if (scene.end_to_end_long) { const auto &acceleration = (*s->sm)["modelV2"].getModelV2().getAcceleration(); float acceleration_future = 0; - if (acceleration.getZ().size() > 10) { + if (acceleration.getZ().size() > 10 && (*s->sm)["carControl"].getCarControl().getLongActive()) { acceleration_future = acceleration.getX()[10]; // 1.0 second } // speed up: 148, slow down: 0 diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 945218ec11..0198405769 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -214,7 +214,7 @@ void UIState::updateStatus() { UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ - "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", + "modelV2", "carControl", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "gnssMeasurements", }); From e23a25c3ae82e65b8adad47e799c588cc46bba0e Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 4 Nov 2022 21:54:06 -0700 Subject: [PATCH 0196/1179] fix gps test runner --- tools/gpstest/run_unittest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gpstest/run_unittest.sh b/tools/gpstest/run_unittest.sh index 9f93fdfc9a..e0ca017a6d 100755 --- a/tools/gpstest/run_unittest.sh +++ b/tools/gpstest/run_unittest.sh @@ -4,7 +4,7 @@ # run limeGPS with random static location timeout 300 ./simulate_gps_signal.py 32.7518 -117.1962 & -gps_PID=$(ps -aux | grep -m 1 "timeout 300" | cut -d ' ' -f 7) +gps_PID=$(ps -aux | grep -m 1 "timeout 300" | awk '{print $2}') echo "starting limeGPS..." sleep 10 From 50fddb52ba2e816123fa89a802a9e603e7407ada Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Sat, 5 Nov 2022 17:44:18 +0900 Subject: [PATCH 0197/1179] Multilang: kor translation update (#26380) --- selfdrive/ui/translations/main_ko.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 397b43f545..f58c4f34d5 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -240,11 +240,11 @@ Reset - + 리셋 Review - + 다시보기
@@ -475,11 +475,11 @@ location set ParamControl Ok - 확인 + 확인 Cancel - 취소 + 취소 @@ -864,7 +864,7 @@ location set Uninstall - + 삭제 @@ -1070,7 +1070,7 @@ location set Forget - + 저장안함 From 5768af09c06bc5e4774a30e1f94bba32d50721c4 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Sat, 5 Nov 2022 13:24:38 -0700 Subject: [PATCH 0198/1179] DM: lower bound ee calib (#26370) keep in linear region --- selfdrive/monitoring/driver_monitor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index 48163dcf2a..e3f6a5094d 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -34,6 +34,7 @@ class DRIVER_MONITOR_SETTINGS(): self._EE_THRESH11 = 0.275 self._EE_THRESH12 = 5.5 self._EE_MAX_OFFSET1 = 0.06 + self._EE_MIN_OFFSET1 = 0.025 self._EE_THRESH21 = 0.01 self._EE_THRESH22 = 0.35 @@ -206,7 +207,7 @@ class DriverStatus(): distracted_types.append(DistractedType.DISTRACTED_BLINK) if self.ee1_calibrated: - ee1_dist = self.eev1 > min(self.ee1_offseter.filtered_stat.M, self.settings._EE_MAX_OFFSET1) * self.settings._EE_THRESH12 + ee1_dist = self.eev1 > max(min(self.ee1_offseter.filtered_stat.M, self.settings._EE_MAX_OFFSET1), self.settings._EE_MIN_OFFSET1) * self.settings._EE_THRESH12 else: ee1_dist = self.eev1 > self.settings._EE_THRESH11 # if self.ee2_calibrated: From e079751f79c5256b1881cb34d1a92d08faa128d7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 5 Nov 2022 15:05:30 -0700 Subject: [PATCH 0199/1179] ui: revert e2e path changes (#26382) * Revert "ui: fade to default path color when inactive (#26375)" This reverts commit 0b385a5650c4e0b06eb83e44bdba3fcff117beeb. * Revert "ui: minor e2e path tweaks (#26351)" This reverts commit d257e28479f49339e7f79491ff9d67e9ba034dfe. * stronger colors 45 --- selfdrive/ui/qt/onroad.cc | 17 +++++++++-------- selfdrive/ui/qt/onroad.h | 1 - selfdrive/ui/ui.cc | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index c4e4beb76a..bfd2f44561 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -170,7 +170,7 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { } -AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), accel_filter(UI_FREQ, .5, 1. / UI_FREQ), CameraWidget("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}); @@ -463,18 +463,19 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { if (scene.end_to_end_long) { const auto &acceleration = (*s->sm)["modelV2"].getModelV2().getAcceleration(); float acceleration_future = 0; - if (acceleration.getZ().size() > 10 && (*s->sm)["carControl"].getCarControl().getLongActive()) { - acceleration_future = acceleration.getX()[10]; // 1.0 second + if (acceleration.getZ().size() > 16) { + acceleration_future = acceleration.getX()[16]; // 2.5 seconds } - // speed up: 148, slow down: 0 - start_hue = fmax(fmin(60 + accel_filter.update(acceleration_future) * 80, 148), 0); + start_hue = 60; + // speed up: 120, slow down: 0 + end_hue = fmax(fmin(start_hue + acceleration_future * 45, 148), 0); // FIXME: painter.drawPolygon can be slow if hue is not rounded - start_hue = int(start_hue * 100 + 0.5) / 100; + end_hue = int(end_hue * 100 + 0.5) / 100; bg.setColorAt(0.0, QColor::fromHslF(start_hue / 360., 0.97, 0.56, 0.4)); - bg.setColorAt(0.75, QColor::fromHslF(63 / 360., 1.0, 0.68, 0.35)); - bg.setColorAt(1.0, QColor::fromHslF(63 / 360., 1.0, 0.68, 0.0)); + bg.setColorAt(0.5, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.35)); + bg.setColorAt(1.0, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.0)); } else { const auto &orientation = (*s->sm)["modelV2"].getModelV2().getOrientation(); float orientation_future = 0; diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 1f6a49bf8c..7edca6b3d5 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -87,7 +87,6 @@ protected: double prev_draw_t = 0; FirstOrderFilter fps_filter; - FirstOrderFilter accel_filter; }; // container for all onroad widgets diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 0198405769..945218ec11 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -214,7 +214,7 @@ void UIState::updateStatus() { UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ - "modelV2", "carControl", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", + "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "gnssMeasurements", }); From ac76cc93256578f24db255cefd10c013dd906c28 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 6 Nov 2022 07:52:16 +0800 Subject: [PATCH 0200/1179] Cabana: cleanup code (#26369) * remove ChartView::enterEvent * cleanup ChartsWidget::removeAll * group graphics items * remove rubber->setPalette * helper function DBCManager::parseId * remove variable name from dbcManager * fix readme/Usage * use QSlider::setRange * cleanup include * use emplace_back * remove varialbe routeName from CanMessages * remove tmp variable * remove blank line * cleanup layout * clean settings layout * connect to streamStarted * cleanup signal/slot --- tools/cabana/README.md | 2 +- tools/cabana/canmessages.cc | 14 +++------ tools/cabana/canmessages.h | 5 ++-- tools/cabana/chartswidget.cc | 53 +++++++++------------------------- tools/cabana/chartswidget.h | 3 +- tools/cabana/dbcmanager.cc | 20 +++++-------- tools/cabana/dbcmanager.h | 7 ++--- tools/cabana/detailwidget.cc | 8 ++--- tools/cabana/detailwidget.h | 3 -- tools/cabana/mainwin.cc | 3 +- tools/cabana/messageswidget.cc | 2 +- tools/cabana/settings.cc | 7 ++--- tools/cabana/videowidget.cc | 13 +++++---- tools/cabana/videowidget.h | 1 - 14 files changed, 45 insertions(+), 96 deletions(-) diff --git a/tools/cabana/README.md b/tools/cabana/README.md index 99d0d4c9ce..dd131880a6 100644 --- a/tools/cabana/README.md +++ b/tools/cabana/README.md @@ -8,7 +8,7 @@ Cabana is a tool developed to view raw CAN data. One use for this is creating an ```bash $ ./cabana -h -Usage: ./_cabana [options] route +Usage: ./cabana [options] route Options: -h, --help Displays this help. diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 3ffc29916f..f1f5c2cd23 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -1,6 +1,5 @@ #include "tools/cabana/canmessages.h" -#include #include #include "tools/cabana/dbcmanager.h" @@ -9,7 +8,6 @@ CANMessages *can = nullptr; CANMessages::CANMessages(QObject *parent) : QObject(parent) { can = this; - QObject::connect(this, &CANMessages::received, this, &CANMessages::process, Qt::QueuedConnection); QObject::connect(&settings, &Settings::changed, this, &CANMessages::settingChanged); } @@ -24,11 +22,11 @@ static bool event_filter(const Event *e, void *opaque) { } bool CANMessages::loadRoute(const QString &route, const QString &data_dir, bool use_qcam) { - routeName = route; replay = new Replay(route, {"can", "roadEncodeIdx", "carParams"}, {}, nullptr, use_qcam ? REPLAY_FLAG_QCAMERA : 0, data_dir, this); replay->setSegmentCacheLimit(settings.cached_segment_limit); replay->installEventFilter(event_filter, this); QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); + QObject::connect(replay, &Replay::streamStarted, this, &CANMessages::streamStarted); if (replay->load()) { replay->start(); return true; @@ -40,12 +38,9 @@ QList CANMessages::findSignalValues(const QString &id, const Signal *si auto evts = events(); if (!evts) return {}; - auto l = id.split(':'); - int bus = l[0].toInt(); - uint32_t address = l[1].toUInt(nullptr, 16); - QList ret; ret.reserve(max_count); + auto [bus, address] = DBCManager::parseId(id); for (auto &evt : *evts) { if (evt->which != cereal::Event::Which::CAN) continue; @@ -101,10 +96,9 @@ bool CANMessages::eventFilter(const Event *event) { data.bus_time = c.getBusTime(); data.dat.append((char *)c.getDat().begin(), c.getDat().size()); - auto &count = counters[id]; - data.count = ++count; + data.count = ++counters[id]; if (double delta = (current_sec - counters_begin_sec); delta > 0) { - data.freq = count / delta; + data.freq = data.count / delta; } (*new_msgs)[id] = data; } diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 5fbccdbe12..14e2423d01 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -32,7 +32,7 @@ public: QList findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); bool eventFilter(const Event *event); - inline QString route() const { return routeName; } + inline QString route() const { return replay->route()->name(); } inline QString carFingerprint() const { return replay->carFingerprint().c_str(); } inline double totalSeconds() const { return replay->totalSeconds(); } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } @@ -47,6 +47,7 @@ public: inline const std::vector> getTimeline() { return replay->getTimeline(); } signals: + void streamStarted(); void eventsMerged(); void updated(); void received(QHash *); @@ -58,9 +59,7 @@ protected: void process(QHash *); void settingChanged(); - QString routeName; Replay *replay = nullptr; - std::mutex lock; std::atomic counters_begin_sec = 0; QHash counters; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 7540abbcb2..6432cb7079 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -176,16 +176,8 @@ void ChartsWidget::removeChart(ChartWidget *chart) { } void ChartsWidget::removeAll(const Signal *sig) { - QMutableListIterator it(charts); - while (it.hasNext()) { - auto c = it.next(); - if (sig == nullptr || c->signal == sig) { - c->deleteLater(); - emit chartClosed(c->id, c->signal); - it.remove(); - } - } - updateTitleBar(); + for (auto c : charts.toVector()) + if (!sig || c->signal == sig) removeChart(c); } void ChartsWidget::signalUpdated(const Signal *sig) { @@ -267,26 +259,21 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) chart->setMargins({0, 0, 0, 0}); chart->layout()->setContentsMargins(0, 0, 0, 0); - track_line = new QGraphicsLineItem(chart); - track_line->setZValue(chart->zValue() + 10); - track_line->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); - track_ellipse = new QGraphicsEllipseItem(chart); - track_ellipse->setZValue(chart->zValue() + 10); - track_ellipse->setBrush(Qt::darkGray); - value_text = new QGraphicsTextItem(chart); - value_text->setZValue(chart->zValue() + 10); 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); + track_ellipse->setBrush(Qt::darkGray); + value_text = new QGraphicsTextItem(chart); + item_group = scene()->createItemGroup({track_line, track_ellipse, value_text}); + item_group->setZValue(chart->zValue() + 10); + setChart(chart); setRenderHint(QPainter::Antialiasing); setRubberBand(QChartView::HorizontalRubberBand); - if (auto rubber = findChild()) { - QPalette pal; - pal.setBrush(QPalette::Base, QColor(0, 0, 0, 80)); - rubber->setPalette(pal); - } QTimer *timer = new QTimer(this); timer->setInterval(100); @@ -335,12 +322,9 @@ void ChartView::updateSeries(const std::pair range) { auto events = can->events(); if (!events) return; - auto l = id.split(':'); - int bus = l[0].toInt(); - uint32_t address = l[1].toUInt(nullptr, 16); - 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()); @@ -380,17 +364,8 @@ void ChartView::updateAxisY() { } } -void ChartView::enterEvent(QEvent *event) { - track_line->setVisible(true); - value_text->setVisible(true); - track_ellipse->setVisible(true); - QChartView::enterEvent(event); -} - void ChartView::leaveEvent(QEvent *event) { - track_line->setVisible(false); - value_text->setVisible(false); - track_ellipse->setVisible(false); + item_group->setVisible(false); QChartView::leaveEvent(event); } @@ -442,9 +417,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { } value_text->setPos(text_x, pos.y() - 10); } - track_line->setVisible(value != vals.end()); - value_text->setVisible(value != vals.end()); - track_ellipse->setVisible(value != vals.end()); + item_group->setVisible(value != vals.end()); } else { setViewportUpdateMode(QGraphicsView::FullViewportUpdate); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index ff56008e7d..70e0774c3e 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "tools/cabana/canmessages.h" @@ -33,11 +32,11 @@ signals: private: void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; - void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void adjustChartMargins(); void updateAxisY(); + QGraphicsItemGroup *item_group; QGraphicsLineItem *track_line; QGraphicsEllipseItem *track_ellipse; QGraphicsTextItem *value_text; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 0ab67dd305..3ddcf41788 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -9,8 +9,7 @@ DBCManager::DBCManager(QObject *parent) : QObject(parent) {} DBCManager::~DBCManager() {} void DBCManager::open(const QString &dbc_file_name) { - dbc_name = dbc_file_name; - dbc = const_cast(dbc_lookup(dbc_name.toStdString())); + dbc = const_cast(dbc_lookup(dbc_file_name.toStdString())); msg_map.clear(); for (auto &msg : dbc->msgs) { msg_map[msg.address] = &msg; @@ -19,7 +18,6 @@ void DBCManager::open(const QString &dbc_file_name) { } 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(); @@ -51,22 +49,19 @@ QString DBCManager::generateDBC() { } void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size) { - auto m = const_cast(msg(id)); - if (m) { + if (auto m = const_cast(msg(id))) { m->name = name.toStdString(); m->size = size; } else { - uint32_t address = addressFromId(id); - dbc->msgs.push_back({.address = address, .name = name.toStdString(), .size = size}); - msg_map[address] = &dbc->msgs.back(); + m = &dbc->msgs.emplace_back(Msg{.address = parseId(id).second, .name = name.toStdString(), .size = size}); + msg_map[m->address] = m; } emit msgUpdated(id); } void DBCManager::addSignal(const QString &id, const Signal &sig) { if (Msg *m = const_cast(msg(id))) { - m->sigs.push_back(sig); - emit signalAdded(&m->sigs.back()); + emit signalAdded(&m->sigs.emplace_back(sig)); } } @@ -90,8 +85,9 @@ void DBCManager::removeSignal(const QString &id, const QString &sig_name) { } } -uint32_t DBCManager::addressFromId(const QString &id) { - return id.mid(id.indexOf(':') + 1).toUInt(nullptr, 16); +std::pair DBCManager::parseId(const QString &id) { + const auto list = id.split(':'); + return {list[0].toInt(), list[1].toUInt(nullptr, 16)}; } DBCManager *dbc() { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 913445d44e..d8a8da9b7a 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -18,13 +18,13 @@ public: void updateSignal(const QString &id, const QString &sig_name, const Signal &sig); void removeSignal(const QString &id, const QString &sig_name); - static uint32_t addressFromId(const QString &id); + static std::pair parseId(const QString &id); inline static std::vector allDBCNames() { return get_dbc_names(); } - inline QString name() const { return dbc_name; } + inline QString name() const { return dbc ? dbc->name.c_str() : ""; } void updateMsg(const QString &id, const QString &name, uint32_t size); inline const DBC *getDBC() const { return dbc; } - inline const Msg *msg(const QString &id) const { return msg(addressFromId(id)); } + inline const Msg *msg(const QString &id) const { return msg(parseId(id).second); } inline const Msg *msg(uint32_t address) const { auto it = msg_map.find(address); return it != msg_map.end() ? it->second : nullptr; @@ -38,7 +38,6 @@ signals: void DBCFileChanged(); private: - QString dbc_name; DBC *dbc = nullptr; std::unordered_map msg_map; }; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index f3e3438229..db731333d3 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -277,9 +277,7 @@ void DetailWidget::removeSignal(const Signal *sig) { 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(); + QFormLayout *form_layout = new QFormLayout(this); form_layout->addRow("ID", new QLabel(msg_id)); name_edit = new QLineEdit(title, this); @@ -291,10 +289,8 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title 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); + form_layout->addRow(buttonBox); setFixedWidth(parent->width() * 0.9); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index ce3468e472..ac32d5952e 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -26,9 +26,6 @@ public: void setMessage(const QString &message_id); void dbcMsgChanged(int show_form_idx = -1); -signals: - void binaryViewMoved(bool in); - private: void updateChartState(const QString &id, const Signal *sig, bool opened); void showTabBarContextMenu(const QPoint &pt); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index c2baca4d22..be643c58d9 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -81,11 +81,10 @@ MainWindow::MainWindow() : QWidget() { QObject::connect(this, &MainWindow::showMessage, status_bar, &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); - QObject::connect(detail_widget, &DetailWidget::binaryViewMoved, [this](bool in) { splitter->setSizes({in ? 100 : 0, 500}); }); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); QObject::connect(settings_btn, &QPushButton::clicked, this, &MainWindow::setOption); - QObject::connect(can, &CANMessages::eventsMerged, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); + QObject::connect(can, &CANMessages::streamStarted, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); main_win = this; qInstallMessageHandler(qLogMessageHandler); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index e80a66bce9..3639789239 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -67,7 +67,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // signals/slots QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); - QObject::connect(can, &CANMessages::eventsMerged, this, &MessagesWidget::loadDBCFromFingerprint); + QObject::connect(can, &CANMessages::streamStarted, this, &MessagesWidget::loadDBCFromFingerprint); QObject::connect(can, &CANMessages::updated, [this]() { model->updateState(); }); QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadDBCFromPaste); diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index bba59c0d74..b173b41df3 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -36,8 +36,7 @@ void Settings::load() { SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Settings")); - QVBoxLayout *main_layout = new QVBoxLayout(this); - QFormLayout *form_layout = new QFormLayout(); + QFormLayout *form_layout = new QFormLayout(this); fps = new QSpinBox(this); fps->setRange(10, 100); @@ -74,10 +73,8 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { chart_theme->setCurrentIndex(settings.chart_theme == 1 ? 1 : 0); form_layout->addRow(tr("Chart theme"), chart_theme); - main_layout->addLayout(form_layout); - auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - main_layout->addWidget(buttonBox); + form_layout->addRow(buttonBox); setFixedWidth(360); connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDlg::save); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 9a28f71bb9..d5e640b5f7 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -28,11 +28,9 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { slider = new Slider(this); slider->setSingleStep(0); - slider->setMinimum(0); - slider->setMaximum(can->totalSeconds() * 1000); slider_layout->addWidget(slider); - end_time_label = new QLabel(formatTime(can->totalSeconds())); + end_time_label = new QLabel(this); slider_layout->addWidget(end_time_label); main_layout->addLayout(slider_layout); @@ -61,6 +59,10 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); QObject::connect(cam_widget, &CameraWidget::clicked, [this]() { pause(!can->isPaused()); }); QObject::connect(play_btn, &QPushButton::clicked, [=]() { pause(!can->isPaused()); }); + QObject::connect(can, &CANMessages::streamStarted, [this]() { + end_time_label->setText(formatTime(can->totalSeconds())); + slider->setRange(0, can->totalSeconds() * 1000); + }); } void VideoWidget::pause(bool pause) { @@ -74,8 +76,7 @@ void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { max = can->totalSeconds(); } end_time_label->setText(formatTime(max)); - slider->setMinimum(min * 1000); - slider->setMaximum(max * 1000); + slider->setRange(min * 1000, max * 1000); } void VideoWidget::updateState() { @@ -91,7 +92,7 @@ Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { timeline = can->getTimeline(); update(); }); - timer->start(); + QObject::connect(can, SIGNAL(streamStarted()), timer, SLOT(start())); } void Slider::sliderChange(QAbstractSlider::SliderChange change) { diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 51dae4c76f..16f60b0b03 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -3,7 +3,6 @@ #include #include #include -#include #include "selfdrive/ui/qt/widgets/cameraview.h" #include "tools/cabana/canmessages.h" From ea5587d1d14e01b7a2aeae34f8abc73886699519 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 7 Nov 2022 03:03:57 +0800 Subject: [PATCH 0201/1179] Cabana: fix wrong hardcoded column index (#26392) fix wrong column count --- tools/cabana/messageswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 3639789239..9444ea9c48 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -224,7 +224,7 @@ void MessageListModel::updateState(bool sort) { changePersistentIndex(idx, index(std::distance(msgs.begin(), it), idx.column())); } } - emit dataChanged(index(0, 0), index(msgs.size() - 1, 3), {Qt::DisplayRole}); + emit dataChanged(index(0, 0), index(msgs.size() - 1, columnCount() - 1), {Qt::DisplayRole}); } } From 529504e201a4130bad7ff9ab712e01c1341ac349 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 7 Nov 2022 03:05:14 +0800 Subject: [PATCH 0202/1179] Cabana: move dbc related code from MessagesWidget to MainWin (#26387) * move dbc related code to mainwin * trigger ci --- tools/cabana/mainwin.cc | 138 ++++++++++++++++++++++++++++++++- tools/cabana/mainwin.h | 31 ++++++++ tools/cabana/messageswidget.cc | 133 +------------------------------ tools/cabana/messageswidget.h | 31 -------- 4 files changed, 167 insertions(+), 166 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index be643c58d9..d3d7ff4156 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -1,7 +1,13 @@ #include "tools/cabana/mainwin.h" #include +#include +#include +#include +#include +#include #include +#include #include #include @@ -23,8 +29,38 @@ MainWindow::MainWindow() : QWidget() { splitter = new QSplitter(Qt::Horizontal, this); splitter->setHandleWidth(11); + + // DBC file selector + QWidget *messages_container = new QWidget(this); + QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); + messages_layout->setContentsMargins(0, 0, 0, 0); + QHBoxLayout *dbc_file_layout = new QHBoxLayout(); + dbc_combo = new QComboBox(this); + auto dbc_names = dbc()->allDBCNames(); + for (const auto &name : dbc_names) { + dbc_combo->addItem(QString::fromStdString(name)); + } + 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); + 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); + dbc_file_layout->addWidget(save_btn); + messages_layout->addLayout(dbc_file_layout); + messages_widget = new MessagesWidget(this); - splitter->addWidget(messages_widget); + messages_layout->addWidget(messages_widget); + splitter->addWidget(messages_container); charts_widget = new ChartsWidget(this); detail_widget = new DetailWidget(charts_widget, this); @@ -78,16 +114,55 @@ MainWindow::MainWindow() : QWidget() { emit updateProgressBar(cur, total, success); }); + main_win = this; + qInstallMessageHandler(qLogMessageHandler); + QFile json_file("./car_fingerprint_to_dbc.json"); + if (json_file.open(QIODevice::ReadOnly)) { + fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); + } + + QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); + QObject::connect(load_from_paste, &QPushButton::clicked, this, &MainWindow::loadDBCFromPaste); + QObject::connect(save_btn, &QPushButton::clicked, this, &MainWindow::saveDBC); QObject::connect(this, &MainWindow::showMessage, status_bar, &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); QObject::connect(settings_btn, &QPushButton::clicked, this, &MainWindow::setOption); + QObject::connect(can, &CANMessages::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(can, &CANMessages::streamStarted, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); +} - main_win = this; - qInstallMessageHandler(qLogMessageHandler); +void MainWindow::loadDBCFromName(const QString &name) { + if (name != dbc()->name()) { + dbc()->open(name); + dbc_combo->setCurrentText(name); + } +} + +void MainWindow::loadDBCFromPaste() { + LoadDBCDialog dlg(this); + if (dlg.exec()) { + dbc()->open("from paste", dlg.dbc_edit->toPlainText()); + dbc_combo->setCurrentText("loaded from paste"); + } +} + +void MainWindow::loadDBCFromFingerprint() { + auto fingerprint = can->carFingerprint(); + if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { + auto dbc_name = fingerprint_to_dbc[fingerprint]; + if (dbc_name != QJsonValue::Undefined) { + loadDBCFromName(dbc_name.toString()); + } + } +} + +void MainWindow::saveDBC() { + SaveDBCDialog dlg(this); + dlg.dbc_edit->setText(dbc()->generateDBC()); + dlg.exec(); } void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool success) { @@ -127,3 +202,60 @@ void MainWindow::setOption() { SettingsDlg dlg(this); dlg.exec(); } + +// LoadDBCDialog + +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); + + setMinimumSize({640, 480}); + QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +// SaveDBCDialog + +SaveDBCDialog::SaveDBCDialog(QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Save DBC")); + QVBoxLayout *main_layout = new QVBoxLayout(this); + dbc_edit = new QTextEdit(this); + dbc_edit->setAcceptRichText(false); + main_layout->addWidget(dbc_edit); + + QPushButton *copy_to_clipboard = new QPushButton(tr("Copy To Clipboard"), this); + QPushButton *save_as = new QPushButton(tr("Save As"), this); + + QHBoxLayout *btn_layout = new QHBoxLayout(); + btn_layout->addStretch(); + btn_layout->addWidget(copy_to_clipboard); + btn_layout->addWidget(save_as); + main_layout->addLayout(btn_layout); + setMinimumSize({640, 480}); + + QObject::connect(copy_to_clipboard, &QPushButton::clicked, this, &SaveDBCDialog::copytoClipboard); + QObject::connect(save_as, &QPushButton::clicked, this, &SaveDBCDialog::saveAs); +} + +void SaveDBCDialog::copytoClipboard() { + dbc_edit->selectAll(); + dbc_edit->copy(); + QDialog::accept(); +} + +void SaveDBCDialog::saveAs() { + QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), + QDir::homePath() + "/untitled.dbc", tr("DBC (*.dbc)")); + if (!file_name.isEmpty()) { + QFile file(file_name); + if (file.open(QIODevice::WriteOnly)) { + file.write(dbc_edit->toPlainText().toUtf8()); + } + QDialog::accept(); + } +} diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index b77744ba9c..f6853a5ea3 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,8 +1,12 @@ #pragma once +#include +#include +#include #include #include #include +#include #include "tools/cabana/chartswidget.h" #include "tools/cabana/detailwidget.h" @@ -17,6 +21,12 @@ public: void dockCharts(bool dock); void showStatusMessage(const QString &msg, int timeout = 0) { status_bar->showMessage(msg, timeout); } +public slots: + void loadDBCFromName(const QString &name); + void loadDBCFromFingerprint(); + void loadDBCFromPaste(); + void saveDBC(); + signals: void showMessage(const QString &msg, int timeout); void updateProgressBar(uint64_t cur, uint64_t total, bool success); @@ -35,4 +45,25 @@ protected: QVBoxLayout *r_layout; QProgressBar *progress_bar; QStatusBar *status_bar; + QJsonDocument fingerprint_to_dbc; + QComboBox *dbc_combo; +}; + + +class LoadDBCDialog : public QDialog { + Q_OBJECT + +public: + LoadDBCDialog(QWidget *parent); + QTextEdit *dbc_edit; +}; + +class SaveDBCDialog : public QDialog { + Q_OBJECT + +public: + SaveDBCDialog(QWidget *parent); + void copytoClipboard(); + void saveAs(); + QTextEdit *dbc_edit; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 9444ea9c48..b2e8e50b55 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -1,15 +1,8 @@ #include "tools/cabana/messageswidget.h" -#include -#include -#include -#include -#include #include #include #include -#include -#include #include #include "tools/cabana/dbcmanager.h" @@ -18,31 +11,6 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); - // DBC file selector - QHBoxLayout *dbc_file_layout = new QHBoxLayout(); - dbc_combo = new QComboBox(this); - auto dbc_names = dbc()->allDBCNames(); - for (const auto &name : dbc_names) { - dbc_combo->addItem(QString::fromStdString(name)); - } - 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); - 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); - dbc_file_layout->addWidget(save_btn); - main_layout->addLayout(dbc_file_layout); - // message filter QLineEdit *filter = new QLineEdit(this); filter->setClearButtonEnabled(true); @@ -67,55 +35,13 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // signals/slots QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); - QObject::connect(can, &CANMessages::streamStarted, this, &MessagesWidget::loadDBCFromFingerprint); QObject::connect(can, &CANMessages::updated, [this]() { model->updateState(); }); - QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); - QObject::connect(load_from_paste, &QPushButton::clicked, this, &MessagesWidget::loadDBCFromPaste); - QObject::connect(save_btn, &QPushButton::clicked, this, &MessagesWidget::saveDBC); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { model->updateState(true); }); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid()) { emit msgSelectionChanged(current.data(Qt::UserRole).toString()); } }); - - QFile json_file("./car_fingerprint_to_dbc.json"); - if (json_file.open(QIODevice::ReadOnly)) { - fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); - } -} - -void MessagesWidget::loadDBCFromName(const QString &name) { - if (name != dbc()->name()) { - dbc()->open(name); - dbc_combo->setCurrentText(name); - // re-sort model to refresh column 'Name' - model->updateState(true); - } -} - -void MessagesWidget::loadDBCFromPaste() { - LoadDBCDialog dlg(this); - if (dlg.exec()) { - dbc()->open("from paste", dlg.dbc_edit->toPlainText()); - dbc_combo->setCurrentText("loaded from paste"); - model->updateState(true); - } -} - -void MessagesWidget::loadDBCFromFingerprint() { - auto fingerprint = can->carFingerprint(); - if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { - auto dbc_name = fingerprint_to_dbc[fingerprint]; - if (dbc_name != QJsonValue::Undefined) { - loadDBCFromName(dbc_name.toString()); - } - } -} - -void MessagesWidget::saveDBC() { - SaveDBCDialog dlg(this); - dlg.dbc_edit->setText(dbc()->generateDBC()); - dlg.exec(); } // MessageListModel @@ -235,60 +161,3 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { updateState(true); } } - -// LoadDBCDialog - -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); - - setMinimumSize({640, 480}); - QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -// SaveDBCDialog - -SaveDBCDialog::SaveDBCDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(tr("Save DBC")); - QVBoxLayout *main_layout = new QVBoxLayout(this); - dbc_edit = new QTextEdit(this); - dbc_edit->setAcceptRichText(false); - main_layout->addWidget(dbc_edit); - - QPushButton *copy_to_clipboard = new QPushButton(tr("Copy To Clipboard"), this); - QPushButton *save_as = new QPushButton(tr("Save As"), this); - - QHBoxLayout *btn_layout = new QHBoxLayout(); - btn_layout->addStretch(); - btn_layout->addWidget(copy_to_clipboard); - btn_layout->addWidget(save_as); - main_layout->addLayout(btn_layout); - setMinimumSize({640, 480}); - - QObject::connect(copy_to_clipboard, &QPushButton::clicked, this, &SaveDBCDialog::copytoClipboard); - QObject::connect(save_as, &QPushButton::clicked, this, &SaveDBCDialog::saveAs); -} - -void SaveDBCDialog::copytoClipboard() { - dbc_edit->selectAll(); - dbc_edit->copy(); - QDialog::accept(); -} - -void SaveDBCDialog::saveAs() { - QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), - QDir::homePath() + "/untitled.dbc", tr("DBC (*.dbc)")); - if (!file_name.isEmpty()) { - QFile file(file_name); - if (file.open(QIODevice::WriteOnly)) { - file.write(dbc_edit->toPlainText().toUtf8()); - } - QDialog::accept(); - } -} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 255dce7dc8..450c7003b7 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,32 +1,9 @@ #pragma once #include -#include -#include -#include #include -#include #include "tools/cabana/canmessages.h" - -class LoadDBCDialog : public QDialog { - Q_OBJECT - -public: - LoadDBCDialog(QWidget *parent); - QTextEdit *dbc_edit; -}; - -class SaveDBCDialog : public QDialog { - Q_OBJECT - -public: - SaveDBCDialog(QWidget *parent); - void copytoClipboard(); - void saveAs(); - QTextEdit *dbc_edit; -}; - class MessageListModel : public QAbstractTableModel { Q_OBJECT @@ -58,18 +35,10 @@ class MessagesWidget : public QWidget { public: MessagesWidget(QWidget *parent); -public slots: - void loadDBCFromName(const QString &name); - void loadDBCFromFingerprint(); - void loadDBCFromPaste(); - void saveDBC(); - signals: void msgSelectionChanged(const QString &message_id); protected: QTableView *table_widget; - QComboBox *dbc_combo; MessageListModel *model; - QJsonDocument fingerprint_to_dbc; }; From 3dc5dbf103290355b85a146f213f733cbb1dfeb5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 7 Nov 2022 03:05:46 +0800 Subject: [PATCH 0203/1179] Cabana: move the chart title into graphics view (#26389) remove class ChartWidget --- tools/cabana/chartswidget.cc | 109 ++++++++++++++--------------------- tools/cabana/chartswidget.h | 45 +++++---------- 2 files changed, 55 insertions(+), 99 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 6432cb7079..9a8d95633c 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -2,9 +2,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -13,7 +13,6 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); // title bar title_bar = new QWidget(this); @@ -120,14 +119,14 @@ void ChartsWidget::updateState() { if (prev_range != display_range) { QFutureSynchronizer future_synchronizer; for (auto c : charts) - future_synchronizer.addFuture(QtConcurrent::run(c->chart_view, &ChartView::updateSeries, display_range)); + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, display_range)); } } const auto &range = is_zoomed ? zoomed_range : display_range; for (auto c : charts) { - c->chart_view->setRange(range.first, range.second); - c->chart_view->updateLineMarker(current_sec); + c->setRange(range.first, range.second); + c->updateLineMarker(current_sec); } } @@ -150,11 +149,11 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show) { if (it != charts.end()) { if (!show) removeChart((*it)); } else if (show) { - auto chart = new ChartWidget(id, sig, this); - chart->chart_view->updateSeries(display_range); - QObject::connect(chart, &ChartWidget::remove, [=]() { removeChart(chart); }); - QObject::connect(chart->chart_view, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); - QObject::connect(chart->chart_view, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); + 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); @@ -168,7 +167,7 @@ bool ChartsWidget::isChartOpened(const QString &id, const Signal *sig) { return it != charts.end(); } -void ChartsWidget::removeChart(ChartWidget *chart) { +void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); updateTitleBar(); @@ -184,8 +183,8 @@ void ChartsWidget::signalUpdated(const Signal *sig) { for (auto c : charts) { if (c->signal == sig) { c->updateTitle(); - c->chart_view->updateSeries(display_range); - c->chart_view->setRange(display_range.first, display_range.second, true); + c->updateSeries(display_range); + c->setRange(display_range.first, display_range.second, true); } } } @@ -198,54 +197,6 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { return false; } -// ChartWidget - -ChartWidget::ChartWidget(const QString &id, const Signal *sig, QWidget *parent) : id(id), signal(sig), QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setSpacing(0); - main_layout->setContentsMargins(0, 0, 0, 0); - - header = new QWidget(this); - QGridLayout *header_layout = new QGridLayout(header); - header_layout->setContentsMargins(11, 11, 11, 0); - msg_name_label = new QLabel(this); - msg_name_label->setTextFormat(Qt::RichText); - header_layout->addWidget(msg_name_label, 0, 0, Qt::AlignLeft); - sig_name_label = new QLabel(this); - header_layout->addWidget(sig_name_label, 0, 1, Qt::AlignCenter); //, 0, Qt::AlignCenter); - - remove_btn = new QPushButton("✖", this); - remove_btn->setFixedSize(20, 20); - remove_btn->setToolTip(tr("Remove chart")); - header_layout->addWidget(remove_btn, 0, 2, Qt::AlignRight); - main_layout->addWidget(header); - - chart_view = new ChartView(id, sig, this); - main_layout->addWidget(chart_view); - main_layout->addStretch(); - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - updateTitle(); - updateFromSettings(); - - QObject::connect(remove_btn, &QPushButton::clicked, [=]() { emit remove(id, sig); }); - QObject::connect(&settings, &Settings::changed, this, &ChartWidget::updateFromSettings); -} - -void ChartWidget::updateTitle() { - msg_name_label->setText(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); - sig_name_label->setText(signal->name.c_str()); -} - -void ChartWidget::updateFromSettings() { - header->setStyleSheet(settings.chart_theme == 0 ? "background-color:white" : "background-color:#23242c"); - QString color_style = settings.chart_theme == 0 ? "color:black" : "color:white"; - sig_name_label->setStyleSheet("font-weight:bold;" + color_style); - msg_name_label->setStyleSheet(color_style); - remove_btn->setStyleSheet(color_style); - chart_view->updateFromSettings(); -} - // ChartView ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) @@ -256,7 +207,6 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) chart->addSeries(series); chart->createDefaultAxes(); chart->legend()->hide(); - chart->setMargins({0, 0, 0, 0}); chart->layout()->setContentsMargins(0, 0, 0, 0); line_marker = new QGraphicsLineItem(chart); @@ -270,26 +220,51 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) item_group = scene()->createItemGroup({track_line, track_ellipse, value_text}); item_group->setZValue(chart->zValue() + 10); - setChart(chart); + // title + msg_title = new QGraphicsTextItem(chart); + QToolButton *remove_btn = new QToolButton(); + remove_btn->setText("X"); + remove_btn->setAutoRaise(true); + remove_btn->setToolTip(tr("Remove Chart")); + close_btn_proxy = new QGraphicsProxyWidget(chart); + close_btn_proxy->setWidget(remove_btn); + 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(&settings, &Settings::changed, this, &ChartView::updateFromSettings); + QObject::connect(remove_btn, &QToolButton::clicked, [=]() { emit remove(id, sig); }); QObject::connect(chart, &QChart::plotAreaChanged, [=](const QRectF &plotArea) { // use a singleshot timer to avoid recursion call. timer->start(); }); } +void ChartView::resizeEvent(QResizeEvent *event) { + QChartView::resizeEvent(event); + msg_title->setPos(11, 6); + close_btn_proxy->setPos(event->size().width() - close_btn_proxy->size().width() - 11, 8); +} + +void ChartView::updateTitle() { + chart()->setTitle(signal->name.c_str()); + msg_title->setHtml(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); +} + void ChartView::updateFromSettings() { setFixedHeight(settings.chart_height); chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark); - line_marker->setPen(QPen(settings.chart_theme == 0 ? Qt::black : Qt::white, 2)); + auto color = chart()->titleBrush().color(); + line_marker->setPen(QPen(color, 2)); + msg_title->setDefaultTextColor(color); } void ChartView::setRange(double min, double max, bool force_update) { @@ -305,7 +280,7 @@ void ChartView::adjustChartMargins() { 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)); + chart()->setMargins(QMargins(left_margin, 11, 0, 0)); } } @@ -314,7 +289,7 @@ 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, 0, x, height()); + line_marker->setLine(x, chart()->plotArea().top() - chart()->margins().top() + 3, x, height()); } } @@ -402,7 +377,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (!is_zooming) { const auto plot_area = chart()->plotArea(); auto axis_x = dynamic_cast(chart()->axisX()); - double x = std::clamp((double)ev->pos().x(), plot_area.left(), plot_area.right()-1); + 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()) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 70e0774c3e..4d33e91cb9 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -1,10 +1,9 @@ #pragma once -#include - #include #include #include +#include #include #include #include @@ -24,48 +23,31 @@ public: void setRange(double min, double max, bool force_update = false); void updateLineMarker(double current_sec); void updateFromSettings(); + void updateTitle(); + + QString id; + const Signal *signal; signals: void zoomIn(double min, double max); void zoomReset(); + void remove(const QString &msg_id, const Signal *sig); private: void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; void leaveEvent(QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; void adjustChartMargins(); void updateAxisY(); QGraphicsItemGroup *item_group; - QGraphicsLineItem *track_line; + QGraphicsLineItem *line_marker, *track_line; QGraphicsEllipseItem *track_ellipse; - QGraphicsTextItem *value_text; - QGraphicsLineItem *line_marker; + QGraphicsTextItem *value_text, *msg_title; + QGraphicsProxyWidget *close_btn_proxy; QVector vals; - QString id; - const Signal *signal; -}; - -class ChartWidget : public QWidget { -Q_OBJECT - -public: - ChartWidget(const QString &id, const Signal *sig, QWidget *parent); - void updateTitle(); - void updateFromSettings(); - -signals: - void remove(const QString &msg_id, const Signal *sig); - -public: - QString id; - const Signal *signal; - QWidget *header; - QLabel *msg_name_label; - QLabel *sig_name_label; - QPushButton *remove_btn; - ChartView *chart_view = nullptr; -}; + }; class ChartsWidget : public QWidget { Q_OBJECT @@ -73,7 +55,7 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); void showChart(const QString &id, const Signal *sig, bool show); - void removeChart(ChartWidget *chart); + void removeChart(ChartView *chart); bool isChartOpened(const QString &id, const Signal *sig); signals: @@ -100,8 +82,7 @@ private: QPushButton *reset_zoom_btn; QPushButton *remove_all_btn; QVBoxLayout *charts_layout; - QList charts; - + QList charts; bool is_zoomed = false; std::pair event_range; std::pair display_range; From cdcc0fb3695d75e781053f9feda6b6b91a08ea86 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 7 Nov 2022 03:06:10 +0800 Subject: [PATCH 0204/1179] Cabana: Reimplement HistoryLog::sizeHintForColumn to improve performance (#26393) Reimplement sizeHintForColumn to improve performance --- tools/cabana/historylog.cc | 6 +++++- tools/cabana/historylog.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 7bb2f37699..4b1818cf68 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -1,7 +1,6 @@ #include "tools/cabana/historylog.h" #include -#include // HistoryLogModel @@ -89,3 +88,8 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); } + +int HistoryLog::sizeHintForColumn(int column) const { + // sizeHintForColumn is only called for column 0 (ResizeToContents) + return itemDelegate()->sizeHint(viewOptions(), model->index(0, 0)).width() + 1; // +1 for grid +} diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index e1c1319166..e8b0f5a35b 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -9,7 +9,7 @@ class HeaderView : public QHeaderView { public: HeaderView(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {} - QSize sectionSizeFromContents(int logicalIndex) const; + QSize sectionSizeFromContents(int logicalIndex) const override; }; class HistoryLogModel : public QAbstractTableModel { @@ -40,5 +40,6 @@ public: void setMessage(const QString &message_id) { model->setMessage(message_id); } void updateState() { model->updateState(); } private: + int sizeHintForColumn(int column) const override; HistoryLogModel *model; }; From 45891c79079ae4404b8828d9bcfe5cd79bce0c90 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 7 Nov 2022 03:06:42 +0800 Subject: [PATCH 0205/1179] Cabana: use QToolBar to manage the controls in ChartsView (#26388) use QToolBar --- tools/cabana/chartswidget.cc | 73 +++++++++++++----------------------- tools/cabana/chartswidget.h | 9 ++--- 2 files changed, 30 insertions(+), 52 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 9a8d95633c..b4d6d89e6d 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -8,47 +8,31 @@ #include #include #include +#include // ChartsWidget ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - // 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")); - - title_layout->addWidget(title_label); - title_layout->addStretch(); - - range_label = new QLabel(); - title_layout->addWidget(range_label); - - reset_zoom_btn = new QPushButton("⟲", this); - reset_zoom_btn->setFixedSize(30, 30); + // toolbar + QToolBar *toolbar = new QToolBar(tr("Charts"), this); + title_label = new QLabel(); + title_label->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred); + toolbar->addWidget(title_label); + toolbar->addWidget(range_label = new QLabel()); + reset_zoom_btn = toolbar->addAction("⟲"); 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 = toolbar->addAction("✖"); remove_all_btn->setToolTip(tr("Remove all charts")); - remove_all_btn->setFixedSize(30, 30); - title_layout->addWidget(remove_all_btn); - - dock_btn = new QPushButton(); - dock_btn->setFixedSize(30, 30); - title_layout->addWidget(dock_btn); - - main_layout->addWidget(title_bar, 0, Qt::AlignTop); + dock_btn = toolbar->addAction(""); + main_layout->addWidget(toolbar); + updateToolBar(); // charts QWidget *charts_container = new QWidget(this); - QVBoxLayout *charts_main = new QVBoxLayout(charts_container); - charts_layout = new QVBoxLayout(); - charts_main->addLayout(charts_layout); - charts_main->addStretch(); + charts_layout = new QVBoxLayout(charts_container); + charts_layout->addStretch(); QScrollArea *charts_scroll = new QScrollArea(this); charts_scroll->setWidgetResizable(true); @@ -67,12 +51,12 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { }); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState); - QObject::connect(remove_all_btn, &QPushButton::clicked, [this]() { removeAll(); }); - QObject::connect(reset_zoom_btn, &QPushButton::clicked, this, &ChartsWidget::zoomReset); - QObject::connect(dock_btn, &QPushButton::clicked, [this]() { + QObject::connect(remove_all_btn, &QAction::triggered, [this]() { removeAll(); }); + QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); + QObject::connect(dock_btn, &QAction::triggered, [this]() { emit dock(!docking); docking = !docking; - updateTitleBar(); + updateToolBar(); }); } @@ -91,7 +75,7 @@ void ChartsWidget::eventsMerged() { void ChartsWidget::zoomIn(double min, double max) { zoomed_range = {min, max}; is_zoomed = zoomed_range != display_range; - updateTitleBar(); + updateToolBar(); emit rangeChanged(min, max, is_zoomed); updateState(); } @@ -130,16 +114,11 @@ void ChartsWidget::updateState() { } } -void ChartsWidget::updateTitleBar() { - title_bar->setVisible(!charts.isEmpty()); - if (charts.isEmpty()) return; - - range_label->setVisible(is_zoomed); +void ChartsWidget::updateToolBar() { + remove_all_btn->setEnabled(!charts.isEmpty()); reset_zoom_btn->setEnabled(is_zoomed); - if (is_zoomed) { - range_label->setText(tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2)); - } - title_label->setText(tr("Charts (%1)").arg(charts.size())); + range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); + title_label->setText(charts.size() > 0 ? tr("Charts (%1)").arg(charts.size()) : tr("Charts")); dock_btn->setText(docking ? "⬈" : "⬋"); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); } @@ -159,7 +138,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show) { emit chartOpened(chart->id, chart->signal); updateState(); } - updateTitleBar(); + updateToolBar(); } bool ChartsWidget::isChartOpened(const QString &id, const Signal *sig) { @@ -170,7 +149,7 @@ bool ChartsWidget::isChartOpened(const QString &id, const Signal *sig) { void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); - updateTitleBar(); + updateToolBar(); emit chartClosed(chart->id, chart->signal); } @@ -191,7 +170,7 @@ void ChartsWidget::signalUpdated(const Signal *sig) { bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { if (obj != this && event->type() == QEvent::Close) { - emit dock_btn->clicked(); + emit dock_btn->triggered(); return true; } return false; diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 4d33e91cb9..e32a6697ce 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -70,17 +70,16 @@ private: void zoomIn(double min, double max); void zoomReset(); void signalUpdated(const Signal *sig); - void updateTitleBar(); + void updateToolBar(); void removeAll(const Signal *sig = nullptr); bool eventFilter(QObject *obj, QEvent *event) override; - QWidget *title_bar; QLabel *title_label; QLabel *range_label; bool docking = true; - QPushButton *dock_btn; - QPushButton *reset_zoom_btn; - QPushButton *remove_all_btn; + QAction *dock_btn; + QAction *reset_zoom_btn; + QAction *remove_all_btn; QVBoxLayout *charts_layout; QList charts; bool is_zoomed = false; From 253e5d7f9d7741e61f010f2ffd6b82a2e908019a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 6 Nov 2022 12:17:07 -0800 Subject: [PATCH 0206/1179] FCW: less false positives (#26366) * Less FP for FCW * enable fcw for e2e long --- selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py | 5 +++-- selfdrive/controls/lib/longitudinal_planner.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 49eb5988e2..080782ad0f 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -36,7 +36,7 @@ A_EGO_COST = 0. J_EGO_COST = 5.0 A_CHANGE_COST = 200. DANGER_ZONE_COST = 100. -CRASH_DISTANCE = .5 +CRASH_DISTANCE = .25 LEAD_DANGER_FACTOR = 0.75 LIMIT_COST = 1e6 ACADOS_SOLVER_TYPE = 'SQP_RTI' @@ -49,6 +49,7 @@ MAX_T = 10.0 T_IDXS_LST = [index_function(idx, max_val=MAX_T, max_idx=N) for idx in range(N+1)] T_IDXS = np.array(T_IDXS_LST) +FCW_IDXS = T_IDXS < 5.0 T_DIFFS = np.diff(T_IDXS, prepend=[0.]) MIN_ACCEL = -3.5 MAX_ACCEL = 2.0 @@ -369,7 +370,7 @@ class LongitudinalMpc: self.params[:,4] = T_FOLLOW self.run() - if (np.any(lead_xv_0[:,0] - self.x_sol[:,0] < CRASH_DISTANCE) and + if (np.any(lead_xv_0[FCW_IDXS,0] - self.x_sol[FCW_IDXS,0] < CRASH_DISTANCE) and radarstate.leadOne.modelProb > 0.9): self.crash_cnt += 1 else: diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 457065d3b5..5a336d18c9 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -132,8 +132,7 @@ class LongitudinalPlanner: self.j_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC[:-1], self.mpc.j_solution) # TODO counter is only needed because radar is glitchy, remove once radar is gone - # TODO write fcw in e2e_long mode - self.fcw = self.mpc.mode == 'acc' and self.mpc.crash_cnt > 5 and not sm['carState'].standstill + self.fcw = self.mpc.crash_cnt > 2 and not sm['carState'].standstill if self.fcw: cloudlog.info("FCW triggered") From 1cf293f3a6c02bb44af9ef1e715b005104de1bc1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 7 Nov 2022 23:53:42 +0800 Subject: [PATCH 0207/1179] Cabana: improve message sorting,filtering and updating. (#26396) * optimize sort/filter/update * helper function msgName * cleanup --- tools/cabana/canmessages.cc | 3 +- tools/cabana/canmessages.h | 1 + tools/cabana/dbcmanager.h | 5 +- tools/cabana/detailwidget.cc | 7 +-- tools/cabana/messageswidget.cc | 112 +++++++++++++-------------------- tools/cabana/messageswidget.h | 13 ++-- 6 files changed, 58 insertions(+), 83 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index f1f5c2cd23..e670ee8c94 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -62,8 +62,9 @@ void CANMessages::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { can_msgs[it.key()] = it.value(); } - delete messages; emit updated(); + emit msgsReceived(messages); + delete messages; } bool CANMessages::eventFilter(const Event *event) { diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 14e2423d01..5ee33bce0d 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -50,6 +50,7 @@ signals: void streamStarted(); void eventsMerged(); void updated(); + void msgsReceived(const QHash *); void received(QHash *); public: diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index d8a8da9b7a..cbe4531d2a 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -48,5 +48,8 @@ int bigEndianStartBitsIndex(int start_bit); int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(Signal &s, int from, int to); std::pair getSignalRange(const Signal *s); - DBCManager *dbc(); +inline QString msgName(const QString &id, const char *def = "untitled") { + auto msg = dbc()->msg(id); + return msg ? msg->name.c_str() : def; +} diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index db731333d3..18510c86ea 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -132,8 +132,7 @@ void DetailWidget::setMessage(const QString &message_id) { } if (index == -1) { index = tabbar->addTab(message_id); - auto msg = dbc()->msg(message_id); - tabbar->setTabToolTip(index, msg ? msg->name.c_str() : "untitled"); + tabbar->setTabToolTip(index, msgName(message_id)); } tabbar->setCurrentIndex(index); msg_id = message_id; @@ -173,7 +172,7 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { } edit_btn->setVisible(true); - name_label->setText(msg ? msg->name.c_str() : "untitled"); + name_label->setText(msgName(msg_id)); binary_view->setMessage(msg_id); history_log->setMessage(msg_id); @@ -212,7 +211,7 @@ void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool o void DetailWidget::editMsg() { auto msg = dbc()->msg(msg_id); - QString name = msg ? msg->name.c_str() : "untitled"; + QString name = msgName(msg_id); int size = msg ? msg->size : can->lastMessage(msg_id).dat.size(); EditMessageDialog dlg(msg_id, name, size, this); if (dlg.exec()) { diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index b2e8e50b55..f24b6b0317 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -35,13 +35,19 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // signals/slots QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); - QObject::connect(can, &CANMessages::updated, [this]() { model->updateState(); }); - QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { model->updateState(true); }); + QObject::connect(can, &CANMessages::msgsReceived, model, &MessageListModel::msgsReceived); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); + QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { - if (current.isValid()) { - emit msgSelectionChanged(current.data(Qt::UserRole).toString()); + if (current.isValid() && current.row() < model->msgs.size()) { + current_msg_id = model->msgs[current.row()]; + emit msgSelectionChanged(current_msg_id); } }); + QObject::connect(model, &MessageListModel::modelReset, [this]() { + if (int row = model->msgs.indexOf(current_msg_id); row != -1) + table_widget->selectionModel()->select(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); + }); } // MessageListModel @@ -54,103 +60,71 @@ QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, QVariant MessageListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { - const auto &m = msgs[index.row()]; - auto &can_data = can->lastMessage(m->id); + const auto &id = msgs[index.row()]; + auto &can_data = can->lastMessage(id); switch (index.column()) { - case 0: return m->name; - case 1: return m->id; + case 0: return msgName(id); + case 1: return id; case 2: return can_data.freq; case 3: return can_data.count; case 4: return toHex(can_data.dat); } - } else if (role == Qt::UserRole) { - return msgs[index.row()]->id; - } else if (role == Qt::FontRole) { - if (index.column() == columnCount() - 1) { - return QFontDatabase::systemFont(QFontDatabase::FixedFont); - } + } else if (role == Qt::FontRole && index.column() == columnCount() - 1) { + return QFontDatabase::systemFont(QFontDatabase::FixedFont); } return {}; } -void MessageListModel::setFilterString(const QString &string) { +void MessageListModel::setFilterString(const QString &string) { filter_str = string; - updateState(true); + bool search_id = filter_str.contains(':'); + msgs.clear(); + for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + if ((search_id ? it.key() : msgName(it.key())).contains(filter_str, Qt::CaseInsensitive)) + msgs.push_back(it.key()); + } + sortMessages(); } -bool MessageListModel::updateMessages(bool sort) { - if (msgs.size() == can->can_msgs.size() && filter_str.isEmpty() && !sort) - return false; - - // update message list - int i = 0; - bool search_id = filter_str.contains(':'); - for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { - const Msg *msg = dbc()->msg(it.key()); - QString msg_name = msg ? msg->name.c_str() : "untitled"; - if (!filter_str.isEmpty() && !(search_id ? it.key() : msg_name).contains(filter_str, Qt::CaseInsensitive)) - continue; - auto &m = i < msgs.size() ? msgs[i] : msgs.emplace_back(new Message); - m->id = it.key(); - m->name = msg_name; - ++i; - } - msgs.resize(i); - +void MessageListModel::sortMessages() { + beginResetModel(); if (sort_column == 0) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - bool ret = l->name < r->name || (l->name == r->name && l->id < r->id); + bool ret = std::pair{msgName(l), l} < std::pair{msgName(r), r}; return sort_order == Qt::AscendingOrder ? ret : !ret; }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - return sort_order == Qt::AscendingOrder ? l->id < r->id : l->id > r->id; + return sort_order == Qt::AscendingOrder ? l < r : l > r; }); } else if (sort_column == 2) { - // sort by frequency std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - uint32_t lfreq = can->lastMessage(l->id).freq; - uint32_t rfreq = can->lastMessage(r->id).freq; - bool ret = lfreq < rfreq || (lfreq == rfreq && l->id < r->id); + bool ret = std::pair{can->lastMessage(l).freq, l} < std::pair{can->lastMessage(r).freq, r}; return sort_order == Qt::AscendingOrder ? ret : !ret; }); } else if (sort_column == 3) { - // sort by count std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - uint32_t lcount = can->lastMessage(l->id).count; - uint32_t rcount = can->lastMessage(r->id).count; - bool ret = lcount < rcount || (lcount == rcount && l->id < r->id); + bool ret = std::pair{can->lastMessage(l).count, l} < std::pair{can->lastMessage(r).count, r}; return sort_order == Qt::AscendingOrder ? ret : !ret; }); } - return true; + endResetModel(); } -void MessageListModel::updateState(bool sort) { +void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); - auto prev_idx = persistentIndexList(); - QString selected_msg_id = prev_idx.empty() ? "" : prev_idx[0].data(Qt::UserRole).toString(); - - bool msg_updated = updateMessages(sort); - int delta = msgs.size() - prev_row_count; - if (delta > 0) { - beginInsertRows({}, prev_row_count, msgs.size() - 1); - endInsertRows(); - } else if (delta < 0) { - beginRemoveRows({}, msgs.size(), prev_row_count - 1); - endRemoveRows(); + if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { + msgs = can->can_msgs.keys(); } - - if (!msgs.empty()) { - if (msg_updated && !prev_idx.isEmpty()) { - // keep selection - auto it = std::find_if(msgs.begin(), msgs.end(), [&](auto &m) { return m->id == selected_msg_id; }); - if (it != msgs.end()) { - for (auto &idx : prev_idx) - changePersistentIndex(idx, index(std::distance(msgs.begin(), it), idx.column())); - } + if (msgs.size() != prev_row_count) { + sortMessages(); + return; + } + for (int i = 0; i < msgs.size(); ++i) { + if (new_msgs->contains(msgs[i])) { + for (int col = 2; col < columnCount(); ++col) + emit dataChanged(index(i, col), index(i, col), {Qt::DisplayRole}); } - emit dataChanged(index(0, 0), index(msgs.size() - 1, columnCount() - 1), {Qt::DisplayRole}); } } @@ -158,6 +132,6 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { if (column != columnCount() - 1) { sort_column = column; sort_order = order; - updateState(true); + sortMessages(); } } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 450c7003b7..3a42bed4be 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -4,6 +4,7 @@ #include #include "tools/cabana/canmessages.h" + class MessageListModel : public QAbstractTableModel { Q_OBJECT @@ -14,16 +15,12 @@ public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; - void updateState(bool sort = false); void setFilterString(const QString &string); + void msgsReceived(const QHash *new_msgs = nullptr); + void sortMessages(); + QStringList msgs; private: - bool updateMessages(bool sort); - - struct Message { - QString id, name; - }; - std::vector> msgs; QString filter_str; int sort_column = 0; Qt::SortOrder sort_order = Qt::AscendingOrder; @@ -34,11 +31,11 @@ class MessagesWidget : public QWidget { public: MessagesWidget(QWidget *parent); - signals: void msgSelectionChanged(const QString &message_id); protected: QTableView *table_widget; + QString current_msg_id; MessageListModel *model; }; From 1fe45ab3c5bae9983c11a82fed04167802f75b36 Mon Sep 17 00:00:00 2001 From: Alen <3875050+alenl2@users.noreply.github.com> Date: Mon, 7 Nov 2022 23:07:40 +0100 Subject: [PATCH 0208/1179] Kia EV6: Add EU fwdCamera firmware (#26398) --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 536af7cf01..972aad0c90 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1374,6 +1374,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027', + b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', ], }, CAR.IONIQ_5: { From ed3bf4f12332556c6684141f1a8b2aed6b342ecc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 7 Nov 2022 16:39:53 -0800 Subject: [PATCH 0209/1179] onroad ui: fix opacity affecting other drawn icons (#26378) * save painter in drawIcon * fix * Update selfdrive/ui/qt/onroad.cc --- selfdrive/ui/qt/onroad.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index bfd2f44561..b4925c2f73 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -404,6 +404,7 @@ void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &t } void AnnotatedCameraWidget::drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, float opacity) { + p.setOpacity(1.0); // bg dictates opacity of ellipse p.setPen(Qt::NoPen); p.setBrush(bg); p.drawEllipse(x - radius / 2, y - radius / 2, radius, radius); From ea813a9a7dd1457899d5c1fe5ac67449c674eb0f Mon Sep 17 00:00:00 2001 From: brownspaceman Date: Mon, 7 Nov 2022 16:48:54 -0800 Subject: [PATCH 0210/1179] Subaru: add missing engine FW for 2019 Impreza (#26385) added fw for 2019 subaru impreza --- selfdrive/car/subaru/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index da5ff1785a..7a1e9a8a3d 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -196,6 +196,7 @@ FW_VERSIONS = { b'\xaa!dt\a', b'\xc5!ar\a', b'\xbe!as\a', + b'\xc5!as\x07', b'\xc5!ds\a', b'\xc5!`s\a', b'\xaa!au\a', From 1b6e37daa64c6fda8eaf0ade26d6d8c11274ef68 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 7 Nov 2022 19:51:32 -0500 Subject: [PATCH 0211/1179] Hyundai: update Ioniq 5 HDA I supported model years (#26376) * Hyundai: Add FW for 2023 Ioniq 5 HDA2 * Update values.py * Update CARS.md * Update values.py * Update CARS.md --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c347868968..7066b94f61 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -60,7 +60,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Ioniq 5 (with HDA II) 2022-23|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| -|Hyundai|Ioniq 5 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| +|Hyundai|Ioniq 5 (without HDA II) 2022-23|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 972aad0c90..4b2ef474b8 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -145,7 +145,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e), CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a), CAR.IONIQ_5: [ - HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022" , "Highway Driving Assist", harness=Harness.hyundai_k), + HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23" , "Highway Driving Assist", harness=Harness.hyundai_k), HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", harness=Harness.hyundai_q), ], CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), From e9eb5d99ff659a3f5e1b4e0bead321c469d8d889 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Mon, 7 Nov 2022 17:01:24 -0800 Subject: [PATCH 0212/1179] [torqued] Fix high speed oscillations (#26338) * modify low speed factor during high speeds and rescale friction * update refs --- selfdrive/car/interfaces.py | 2 +- selfdrive/controls/lib/latcontrol_torque.py | 8 +++++--- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 4647a04244..982ba40b17 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -23,7 +23,7 @@ TorqueFromLateralAccelCallbackType = Callable[[float, car.CarParams.LateralTorqu MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS ACCEL_MAX = 2.0 ACCEL_MIN = -3.5 -FRICTION_THRESHOLD = 0.2 +FRICTION_THRESHOLD = 0.3 TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.yaml') TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.yaml') diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 51676086ba..d10d39d945 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -17,7 +17,8 @@ from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY # friction in the steering wheel that needs to be overcome to # move it at all, this is compensated for too. -LOW_SPEED_FACTOR = 200 +LOW_SPEED_X = [0, 10, 20, 30] +LOW_SPEED_Y = [15, 13, 10, 5] class LatControlTorque(LatControl): @@ -57,8 +58,9 @@ class LatControlTorque(LatControl): actual_lateral_accel = actual_curvature * CS.vEgo ** 2 lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2 - setpoint = desired_lateral_accel + LOW_SPEED_FACTOR * desired_curvature - measurement = actual_lateral_accel + LOW_SPEED_FACTOR * actual_curvature + low_speed_factor = interp(CS.vEgo, LOW_SPEED_X, LOW_SPEED_Y)**2 + setpoint = desired_lateral_accel + low_speed_factor * desired_curvature + measurement = actual_lateral_accel + low_speed_factor * actual_curvature error = setpoint - measurement gravity_adjusted_lateral_accel = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY pid_log.error = self.torque_from_lateral_accel(error, self.torque_params, error, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 8bc13f37d4..0608a6d14b 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -24a8d02b148b7f6d20f641d56a7bed71c244b6e3 \ No newline at end of file +2991a54ea491633f93fae76da4f5f1d265ce311a \ No newline at end of file From f63f0de80a78ade6ad12fe98ea27094035d97457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 7 Nov 2022 17:49:36 -0800 Subject: [PATCH 0213/1179] E2e long model: calibrate model speed to wheel speed (#26395) * calibrate! * Fix test * Fix proc replay * check len * get v_ego from model 8501d20-bb59-4193-aa82-82b2737dedd6/449 609d90f3-65e6-4617-a60c-d6d99eead408/700 * bump cereal * initialize v_model_error * typo * better names * cleanup * bump cereal * update model replay ref commit * bump to cereal master Co-authored-by: Yassine Yousfi --- cereal | 2 +- selfdrive/controls/lib/longitudinal_planner.py | 12 ++++++++---- selfdrive/modeld/models/driving.cc | 11 +++++++++++ selfdrive/modeld/models/driving.h | 9 +++++++++ selfdrive/modeld/models/supercombo.onnx | 4 ++-- .../test/process_replay/model_replay_ref_commit | 2 +- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/cereal b/cereal index 1d25fc3f20..cdba1aafec 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 1d25fc3f202d5ddeee97848480323e9b14f9bdfa +Subproject commit cdba1aafec5e36505ef6ace675568e1f15003c47 diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 5a336d18c9..19ea40a8f4 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -58,6 +58,7 @@ class LongitudinalPlanner: self.a_desired = init_a self.v_desired_filter = FirstOrderFilter(init_v, 2.0, DT_MDL) + self.v_model_error = 0.0 self.v_desired_trajectory = np.zeros(CONTROL_N) self.a_desired_trajectory = np.zeros(CONTROL_N) @@ -68,12 +69,12 @@ class LongitudinalPlanner: e2e = self.params.get_bool('EndToEndLong') and self.CP.openpilotLongitudinalControl self.mpc.mode = 'blended' if e2e else 'acc' - def parse_model(self, model_msg): + def parse_model(self, model_msg, model_error): if (len(model_msg.position.x) == 33 and len(model_msg.velocity.x) == 33 and len(model_msg.acceleration.x) == 33): - x = np.interp(T_IDXS_MPC, T_IDXS, model_msg.position.x) - v = np.interp(T_IDXS_MPC, T_IDXS, model_msg.velocity.x) + x = np.interp(T_IDXS_MPC, T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC + v = np.interp(T_IDXS_MPC, T_IDXS, model_msg.velocity.x) - model_error a = np.interp(T_IDXS_MPC, T_IDXS, model_msg.acceleration.x) j = np.zeros(len(T_IDXS_MPC)) else: @@ -112,6 +113,9 @@ class LongitudinalPlanner: # Prevent divergence, smooth in current v_ego self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego)) + # Compute model v_ego error + if len(sm['modelV2'].temporalPose.trans): + self.v_model_error = sm['modelV2'].temporalPose.trans[0] - v_ego if force_slow_decel: # if required so, force a smooth deceleration @@ -124,7 +128,7 @@ class LongitudinalPlanner: self.mpc.set_weights(prev_accel_constraint) self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1]) self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired) - x, v, a, j = self.parse_model(sm['modelV2']) + x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error) self.mpc.update(sm['carState'], sm['radarState'], v_cruise, x, v, a, j) self.v_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.v_solution) diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index cc4a83de62..4015731c42 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -337,6 +337,17 @@ void fill_model(cereal::ModelDataV2::Builder &framed, const ModelOutput &net_out for (int i=0; i Date: Mon, 7 Nov 2022 18:25:39 -0800 Subject: [PATCH 0214/1179] [controlsd] Revert Rav4 TSS2 to PID control (#26403) * revert rav4 tss2 to pid control * Update interface.py --- selfdrive/car/toyota/interface.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 02e4caa9d6..6c360fc2c7 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -110,6 +110,19 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.3 tire_stiffness_factor = 0.7933 ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid + ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kpV = [0.6] + ret.lateralTuning.pid.kiV = [0.1] + ret.lateralTuning.pid.kf = 0.00007818594 + + # 2019+ RAV4 TSS2 uses two different steering racks and specific tuning seems to be necessary. + # See https://github.com/commaai/openpilot/pull/21429#issuecomment-873652891 + for fw in car_fw: + if fw.ecu == "eps" and (fw.fwVersion.startswith(b'\x02') or fw.fwVersion in [b'8965B42181\x00\x00\x00\x00\x00\x00']): + ret.lateralTuning.pid.kpV = [0.15] + ret.lateralTuning.pid.kiV = [0.05] + ret.lateralTuning.pid.kf = 0.00004 + break elif candidate in (CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2): stop_and_go = True From e971bb11c2170d8d6d66f430741d7234a77a0499 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 7 Nov 2022 22:14:47 -0800 Subject: [PATCH 0215/1179] Hyundai: bump safety params (#26407) * bump panda * bump panda * bump panda * update refs * bump panda * bump panda --- panda | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/test_processes.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panda b/panda index f3fc343262..ca681ff829 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit f3fc343262818801f037e9dca1a96ca99d7e64c5 +Subproject commit ca681ff8299c91491558c0e44f4a4779dc0a2998 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0608a6d14b..3120b8a7cf 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -2991a54ea491633f93fae76da4f5f1d265ce311a \ No newline at end of file +cf8700aa252d55d4d5b9f5bec136e34151c2de61 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 5c754d9312..c58909bf7f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -18,7 +18,7 @@ from tools.lib.logreader import LogReader source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY ("HYUNDAI", "02c45f73a2e5c6e9|2021-01-01--19-08-22--1"), # HYUNDAI.SONATA - ("HYUNDAI2", "d545129f3ca90f28|2022-10-19--09-22-54--9"), # HYUNDAI.KIA_EV6 + ("HYUNDAI2", "d545129f3ca90f28|2022-11-07--20-43-08--3"), # HYUNDAI.KIA_EV6 ("TOYOTA", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA.PRIUS (INDI) ("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR) ("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2 @@ -41,7 +41,7 @@ source_segments = [ segments = [ ("BODY", "regenFA002A80700|2022-09-27--15-37-02--0"), ("HYUNDAI", "regenBE53A59065B|2022-09-27--16-52-03--0"), - ("HYUNDAI2", "d545129f3ca90f28|2022-10-19--09-22-54--9"), + ("HYUNDAI2", "d545129f3ca90f28|2022-11-07--20-43-08--3"), ("TOYOTA", "regen929C5790007|2022-09-27--16-27-47--0"), ("TOYOTA2", "regenEA3950D7F22|2022-09-27--15-43-24--0"), ("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"), From d62cdc400ce5f49b22ac42d5e9b74398e7c636b6 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Tue, 8 Nov 2022 02:03:36 -0500 Subject: [PATCH 0216/1179] HKG: Car Port for Genesis GV70 2022 (#26373) * HKG: Car Port for Genesis GV70 2023 thanks to @zunichky! Co-authored-by: kyle zunich * Update docs * Update selfdrive/car/hyundai/values.py * GV70 does radar SCC, separate them * One more * bump panda * Gate 0x1A0 away from bus 6 * Can't leave out the OG * EV6 non-HDA2 too? * bump panda * bump panda * Check 0x1a0 based on param * bump panda * bump panda * bit simpler * fix bit op * fixes * bump panda to master * cmt * flip Co-authored-by: kyle zunich Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- panda | 2 +- selfdrive/car/hyundai/carstate.py | 16 +++++++++------- selfdrive/car/hyundai/interface.py | 10 +++++++++- selfdrive/car/hyundai/values.py | 17 ++++++++++++++++- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 8 files changed, 40 insertions(+), 11 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 83b3ac46f4..4103361b93 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -15,6 +15,7 @@ Version 0.8.17 (2022-XX-XX) * Added button to bookmark events while driving; view them later in comma connect * AGNOS 6 * tools: new and improved cabana thanks to deanlee! +* Genesis GV70 2022-23 support thanks to zunichky and sunnyhaibin! * Hyundai Santa Cruz 2021-22 support thanks to sunnyhaibin! * Kia Sportage 2023 support thanks to sunnyhaibin! * Kia Sportage Hybrid 2023 support thanks to sunnyhaibin! diff --git a/docs/CARS.md b/docs/CARS.md index 7066b94f61..04f7712016 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 213 Supported Cars +# 214 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -31,6 +31,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|Genesis|GV70 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| diff --git a/panda b/panda index ca681ff829..1ccdff90c5 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit ca681ff8299c91491558c0e44f4a4779dc0a2998 +Subproject commit 1ccdff90c564154489a3394691a4830a4ae19027 diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 7cf1515fda..2c309fa0df 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -200,7 +200,7 @@ class CarState(CarStateBase): self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1 if not self.CP.openpilotLongitudinalControl: speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS - cp_cruise_info = cp if self.CP.flags & HyundaiFlags.CANFD_HDA2 else cp_cam + cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) @@ -467,7 +467,7 @@ class CarState(CarStateBase): ("BLINDSPOTS_REAR_CORNERS", 20), ] - if CP.flags & HyundaiFlags.CANFD_HDA2 and not CP.openpilotLongitudinalControl: + if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl: signals += [ ("ACCMode", "SCC_CONTROL"), ("VSetDis", "SCC_CONTROL"), @@ -504,11 +504,13 @@ class CarState(CarStateBase): @staticmethod def get_cam_can_parser_canfd(CP): + signals = [] + checks = [] if CP.flags & HyundaiFlags.CANFD_HDA2: - signals = [(f"BYTE{i}", "CAM_0x2a4") for i in range(3, 24)] - checks = [("CAM_0x2a4", 20)] - else: - signals = [ + signals += [(f"BYTE{i}", "CAM_0x2a4") for i in range(3, 24)] + checks += [("CAM_0x2a4", 20)] + elif CP.flags & HyundaiFlags.CANFD_CAMERA_SCC: + signals += [ ("COUNTER", "SCC_CONTROL"), ("NEW_SIGNAL_1", "SCC_CONTROL"), ("MainMode_ACC", "SCC_CONTROL"), @@ -521,7 +523,7 @@ class CarState(CarStateBase): ("VSetDis", "SCC_CONTROL"), ] - checks = [ + checks += [ ("SCC_CONTROL", 50), ] diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 6c8d0076f1..0306f7e104 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from common.conversions import Conversions as CV -from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams +from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -44,6 +44,8 @@ class CarInterface(CarInterfaceBase): # ICE cars do not have 0x130; GEARS message on 0x40 instead if 0x130 not in fingerprint[4]: ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value + if candidate not in CANFD_RADAR_SCC_CAR: + ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value ret.steerActuatorDelay = 0.1 # Default delay ret.steerLimitTimer = 0.4 @@ -200,6 +202,10 @@ class CarInterface(CarInterfaceBase): ret.mass = 3673.0 * CV.LB_TO_KG + STD_CARGO_KG ret.wheelbase = 2.83 ret.steerRatio = 12.9 + elif candidate == CAR.GENESIS_GV70_1ST_GEN: + ret.mass = 1950. + STD_CARGO_KG + ret.wheelbase = 2.87 + ret.steerRatio = 14.6 elif candidate == CAR.GENESIS_G80: ret.mass = 2060. + STD_CARGO_KG ret.wheelbase = 3.01 @@ -244,6 +250,8 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2 if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS: ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS + if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC: + ret.safetyConfigs[1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC else: if candidate in LEGACY_SAFETY_MODE_CAR: # these cars require a special panda safety mode due to missing counters and checksums in the messages diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4b2ef474b8..e5ddc5cac7 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -48,6 +48,7 @@ class HyundaiFlags(IntFlag): CANFD_HDA2 = 1 CANFD_ALT_BUTTONS = 2 CANFD_ALT_GEARS = 4 + CANFD_CAMERA_SCC = 8 class CAR: @@ -100,6 +101,7 @@ class CAR: # Genesis GENESIS_G70 = "GENESIS G70 2018" GENESIS_G70_2020 = "GENESIS G70 2020" + GENESIS_GV70_1ST_GEN = "GENESIS GV70 1ST GEN" GENESIS_G80 = "GENESIS G80 2017" GENESIS_G90 = "GENESIS G90 2017" @@ -188,6 +190,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { # Genesis CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f), + CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l), CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2017-19", "All", harness=Harness.hyundai_h), CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness=Harness.hyundai_c), } @@ -1423,6 +1426,14 @@ FW_VERSIONS = { b'\xf1\x00NQ5__ 1.00 1.03 99110-P1000 ', ], }, + CAR.GENESIS_GV70_1ST_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00JK1_ SCC FHCUP 1.00 1.02 99110-AR000 ', + ], + }, } CHECKSUM = { @@ -1440,7 +1451,10 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN} + +# The radar does SCC on these cars when HDA I, rather than the camera +CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, } # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } @@ -1500,4 +1514,5 @@ DBC = { CAR.SANTA_CRUZ_1ST_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SPORTAGE_5TH_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None), + CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index bf949d3492..d0051454a6 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -81,6 +81,7 @@ routes = [ CarTestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS), CarTestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70), + CarTestRoute("ca4de5b12321bd98|2022-10-18--21-15-59", HYUNDAI.GENESIS_GV70_1ST_GEN), CarTestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80), CarTestRoute("f0709d2bc6ca451f|2022-10-15--08-13-54", HYUNDAI.SANTA_CRUZ_1ST_GEN), CarTestRoute("4dbd55df87507948|2022-03-01--09-45-38", HYUNDAI.SANTA_FE), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index c5a316aaaf..2ef5a1cd0f 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -34,6 +34,7 @@ HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0] HYUNDAI SANTA CRUZ 1ST GEN: [2.7, 2.7, 0.0] KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.0] KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.0] +GENESIS GV70 1ST GEN: [2.42, 2.42, 0.01] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From 52a644e6564582632559255230c82b550db50c76 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 8 Nov 2022 00:03:23 -0800 Subject: [PATCH 0217/1179] Toyota: add hysteresis to cluster speed (#26386) * add hysteresis to cluster speed * add minimum cluster scaling * fix * Update ref_commit --- selfdrive/car/toyota/carstate.py | 2 ++ selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 4758149916..a959633281 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -15,6 +15,8 @@ class CarState(CarStateBase): can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) self.shifter_values = can_define.dv["GEAR_PACKET"]["GEAR"] self.eps_torque_scale = EPS_SCALE[CP.carFingerprint] / 100. + self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2. + self.cluster_min_speed = CV.KPH_TO_MS / 2. # On cars with cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"] # the signal is zeroed to where the steering angle is at start. diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 3120b8a7cf..08eb063d41 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -cf8700aa252d55d4d5b9f5bec136e34151c2de61 \ No newline at end of file +caa8fb2a046a6c2c186e66af339212a5fae6b7a4 From 5960ba5def7c42b3944f96cf103a0c4a6e633754 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 8 Nov 2022 12:49:22 -0800 Subject: [PATCH 0218/1179] UI: widecam only in e2e mode (#26412) --- selfdrive/ui/qt/onroad.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index b4925c2f73..15672d33c1 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -567,6 +567,7 @@ void AnnotatedCameraWidget::paintGL() { } else if (v_ego > 15) { wide_cam_requested = false; } + wide_cam_requested = wide_cam_requested && s->scene.end_to_end_long; // TODO: also detect when ecam vision stream isn't available // for replay of old routes, never go to widecam wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; From 8ba9a5107b353cc0fc5ab3bbab589b70c2fe9aaa Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 8 Nov 2022 13:21:07 -0800 Subject: [PATCH 0219/1179] boardd: SPI support (#26374) * spi handle * put usb back * handle eintr Co-authored-by: Comma Device --- common/util.cc | 9 ++ common/util.h | 1 + release/files_common | 1 + selfdrive/boardd/SConscript | 4 +- selfdrive/boardd/panda.cc | 6 +- selfdrive/boardd/panda_comms.h | 22 +++ selfdrive/boardd/spi.cc | 252 +++++++++++++++++++++++++++++++ system/hardware/tici/hardware.py | 3 + 8 files changed, 295 insertions(+), 3 deletions(-) create mode 100644 selfdrive/boardd/spi.cc diff --git a/common/util.cc b/common/util.cc index b6a8322a27..010fe8a11a 100644 --- a/common/util.cc +++ b/common/util.cc @@ -1,5 +1,6 @@ #include "common/util.h" +#include #include #include @@ -149,6 +150,14 @@ int safe_fflush(FILE *stream) { return ret; } +int safe_ioctl(int fd, unsigned long request, void *argp) { + int ret; + do { + ret = ioctl(fd, request, argp); + } while ((ret == -1) && (errno == EINTR)); + return ret; +} + std::string readlink(const std::string &path) { char buff[4096]; ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1); diff --git a/common/util.h b/common/util.h index e13f4dc130..b46f7bde4a 100644 --- a/common/util.h +++ b/common/util.h @@ -86,6 +86,7 @@ int write_file(const char* path, const void* data, size_t size, int flags = O_WR FILE* safe_fopen(const char* filename, const char* mode); size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream); int safe_fflush(FILE *stream); +int safe_ioctl(int fd, unsigned long request, void *argp); std::string readlink(const std::string& path); bool file_exists(const std::string& fn); diff --git a/release/files_common b/release/files_common index 61d16a2088..26662f1ef1 100644 --- a/release/files_common +++ b/release/files_common @@ -90,6 +90,7 @@ selfdrive/boardd/boardd_api_impl.pyx selfdrive/boardd/can_list_to_can_capnp.cc selfdrive/boardd/panda.cc selfdrive/boardd/panda.h +selfdrive/boardd/spi.cc selfdrive/boardd/panda_comms.h selfdrive/boardd/panda_comms.cc selfdrive/boardd/set_time.py diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript index 356b5de663..d99e67a9f0 100644 --- a/selfdrive/boardd/SConscript +++ b/selfdrive/boardd/SConscript @@ -1,9 +1,9 @@ Import('env', 'envCython', 'common', 'cereal', 'messaging') libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj'] -env.Program('boardd', ['main.cc', 'boardd.cc', 'panda.cc', 'panda_comms.cc'], LIBS=libs) +env.Program('boardd', ['main.cc', 'boardd.cc', 'panda.cc', 'panda_comms.cc', 'spi.cc'], LIBS=libs) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"]) if GetOption('test'): - env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc', 'panda.cc', 'panda_comms.cc'], LIBS=libs) + env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc', 'panda.cc', 'panda_comms.cc', 'spi.cc'], LIBS=libs) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index e68558632e..deccee3e76 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -12,7 +12,11 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { // TODO: support SPI here one day... - handle = std::make_unique(serial); + if (serial.find("spi") != std::string::npos) { + handle = std::make_unique(serial); + } else { + handle = std::make_unique(serial); + } hw_type = get_hw_type(); diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index c5143b16b3..08d0c1a2af 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -8,6 +8,7 @@ #include #define TIMEOUT 0 +#define SPI_BUF_SIZE 1024 // comms base class @@ -49,3 +50,24 @@ private: std::vector recv_buf; void handle_usb_issue(int err, const char func[]); }; + +class PandaSpiHandle : public PandaCommsHandle { +public: + PandaSpiHandle(std::string serial); + ~PandaSpiHandle(); + int control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout=TIMEOUT); + int control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout=TIMEOUT); + int bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); + int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT); + void cleanup(); + + static std::vector list(); + +private: + int spi_fd = -1; + int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); + int wait_for_ack(); + + uint8_t tx_buf[SPI_BUF_SIZE]; + uint8_t rx_buf[SPI_BUF_SIZE]; +}; diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc new file mode 100644 index 0000000000..1ec5e89c71 --- /dev/null +++ b/selfdrive/boardd/spi.cc @@ -0,0 +1,252 @@ +#include +#include + +#include +#include + +#include "common/util.h" +#include "common/swaglog.h" +#include "selfdrive/boardd/panda_comms.h" + + +#define SPI_SYNC 0x5AU +#define SPI_HACK 0x79U +#define SPI_DACK 0x85U +#define SPI_NACK 0x1FU +#define SPI_CHECKSUM_START 0xABU + +struct __attribute__((packed)) spi_header { + uint8_t sync; + uint8_t endpoint; + uint16_t tx_len; + uint16_t max_rx_len; +}; + +struct __attribute__((packed)) spi_control_packet { + uint16_t request; + uint16_t param1; + uint16_t param2; + uint16_t length; +}; + + +PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { + LOGD("opening SPI panda: %s", serial.c_str()); + + int err; + uint32_t spi_mode = SPI_MODE_0; + uint32_t spi_speed = 30000000; + uint8_t spi_bits_per_word = 8; + + spi_fd = open(serial.c_str(), O_RDWR); + if (spi_fd < 0) { + LOGE("failed setting SPI mode %d", err); + goto fail; + } + + // SPI settings + err = util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode); + if (err < 0) { + LOGE("failed setting SPI mode %d", err); + goto fail; + } + + err = util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); + if (err < 0) { + LOGE("failed setting SPI speed"); + goto fail; + } + + err = util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word); + if (err < 0) { + LOGE("failed setting SPI bits per word"); + goto fail; + } + + return; + +fail: + cleanup(); + throw std::runtime_error("Error connecting to panda"); +} + +PandaSpiHandle::~PandaSpiHandle() { + std::lock_guard lk(hw_lock); + cleanup(); +} + +void PandaSpiHandle::cleanup() { + if (spi_fd != -1) { + close(spi_fd); + spi_fd = -1; + } +} + + + +int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout) { + int err; + + std::lock_guard lk(hw_lock); + do { + spi_control_packet packet = { + .request = request, + .param1 = param1, + .param2 = param2, + .length = 0 + }; + + // TODO: handle error + err = spi_transfer(0, (uint8_t *) &packet, sizeof(packet), NULL, 0); + } while (err < 0 && connected); + + return err; +} + +int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout) { + int err; + + std::lock_guard lk(hw_lock); + do { + spi_control_packet packet = { + .request = request, + .param1 = param1, + .param2 = param2, + .length = length + }; + + // TODO: handle error + err = spi_transfer(0, (uint8_t *) &packet, sizeof(packet), data, length); + } while (err < 0 && connected); + + return err; +} + +int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + return 0; +} + +int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + return 0; +} + +std::vector PandaSpiHandle::list() { + // TODO: list all pandas available over SPI + return {}; +} + + + +void add_checksum(uint8_t *data, int data_len) { + data[data_len] = SPI_CHECKSUM_START; + for (int i=0; i < data_len; i++) { + data[data_len] ^= data[i]; + } +} + + +int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { + int ret; + uint16_t rx_data_len; + + // needs to be less, since we need to have space for the checksum + assert(tx_len < SPI_BUF_SIZE); + assert(max_rx_len < SPI_BUF_SIZE); + + spi_header header = { + .sync = SPI_SYNC, + .endpoint = endpoint, + .tx_len = tx_len, + .max_rx_len = max_rx_len + }; + + spi_ioc_transfer transfer = { + .tx_buf = (uint64_t)tx_buf, + .rx_buf = (uint64_t)rx_buf + }; + + // Send header + memcpy(tx_buf, &header, sizeof(header)); + add_checksum(tx_buf, sizeof(header)); + transfer.len = sizeof(header) + 1; + ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to send header"); + goto transfer_fail; + } + + // Wait for (N)ACK + tx_buf[0] = 0x12; + transfer.len = 1; + while (true) { + ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to send ACK request"); + goto transfer_fail; + } + + if (rx_buf[0] == SPI_HACK) { + break; + } else if (rx_buf[0] == SPI_NACK) { + LOGW("SPI: got header NACK"); + goto transfer_fail; + } + } + + // Send data + if (tx_data != NULL) { + memcpy(tx_buf, tx_data, tx_len); + } + add_checksum(tx_buf, tx_len); + transfer.len = tx_len + 1; + ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to send data"); + goto transfer_fail; + } + + // Wait for (N)ACK + tx_buf[0] = 0xab; + transfer.len = 1; + while (true) { + ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to send ACK request"); + goto transfer_fail; + } + + if (rx_buf[0] == SPI_DACK) { + break; + } else if (rx_buf[0] == SPI_NACK) { + LOGE("SPI: got data NACK"); + goto transfer_fail; + } + } + + // Read data len + transfer.len = 2; + ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to read rx data len"); + goto transfer_fail; + } + rx_data_len = *(uint16_t *)rx_buf; + assert(rx_data_len < SPI_BUF_SIZE); + + // Read data + transfer.len = rx_data_len + 1; + ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to read rx data"); + goto transfer_fail; + } + // TODO: check checksum + + if (rx_data != NULL) { + memcpy(rx_data, rx_buf, rx_data_len); + } + ret = rx_data_len; + +transfer_fail: + return ret; +} diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index e2fd20c1be..c5b931ddae 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -431,6 +431,9 @@ class Tici(HardwareBase): def initialize_hardware(self): self.amplifier.initialize_configuration() + # TODO: this should go in AGNOS + os.system("sudo chmod 666 /dev/spidev0.0") + # Allow thermald to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") From 4ec1c7e614a2ca3fbf38f302a82b87d112d06b02 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 8 Nov 2022 22:51:16 +0100 Subject: [PATCH 0220/1179] CI: camera box update (#26414) * check if all frames are laggy * apply tolerance Co-authored-by: Kurt Nistelberger --- system/camerad/test/test_camerad.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index 3c6d466a69..6c2ef1c7bc 100755 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -11,7 +11,7 @@ from system.hardware import TICI TEST_TIMESPAN = 30 LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0321: 0.5, # ARs use synced pulses for frame starts - log.FrameData.ImageSensor.ox03c10: 1.0} # OXs react to out-of-sync at next frame + log.FrameData.ImageSensor.ox03c10: 1.0} # OXs react to out-of-sync at next frame CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState') @@ -68,12 +68,17 @@ class TestCamerad(unittest.TestCase): frame_times = {frame_id: [getattr(m, m.which()).timestampSof for m in msgs] for frame_id, msgs in self.log_by_frame_id.items()} diffs = {frame_id: (max(ts) - min(ts))/1e6 for frame_id, ts in frame_times.items()} - def get_desc(fid, diff): cam_times = [(m.which(), getattr(m, m.which()).timestampSof/1e6) for m in self.log_by_frame_id[fid]] - return f"{diff=} {cam_times=}" + return (diff, cam_times) laggy_frames = {k: get_desc(k, v) for k, v in diffs.items() if v > LAG_FRAME_TOLERANCE[sensor_type]} - assert len(laggy_frames) == 0, f"Frames not synced properly: {laggy_frames=}" + + def in_tol(diff): + return 50 - LAG_FRAME_TOLERANCE[sensor_type] < diff and diff < 50 + LAG_FRAME_TOLERANCE[sensor_type] + if len(laggy_frames) != 0 and all( in_tol(laggy_frames[lf][0]) for lf in laggy_frames): + print("TODO: handle camera out of sync") + else: + assert len(laggy_frames) == 0, f"Frames not synced properly: {laggy_frames=}" if __name__ == "__main__": unittest.main() From 1181efb288db18420e5a376ed5dba53eadf8c2cb Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 8 Nov 2022 23:01:07 +0100 Subject: [PATCH 0221/1179] CI: update qcom tests (#26404) update qcom tests Co-authored-by: Kurt Nistelberger --- tools/gpstest/test_gps_qcom.py | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/tools/gpstest/test_gps_qcom.py b/tools/gpstest/test_gps_qcom.py index 0909316c5e..b3ce93fc81 100644 --- a/tools/gpstest/test_gps_qcom.py +++ b/tools/gpstest/test_gps_qcom.py @@ -40,14 +40,10 @@ class TestGPS(unittest.TestCase): if ublox_available: raise unittest.SkipTest - @unittest.skip("Skip cold start test due to time") - def test_quectel_cold_start(self): + def test_a_quectel_cold_start(self): # delete assistance data to enforce cold start for GNSS # testing shows that this takes up to 20min - # invalidate supl setting, cannot be reset - _, err = exec_mmcli("--location-set-supl-server=unittest:1") - _, err = exec_mmcli("--command='AT+QGPSDEL=0'") assert len(err) == 0, f"GPSDEL failed: {err}" @@ -55,27 +51,6 @@ class TestGPS(unittest.TestCase): start_time = time.monotonic() glo = messaging.sub_sock("gpsLocation", timeout=0.1) - timeout = 10*60*25 # 25 minute - timedout = wait_for_location(glo, timeout) - managed_processes['rawgpsd'].stop() - - assert timedout is False, "Waiting for location timed out (25min)!" - - duration = time.monotonic() - start_time - assert duration < 50, f"Received GPS location {duration}!" - - - def test_a_quectel_cold_start_AGPS(self): - _, err = exec_mmcli("--command='AT+QGPSDEL=0'") - assert len(err) == 0, f"GPSDEL failed: {err}" - - # setup AGPS - exec_mmcli("--location-set-supl-server=supl.google.com:7276") - - managed_processes['rawgpsd'].start() - start_time = time.monotonic() - glo = messaging.sub_sock("gpsLocation", timeout=0.1) - timeout = 10*60*3 # 3 minute timedout = wait_for_location(glo, timeout) managed_processes['rawgpsd'].stop() @@ -87,15 +62,11 @@ class TestGPS(unittest.TestCase): def test_b_quectel_startup(self): - - # setup AGPS - exec_mmcli("--location-set-supl-server=supl.google.com:7276") - managed_processes['rawgpsd'].start() start_time = time.monotonic() glo = messaging.sub_sock("gpsLocation", timeout=0.1) - timeout = 10*60*3 # 3 minute + timeout = 10*60 # 1 minute timedout = wait_for_location(glo, timeout) managed_processes['rawgpsd'].stop() From 9a3f46805104c4bcb5cffa304b9b322874ccf412 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 8 Nov 2022 14:45:01 -0800 Subject: [PATCH 0222/1179] experimental mode (#26416) * experimental mode * rename param * red lights --- RELEASES.md | 8 +++- common/params.cc | 2 +- selfdrive/controls/controlsd.py | 2 +- .../controls/lib/longitudinal_planner.py | 2 +- selfdrive/controls/tests/test_cruise_speed.py | 2 +- .../controls/tests/test_following_distance.py | 2 +- .../test_longitudinal.py | 4 +- selfdrive/ui/qt/offroad/settings.cc | 41 +++++++++++-------- selfdrive/ui/qt/onroad.cc | 4 +- selfdrive/ui/translations/main_ja.ts | 24 +++++------ selfdrive/ui/translations/main_ko.ts | 24 +++++------ selfdrive/ui/translations/main_pt-BR.ts | 24 +++++------ selfdrive/ui/translations/main_zh-CHS.ts | 24 +++++------ selfdrive/ui/translations/main_zh-CHT.ts | 24 +++++------ selfdrive/ui/ui.cc | 2 +- selfdrive/ui/ui.h | 2 +- 16 files changed, 101 insertions(+), 90 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 4103361b93..e175050eaf 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,9 +1,13 @@ -Version 0.8.17 (2022-XX-XX) +Version 0.8.17 (2022-11-XX) ======================== * New driving model * Internal feature space accuracy increased tenfold during training, this makes the model dramatically more accurate. * New driver monitoring model * New end-to-end distracted trigger +* Experimental driving mode + * End-to-end longitudinal control + * Stops for red lights and stop signs + * openpilot defaults to chill mode, enable experimental in settings * Self-tuning torque lateral controller parameters * Parameters learned live for each car * Torque controller used on all Toyota, Lexus, Hyundai, Kia, and Genesis models @@ -12,7 +16,7 @@ Version 0.8.17 (2022-XX-XX) * Matched speeds shown on car's dash * Improved update experience * Border turns grey while overriding steering - * Added button to bookmark events while driving; view them later in comma connect + * Bookmark events while driving; view them in comma connect * AGNOS 6 * tools: new and improved cabana thanks to deanlee! * Genesis GV70 2022-23 support thanks to zunichky and sunnyhaibin! diff --git a/common/params.cc b/common/params.cc index 155bc88487..e17d1f1b13 100644 --- a/common/params.cc +++ b/common/params.cc @@ -102,7 +102,7 @@ std::unordered_map keys = { {"DashcamOverride", PERSISTENT}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisablePowerDown", PERSISTENT}, - {"EndToEndLong", PERSISTENT}, + {"ExperimentalMode", PERSISTENT}, {"ExperimentalLongitudinalEnabled", PERSISTENT}, // WARNING: THIS MAY DISABLE AEB {"DisableUpdates", PERSISTENT}, {"DisengageOnAccelerator", PERSISTENT}, diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 1adbba4171..0bdaadf6ef 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -147,7 +147,7 @@ class Controls: if not self.CP.experimentalLongitudinalAvailable: self.params.remove("ExperimentalLongitudinalEnabled") if not self.CP.openpilotLongitudinalControl: - self.params.remove("EndToEndLong") + self.params.remove("ExperimentalMode") self.CC = car.CarControl.new_message() self.CS_prev = car.CarState.new_message() diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 19ea40a8f4..2fa13bfb15 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -66,7 +66,7 @@ class LongitudinalPlanner: self.solverExecutionTime = 0.0 def read_param(self): - e2e = self.params.get_bool('EndToEndLong') and self.CP.openpilotLongitudinalControl + e2e = self.params.get_bool('ExperimentalMode') and self.CP.openpilotLongitudinalControl self.mpc.mode = 'blended' if e2e else 'acc' def parse_model(self, model_msg, model_error): diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index a972bfb073..ca070f1c3f 100644 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -26,7 +26,7 @@ class TestCruiseSpeed(unittest.TestCase): def test_cruise_speed(self): params = Params() for e2e in [False, True]: - params.put_bool("EndToEndLong", e2e) + params.put_bool("ExperimentalMode", e2e) for speed in np.arange(5, 40, 5): print(f'Testing {speed} m/s') cruise_speed = float(speed) diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py index 3534f58235..0535caab84 100644 --- a/selfdrive/controls/tests/test_following_distance.py +++ b/selfdrive/controls/tests/test_following_distance.py @@ -27,7 +27,7 @@ class TestFollowingDistance(unittest.TestCase): def test_following_distance(self): params = Params() for e2e in [False, True]: - params.put_bool("EndToEndLong", e2e) + params.put_bool("ExperimentalMode", e2e) for speed in np.arange(0, 40, 5): print(f'Testing {speed} m/s') v_lead = float(speed) diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py index c7c2915878..7cc95b104a 100755 --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -143,11 +143,11 @@ def run_maneuver_worker(k): params = Params() man = maneuvers[k] - params.put_bool("EndToEndLong", True) + params.put_bool("ExperimentalMode", True) print(man.title, ' in e2e mode') valid, _ = man.evaluate() self.assertTrue(valid, msg=man.title) - params.put_bool("EndToEndLong", False) + params.put_bool("ExperimentalMode", False) print(man.title, ' in acc mode') valid, _ = man.evaluate() self.assertTrue(valid, msg=man.title) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 51b5ce6bd7..29069155b2 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -36,6 +36,21 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "../assets/offroad/icon_openpilot.png", false, }, + { + "ExperimentalMode", + tr("Experimental mode"), + "", + "../assets/offroad/icon_road.png", + false, + }, + { + "ExperimentalLongitudinalEnabled", + tr("Experimental openpilot longitudinal control"), + tr("WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.
\ + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control."), + "../assets/offroad/icon_speed_limit.png", + true, + }, { "IsLdwEnabled", tr("Enable Lane Departure Warnings"), @@ -64,20 +79,6 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "../assets/offroad/icon_disengage_on_accelerator.svg", false, }, - { - "EndToEndLong", - tr("🌮 End-to-end longitudinal (extremely alpha) 🌮"), - "", - "../assets/offroad/icon_road.png", - false, - }, - { - "ExperimentalLongitudinalEnabled", - tr("Experimental openpilot longitudinal control"), - tr("WARNING: openpilot longitudinal control is experimental for this car and will disable AEB."), - "../assets/offroad/icon_speed_limit.png", - true, - }, #ifdef ENABLE_MAPS { "NavSettingTime24h", @@ -116,9 +117,15 @@ void TogglesPanel::showEvent(QShowEvent *event) { } void TogglesPanel::updateToggles() { - auto e2e_toggle = toggles["EndToEndLong"]; + auto e2e_toggle = toggles["ExperimentalMode"]; auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"]; - const QString e2e_description = tr("Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental."); + const QString e2e_description = tr("\ + openpilot defaults to driving in chill mode.\ + Experimental mode enables alpha-level features that aren't ready for chill mode. \ + Experimental features are listed below:\ +
\ +

🌮 End-to-End Longitudinal Control 🌮

\ + 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."); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { @@ -140,7 +147,7 @@ void TogglesPanel::updateToggles() { } else { // no long for now e2e_toggle->setEnabled(false); - params.remove("EndToEndLong"); + params.remove("ExperimentalMode"); const QString no_long = tr("openpilot longitudinal control is not currently available for this car."); const QString exp_long = tr("Enable experimental longitudinal control to enable this."); diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 15672d33c1..37c1913743 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -461,7 +461,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { // paint path QLinearGradient bg(0, height(), 0, height() / 4); float start_hue, end_hue; - if (scene.end_to_end_long) { + if (scene.experimental_mode) { const auto &acceleration = (*s->sm)["modelV2"].getModelV2().getAcceleration(); float acceleration_future = 0; if (acceleration.getZ().size() > 16) { @@ -567,7 +567,7 @@ void AnnotatedCameraWidget::paintGL() { } else if (v_ego > 15) { wide_cam_requested = false; } - wide_cam_requested = wide_cam_requested && s->scene.end_to_end_long; + wide_cam_requested = wide_cam_requested && s->scene.experimental_mode; // TODO: also detect when ecam vision stream isn't available // for replay of old routes, never go to widecam wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 5ee2d86756..039ad7b2a4 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -966,22 +966,10 @@ location set Upload data from the driver facing camera and help improve the driver monitoring algorithm. 車内カメラの映像をアップロードし、ドライバー監視システムのアルゴリズムの向上に役立てます。 - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 エンドツーエンドのアクセル制御 (超α版) 🌮 - Experimental openpilot longitudinal control 実験段階のopenpilotによるアクセル制御 - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - <b>警告: openpilotによるアクセル制御は実験段階であり、AEBを無効化します。</b> - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - アクセルとブレーキの制御をopenpilotに任せます。openpilotが人間と同じように運転します。最初期の実験段階です。 - openpilot longitudinal control is not currently available for this car. openpilotによるアクセル制御は、この車では現在利用できません。 @@ -1014,6 +1002,18 @@ location set Show map on left side when in split screen view. 分割画面表示の場合、ディスプレイの左側にマップを表示します。 + + Experimental mode + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + + + + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + +
Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index f58c4f34d5..e9b4943650 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -966,22 +966,10 @@ location set Upload data from the driver facing camera and help improve the driver monitoring algorithm. 운전자 카메라에서 데이터를 업로드하고 운전자 모니터링 알고리즘을 개선합니다. - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 e2e 롱컨트롤 사용 (매우 실험적) 🌮 - Experimental openpilot longitudinal control openpilot 롱컨트롤 (실험적) - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - <b>경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 AEB를 비활성화합니다.</b> - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - 주행모델이 가속과 감속을 제어하도록 하면 openpilot은 운전자가 생각하는것처럼 운전합니다. (매우 실험적) - openpilot longitudinal control is not currently available for this car. 현재 이 차량에는 openpilot 롱컨트롤을 사용할 수 없습니다. @@ -1014,6 +1002,18 @@ location set Show map on left side when in split screen view. 분할 화면 보기에서 지도를 왼쪽에 표시합니다. + + Experimental mode + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + + + + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 6774555b73..a5187af50f 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -970,22 +970,10 @@ trabalho definido Upload data from the driver facing camera and help improve the driver monitoring algorithm. Upload dados da câmera voltada para o motorista e ajude a melhorar o algoritmo de monitoramentor. - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 End-to-end longitudinal (experimental) 🌮 - Experimental openpilot longitudinal control Controle longitudinal experimental openpilot - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - <b>AVISO: o controle longitudinal openpilot é experimental para este carro e irá desabilitar AEB.</b> - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - Deixe o modelo controlar o acelerador e os freios. openpilot irá conduzir como pensa que um humano faria. Super experimental. - openpilot longitudinal control is not currently available for this car. controle longitudinal openpilot não está disponível para este carro. @@ -1018,6 +1006,18 @@ trabalho definido Show map on left side when in split screen view. Exibir mapa do lado esquerdo quando a tela for dividida. + + Experimental mode + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + + + + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 6189a235e8..44e707e49c 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -964,22 +964,10 @@ location set Upload data from the driver facing camera and help improve the driver monitoring algorithm. 上传驾驶员摄像头的数据,帮助改进驾驶员监控算法。 - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 端对端纵向控制(实验性功能) 🌮 - Experimental openpilot longitudinal control - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - 让驾驶模型直接控制油门和刹车,openpilot将会模仿人类司机的驾驶方式。该功能仍非常实验性。 - openpilot longitudinal control is not currently available for this car. @@ -1012,6 +1000,18 @@ location set Show map on left side when in split screen view. 在分屏模式中,将地图置于屏幕左侧。 + + Experimental mode + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + + + + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 0b0dbe4ae5..274cff3a5a 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -966,22 +966,10 @@ location set Upload data from the driver facing camera and help improve the driver monitoring algorithm. 上傳駕駛監控的錄像來協助我們提升駕駛監控的準確率。 - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 端對端縱向控制(實驗性功能) 🌮 - Experimental openpilot longitudinal control 使用 openpilot 縱向控制(實驗) - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - <b>注意:這台車的 openpilot 縱向控制仍然是實驗中的功能,開啟這功能將會關閉自動緊急煞車 (AEB)。</b> - - - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - 讓駕駛模型直接控製油門和剎車,openpilot將會模仿人類司機的駕駛方式。該功能仍非常實驗性。 - openpilot longitudinal control is not currently available for this car. openpilot 縱向控制目前不適用於這輛車。 @@ -1014,6 +1002,18 @@ location set Show map on left side when in split screen view. 進入分割畫面後,地圖將會顯示在畫面的左側。 + + Experimental mode + + + + <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + + + + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + + Updater diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 945218ec11..970448359e 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -174,7 +174,7 @@ void ui_update_params(UIState *s) { auto params = Params(); s->scene.is_metric = params.getBool("IsMetric"); s->scene.map_on_left = params.getBool("NavSettingLeftSide"); - s->scene.end_to_end_long = params.getBool("EndToEndLong"); + s->scene.experimental_mode = params.getBool("ExperimentalMode"); } void UIState::updateStatus() { diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index e550afd5f2..38e2ffe3ce 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -104,7 +104,7 @@ typedef struct UIScene { QPointF lead_vertices[2]; float light_sensor; - bool started, ignition, is_metric, map_on_left, longitudinal_control, end_to_end_long; + bool started, ignition, is_metric, map_on_left, longitudinal_control, experimental_mode; uint64_t started_frame; } UIScene; From 191b8081b2a9f3f9db0131edd270e40166570cfa Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 8 Nov 2022 20:52:35 -0800 Subject: [PATCH 0223/1179] GM Camera: use ECM brake pressed bit (#26400) * GM camera: use ECM brake pressed bit * bump panda and use more reliable bit * bump panda * back to ECMEngineStatus * bump * Update selfdrive/car/gm/carstate.py * bump panda * Update ref_commit --- panda | 2 +- selfdrive/car/gm/carstate.py | 14 +++++++++----- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/panda b/panda index 1ccdff90c5..281eb7731b 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 1ccdff90c564154489a3394691a4830a4ae19027 +Subproject commit 281eb7731b4338fef049977593fdf3315adf09e9 diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index af69307a2c..f4b3f88e99 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -51,12 +51,15 @@ class CarState(CarStateBase): else: ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(pt_cp.vl["ECMPRDNL2"]["PRNDL2"], None)) - # Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe - # that the brake is being intermittently pressed without user interaction. - # To avoid a cruise fault we need to match the ECM's brake pressed signal and threshold - # https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"] - ret.brakePressed = ret.brake >= 8 + if self.CP.networkLocation == NetworkLocation.fwdCamera: + ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0 + else: + # Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe + # that the brake is being intermittently pressed without user interaction. + # To avoid a cruise fault we need to use a conservative brake position threshold + # https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf + ret.brakePressed = ret.brake >= 8 # Regen braking is braking if self.CP.transmissionType == TransmissionType.direct: @@ -154,6 +157,7 @@ class CarState(CarStateBase): ("TractionControlOn", "ESPStatus"), ("ParkBrake", "VehicleIgnitionAlt"), ("CruiseMainOn", "ECMEngineStatus"), + ("BrakePressed", "ECMEngineStatus"), ] checks = [ diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 08eb063d41..da954d76a6 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -caa8fb2a046a6c2c186e66af339212a5fae6b7a4 +372a67c524342bbf15e22f0caea08d2038973281 From 9f1fe1193c4779f692028e1b054d4c76b6e55119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 8 Nov 2022 21:57:01 -0800 Subject: [PATCH 0224/1179] Update RELEASES.md --- RELEASES.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index e175050eaf..18817bda4d 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,7 +1,11 @@ Version 0.8.17 (2022-11-XX) ======================== * New driving model - * Internal feature space accuracy increased tenfold during training, this makes the model dramatically more accurate. + * Internal feature space information content increased tenfold during training (to ~700 bits), this makes the model dramatically more accurate + * Less reliance on previous frames makes model more reactive and snappy + * Trained in new reprojective simulator + * Model trained in openpilot was trained in 36hrs from scratch, compared to around 1 week of previous releases + * Model training now simulates lateral and longitudinal behavior, this allows openpilot to slow down for turns, stop at traffic lights, etc,... in experimental mode * New driver monitoring model * New end-to-end distracted trigger * Experimental driving mode From 34f580e75ee148398e6a44980053c20bf10f9797 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 9 Nov 2022 04:55:37 -0500 Subject: [PATCH 0225/1179] VW PQ: Fix exception with openpilot longitudinal (#26417) * VW PQ: Fix exception in long control * move default value to init --- selfdrive/car/volkswagen/carstate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index d09420cf7a..def14ab019 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -12,6 +12,7 @@ class CarState(CarStateBase): super().__init__(CP) self.CCP = CarControllerParams(CP) self.button_states = {button.event_type: False for button in self.CCP.BUTTONS} + self.esp_hold_confirmation = False def create_button_events(self, pt_cp, buttons): button_events = [] From fc872271ae73a0139be6b085b90467c2e8d83c66 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 10 Nov 2022 03:10:57 +0800 Subject: [PATCH 0226/1179] Cabana: add menu bar to main window (#26419) * add menu bar * show DBC name in title * cleanup --- tools/cabana/chartswidget.cc | 1 + tools/cabana/mainwin.cc | 197 ++++++++++++++--------------------- tools/cabana/mainwin.h | 36 ++----- 3 files changed, 87 insertions(+), 147 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index b4d6d89e6d..812a805810 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -14,6 +14,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d3d7ff4156..9b85ba7e8d 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -1,14 +1,17 @@ #include "tools/cabana/mainwin.h" #include +#include #include -#include #include #include #include #include -#include +#include +#include +#include #include +#include #include #include "tools/replay/util.h" @@ -18,15 +21,13 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const if (main_win) emit main_win->showMessage(msg, 0); } -MainWindow::MainWindow() : QWidget() { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(11, 11, 11, 5); +MainWindow::MainWindow() : QMainWindow() { + setWindowTitle("Cabana"); + QWidget *central_widget = new QWidget(this); + QHBoxLayout *main_layout = new QHBoxLayout(central_widget); + main_layout->setContentsMargins(11, 11, 11, 0); main_layout->setSpacing(0); - QHBoxLayout *h_layout = new QHBoxLayout(); - h_layout->setContentsMargins(0, 0, 0, 0); - main_layout->addLayout(h_layout); - splitter = new QSplitter(Qt::Horizontal, this); splitter->setHandleWidth(11); @@ -34,7 +35,6 @@ MainWindow::MainWindow() : QWidget() { QWidget *messages_container = new QWidget(this); QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); messages_layout->setContentsMargins(0, 0, 0, 0); - QHBoxLayout *dbc_file_layout = new QHBoxLayout(); dbc_combo = new QComboBox(this); auto dbc_names = dbc()->allDBCNames(); for (const auto &name : dbc_names) { @@ -42,21 +42,9 @@ MainWindow::MainWindow() : QWidget() { } 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); - 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); - dbc_file_layout->addWidget(save_btn); - messages_layout->addLayout(dbc_file_layout); + messages_layout->addWidget(dbc_combo); messages_widget = new MessagesWidget(this); messages_layout->addWidget(messages_widget); @@ -65,8 +53,7 @@ MainWindow::MainWindow() : QWidget() { charts_widget = new ChartsWidget(this); detail_widget = new DetailWidget(charts_widget, this); splitter->addWidget(detail_widget); - - h_layout->addWidget(splitter); + main_layout->addWidget(splitter); // right widgets QWidget *right_container = new QWidget(this); @@ -74,35 +61,21 @@ MainWindow::MainWindow() : QWidget() { r_layout = new QVBoxLayout(right_container); r_layout->setContentsMargins(11, 0, 0, 0); QHBoxLayout *right_hlayout = new QHBoxLayout(); - QLabel *fingerprint_label = new QLabel(this); - right_hlayout->addWidget(fingerprint_label); + fingerprint_label = new QLabel(this); + right_hlayout->addWidget(fingerprint_label, 0, Qt::AlignLeft); // TODO: click to select another route. - right_hlayout->addWidget(new QLabel(can->route())); - QPushButton *settings_btn = new QPushButton("Settings"); - right_hlayout->addWidget(settings_btn, 0, Qt::AlignRight); - + right_hlayout->addWidget(new QLabel(can->route()), 0, Qt::AlignRight); r_layout->addLayout(right_hlayout); video_widget = new VideoWidget(this); r_layout->addWidget(video_widget, 0, Qt::AlignTop); - r_layout->addWidget(charts_widget); + main_layout->addWidget(right_container); - h_layout->addWidget(right_container); - - // status bar - status_bar = new QStatusBar(this); - status_bar->setFixedHeight(20); - status_bar->setContentsMargins(0, 0, 0, 0); - status_bar->setSizeGripEnabled(true); - progress_bar = new QProgressBar(); - progress_bar->setRange(0, 100); - progress_bar->setTextVisible(true); - progress_bar->setFixedSize({230, 16}); - progress_bar->setVisible(false); - status_bar->addPermanentWidget(progress_bar); - main_layout->addWidget(status_bar); + setCentralWidget(central_widget); + createActions(); + createStatusBar(); qRegisterMetaType("uint64_t"); qRegisterMetaType("ReplyMsgType"); @@ -122,35 +95,65 @@ MainWindow::MainWindow() : QWidget() { } QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); - QObject::connect(load_from_paste, &QPushButton::clicked, this, &MainWindow::loadDBCFromPaste); - QObject::connect(save_btn, &QPushButton::clicked, this, &MainWindow::saveDBC); - QObject::connect(this, &MainWindow::showMessage, status_bar, &QStatusBar::showMessage); + QObject::connect(this, &MainWindow::showMessage, statusBar(), &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); - QObject::connect(settings_btn, &QPushButton::clicked, this, &MainWindow::setOption); QObject::connect(can, &CANMessages::streamStarted, this, &MainWindow::loadDBCFromFingerprint); - QObject::connect(can, &CANMessages::streamStarted, [=]() { fingerprint_label->setText(can->carFingerprint() ); }); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { + dbc_combo->setCurrentText(QFileInfo(dbc()->name()).baseName()); + setWindowTitle(tr("%1 - Cabana").arg(dbc()->name())); + }); +} + +void MainWindow::createActions() { + QMenu *file_menu = menuBar()->addMenu(tr("&File")); + file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::loadDBCFromFile); + file_menu->addAction(tr("Load DBC From Clipboard"), this, &MainWindow::loadDBCFromClipboard); + file_menu->addSeparator(); + file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveDBCToFile); + file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveDBCToClipboard); + file_menu->addSeparator(); + file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption); + QMenu *help_menu = menuBar()->addMenu(tr("&Help")); + help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); +} + +void MainWindow::createStatusBar() { + progress_bar = new QProgressBar(); + progress_bar->setRange(0, 100); + progress_bar->setTextVisible(true); + progress_bar->setFixedSize({230, 16}); + progress_bar->setVisible(false); + statusBar()->addPermanentWidget(progress_bar); } void MainWindow::loadDBCFromName(const QString &name) { - if (name != dbc()->name()) { + if (name != dbc()->name()) dbc()->open(name); - dbc_combo->setCurrentText(name); +} + +void MainWindow::loadDBCFromFile() { + QString file_name = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::homePath(), "DBC (*.dbc)"); + if (!file_name.isEmpty()) { + QFile file(file_name); + if (file.open(QIODevice::ReadOnly)) { + auto dbc_name = QFileInfo(file_name).baseName(); + dbc()->open(dbc_name, file.readAll()); + } } } -void MainWindow::loadDBCFromPaste() { - LoadDBCDialog dlg(this); - if (dlg.exec()) { - dbc()->open("from paste", dlg.dbc_edit->toPlainText()); - dbc_combo->setCurrentText("loaded from paste"); - } +void MainWindow::loadDBCFromClipboard() { + QString dbc_str = QGuiApplication::clipboard()->text(); + dbc()->open("From Clipboard", dbc_str); + QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); } void MainWindow::loadDBCFromFingerprint() { auto fingerprint = can->carFingerprint(); + fingerprint_label->setText(fingerprint); if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { @@ -159,14 +162,23 @@ void MainWindow::loadDBCFromFingerprint() { } } -void MainWindow::saveDBC() { - SaveDBCDialog dlg(this); - dlg.dbc_edit->setText(dbc()->generateDBC()); - dlg.exec(); +void MainWindow::saveDBCToFile() { + QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), + QDir::homePath() + "/untitled.dbc", tr("DBC (*.dbc)")); + if (!file_name.isEmpty()) { + QFile file(file_name); + if (file.open(QIODevice::WriteOnly)) + file.write(dbc()->generateDBC().toUtf8()); + } +} + +void MainWindow::saveDBCToClipboard() { + QGuiApplication::clipboard()->setText(dbc()->generateDBC()); + QMessageBox::information(this, tr("Copy To Clipboard"), tr("DBC Successfully copied!")); } void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool success) { - if (success && cur < total) { + if (success && cur < total) { progress_bar->setValue((cur / (double)total) * 100); progress_bar->setFormat(tr("Downloading %p% (%1)").arg(formattedDataSize(total).c_str())); progress_bar->show(); @@ -202,60 +214,3 @@ void MainWindow::setOption() { SettingsDlg dlg(this); dlg.exec(); } - -// LoadDBCDialog - -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); - - setMinimumSize({640, 480}); - QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -// SaveDBCDialog - -SaveDBCDialog::SaveDBCDialog(QWidget *parent) : QDialog(parent) { - setWindowTitle(tr("Save DBC")); - QVBoxLayout *main_layout = new QVBoxLayout(this); - dbc_edit = new QTextEdit(this); - dbc_edit->setAcceptRichText(false); - main_layout->addWidget(dbc_edit); - - QPushButton *copy_to_clipboard = new QPushButton(tr("Copy To Clipboard"), this); - QPushButton *save_as = new QPushButton(tr("Save As"), this); - - QHBoxLayout *btn_layout = new QHBoxLayout(); - btn_layout->addStretch(); - btn_layout->addWidget(copy_to_clipboard); - btn_layout->addWidget(save_as); - main_layout->addLayout(btn_layout); - setMinimumSize({640, 480}); - - QObject::connect(copy_to_clipboard, &QPushButton::clicked, this, &SaveDBCDialog::copytoClipboard); - QObject::connect(save_as, &QPushButton::clicked, this, &SaveDBCDialog::saveAs); -} - -void SaveDBCDialog::copytoClipboard() { - dbc_edit->selectAll(); - dbc_edit->copy(); - QDialog::accept(); -} - -void SaveDBCDialog::saveAs() { - QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), - QDir::homePath() + "/untitled.dbc", tr("DBC (*.dbc)")); - if (!file_name.isEmpty()) { - QFile file(file_name); - if (file.open(QIODevice::WriteOnly)) { - file.write(dbc_edit->toPlainText().toUtf8()); - } - QDialog::accept(); - } -} diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index f6853a5ea3..bb9280c3ea 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,37 +1,40 @@ #pragma once #include -#include #include +#include #include #include #include -#include #include "tools/cabana/chartswidget.h" #include "tools/cabana/detailwidget.h" #include "tools/cabana/messageswidget.h" #include "tools/cabana/videowidget.h" -class MainWindow : public QWidget { +class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); void dockCharts(bool dock); - void showStatusMessage(const QString &msg, int timeout = 0) { status_bar->showMessage(msg, timeout); } + void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); } public slots: void loadDBCFromName(const QString &name); void loadDBCFromFingerprint(); - void loadDBCFromPaste(); - void saveDBC(); + void loadDBCFromFile(); + void loadDBCFromClipboard(); + void saveDBCToFile(); + void saveDBCToClipboard(); signals: void showMessage(const QString &msg, int timeout); void updateProgressBar(uint64_t cur, uint64_t total, bool success); protected: + void createActions(); + void createStatusBar(); void closeEvent(QCloseEvent *event) override; void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); @@ -44,26 +47,7 @@ protected: QWidget *floating_window = nullptr; QVBoxLayout *r_layout; QProgressBar *progress_bar; - QStatusBar *status_bar; + QLabel *fingerprint_label; QJsonDocument fingerprint_to_dbc; QComboBox *dbc_combo; }; - - -class LoadDBCDialog : public QDialog { - Q_OBJECT - -public: - LoadDBCDialog(QWidget *parent); - QTextEdit *dbc_edit; -}; - -class SaveDBCDialog : public QDialog { - Q_OBJECT - -public: - SaveDBCDialog(QWidget *parent); - void copytoClipboard(); - void saveAs(); - QTextEdit *dbc_edit; -}; From c64e2c228a57dd82685f9ca4251c49e953e1ac69 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 9 Nov 2022 12:09:55 -0800 Subject: [PATCH 0227/1179] [controlsd] Toyota Rav4 TSS2 bugfix (#26421) bugfix toyota rav4 pid init values --- selfdrive/car/toyota/interface.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 6c360fc2c7..3f4edb36d2 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -111,6 +111,8 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.7933 ret.mass = 3585. * CV.LB_TO_KG + STD_CARGO_KG # Average between ICE and Hybrid ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kiBP = [0.0] + ret.lateralTuning.pid.kpBP = [0.0] ret.lateralTuning.pid.kpV = [0.6] ret.lateralTuning.pid.kiV = [0.1] ret.lateralTuning.pid.kf = 0.00007818594 From 0ca9d1810c39d96ec0ebefc80df16dd68eb3387e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 12:10:08 -0800 Subject: [PATCH 0228/1179] interrfaces: more complete PID tests (#26422) * more complete PID tests * doesn't need to be fancy * less fancy --- selfdrive/car/tests/test_car_interfaces.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index aabf652c8c..8d22173671 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -34,15 +34,18 @@ class TestCarInterfaces(unittest.TestCase): self.assertGreater(car_params.maxLateralAccel, 0) if car_params.steerControlType != car.CarParams.SteerControlType.angle: - tuning = car_params.lateralTuning.which() - if tuning == 'pid': - self.assertTrue(len(car_params.lateralTuning.pid.kpV)) - elif tuning == 'torque': - kf = car_params.lateralTuning.torque.kf - self.assertTrue(not math.isnan(kf) and kf > 0) - self.assertTrue(not math.isnan(car_params.lateralTuning.torque.friction)) - elif tuning == 'indi': - self.assertTrue(len(car_params.lateralTuning.indi.outerLoopGainV)) + tune = car_params.lateralTuning + if tune.which() == 'pid': + self.assertTrue(not math.isnan(tune.pid.kf) and tune.pid.kf > 0) + self.assertTrue(len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)) + self.assertTrue(len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)) + + elif tune.which() == 'torque': + self.assertTrue(not math.isnan(tune.torque.kf) and tune.torque.kf > 0) + self.assertTrue(not math.isnan(tune.torque.friction)) + + elif tune.which() == 'indi': + self.assertTrue(len(tune.indi.outerLoopGainV)) # Run car interface CC = car.CarControl.new_message() From 59bf2fc0085420b13b7854d1a106c1706d7df265 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 10 Nov 2022 06:19:11 +0800 Subject: [PATCH 0229/1179] Cabana: support deleting message (#26418) delete message --- tools/cabana/chartswidget.cc | 8 ++++-- tools/cabana/dbcmanager.cc | 35 +++++++++++++++++--------- tools/cabana/dbcmanager.h | 5 +++- tools/cabana/detailwidget.cc | 46 +++++++++++++++++++++------------- tools/cabana/detailwidget.h | 5 +++- tools/cabana/messageswidget.cc | 9 ++++--- 6 files changed, 72 insertions(+), 36 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 812a805810..3a170bccdc 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -45,9 +45,13 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { 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::msgUpdated, [this](const QString &msg_id) { + 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 (c->id == msg_id) c->updateTitle(); + if (DBCManager::parseId(c->id).second == address) c->updateTitle(); } }); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 3ddcf41788..184fab38eb 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -10,23 +10,23 @@ DBCManager::~DBCManager() {} void DBCManager::open(const QString &dbc_file_name) { dbc = const_cast(dbc_lookup(dbc_file_name.toStdString())); - msg_map.clear(); - for (auto &msg : dbc->msgs) { - msg_map[msg.address] = &msg; - } + updateMsgMap(); emit DBCFileChanged(); } void DBCManager::open(const QString &name, const QString &content) { 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; - } + updateMsgMap(); emit DBCFileChanged(); } +void DBCManager::updateMsgMap() { + msg_map.clear(); + for (auto &msg : dbc->msgs) + msg_map[msg.address] = &msg; +} + QString DBCManager::generateDBC() { if (!dbc) return {}; @@ -49,14 +49,25 @@ QString DBCManager::generateDBC() { } void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size) { - if (auto m = const_cast(msg(id))) { + auto [bus, address] = parseId(id); + if (auto m = const_cast(msg(address))) { m->name = name.toStdString(); m->size = size; } else { - m = &dbc->msgs.emplace_back(Msg{.address = parseId(id).second, .name = name.toStdString(), .size = size}); - msg_map[m->address] = m; + m = &dbc->msgs.emplace_back(Msg{.address = address, .name = name.toStdString(), .size = size}); + msg_map[address] = m; + } + emit msgUpdated(address); +} + +void DBCManager::removeMsg(const QString &id) { + uint32_t address = parseId(id).second; + auto it = std::find_if(dbc->msgs.begin(), dbc->msgs.end(), [address](auto &m) { return m.address == address; }); + if (it != dbc->msgs.end()) { + dbc->msgs.erase(it); + updateMsgMap(); + emit msgRemoved(address); } - emit msgUpdated(id); } void DBCManager::addSignal(const QString &id, const Signal &sig) { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index cbe4531d2a..2b6aca41d7 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -23,6 +23,7 @@ public: inline QString name() const { return dbc ? dbc->name.c_str() : ""; } void updateMsg(const QString &id, const QString &name, uint32_t size); + void removeMsg(const QString &id); inline const DBC *getDBC() const { return dbc; } inline const Msg *msg(const QString &id) const { return msg(parseId(id).second); } inline const Msg *msg(uint32_t address) const { @@ -34,10 +35,12 @@ signals: void signalAdded(const Signal *sig); void signalRemoved(const Signal *sig); void signalUpdated(const Signal *sig); - void msgUpdated(const QString &id); + void msgUpdated(uint32_t address); + void msgRemoved(uint32_t address); void DBCFileChanged(); private: + void updateMsgMap(); DBC *dbc = nullptr; std::unordered_map msg_map; }; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 18510c86ea..287c75a617 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -33,20 +33,21 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart title_frame->setFrameShape(QFrame::StyledPanel); // message title - QHBoxLayout *title_layout = new QHBoxLayout(); - title_layout->addWidget(new QLabel("time:")); + toolbar = new QToolBar(this); + toolbar->addWidget(new QLabel("time:")); time_label = new QLabel(this); time_label->setStyleSheet("font-weight:bold"); - title_layout->addWidget(time_label); - title_layout->addStretch(); + toolbar->addWidget(time_label); name_label = new QLabel(this); name_label->setStyleSheet("font-weight:bold;"); - title_layout->addWidget(name_label); - title_layout->addStretch(); - edit_btn = new QPushButton(tr("Edit"), this); - edit_btn->setVisible(false); - title_layout->addWidget(edit_btn); - frame_layout->addLayout(title_layout); + name_label->setAlignment(Qt::AlignCenter); + name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + toolbar->addWidget(name_label); + toolbar->addAction("🖍", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); + remove_msg_act = toolbar->addAction("X", this, &DetailWidget::removeMsg); + remove_msg_act->setToolTip(tr("Remove Message")); + toolbar->setVisible(false); + frame_layout->addWidget(toolbar); // warning warning_widget = new QWidget(this); @@ -85,7 +86,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart history_log = new HistoryLog(this); container_layout->addWidget(history_log); - QObject::connect(edit_btn, &QPushButton::clicked, this, &DetailWidget::editMsg); QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); @@ -171,7 +171,8 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } - edit_btn->setVisible(true); + toolbar->setVisible(!msg_id.isEmpty()); + remove_msg_act->setEnabled(msg != nullptr); name_label->setText(msgName(msg_id)); binary_view->setMessage(msg_id); @@ -210,16 +211,27 @@ void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool o } void DetailWidget::editMsg() { - auto msg = dbc()->msg(msg_id); - QString name = msgName(msg_id); - int size = msg ? msg->size : can->lastMessage(msg_id).dat.size(); - EditMessageDialog dlg(msg_id, name, size, this); + QString id = msg_id; + auto msg = dbc()->msg(id); + int size = msg ? msg->size : can->lastMessage(id).dat.size(); + EditMessageDialog dlg(id, msgName(id), size, this); if (dlg.exec()) { - dbc()->updateMsg(msg_id, dlg.name_edit->text(), dlg.size_spin->value()); + dbc()->updateMsg(id, dlg.name_edit->text(), dlg.size_spin->value()); dbcMsgChanged(); } } +void DetailWidget::removeMsg() { + QString id = msg_id; + if (auto msg = dbc()->msg(id)) { + QString text = tr("Are you sure you want to remove '%1'").arg(msg->name.c_str()); + if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove Message"), text)) { + dbc()->removeMsg(id); + dbcMsgChanged(); + } + } +} + void DetailWidget::addSignal(int from, int to) { if (auto msg = dbc()->msg(msg_id)) { Signal sig = {}; diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index ac32d5952e..7cb3a505ee 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -2,6 +2,7 @@ #include #include +#include #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" @@ -34,15 +35,17 @@ private: void saveSignal(const Signal *sig, const Signal &new_sig); void removeSignal(const Signal *sig); void editMsg(); + void removeMsg(); void showForm(); void updateState(); QString msg_id; QLabel *name_label, *time_label, *warning_label; QWidget *warning_widget; - QPushButton *edit_btn; QWidget *signals_container; QTabBar *tabbar; + QToolBar *toolbar; + QAction *remove_msg_act; HistoryLog *history_log; BinaryView *binary_view; QScrollArea *scroll; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index f24b6b0317..dbf87a3da2 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -38,15 +38,18 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &CANMessages::msgsReceived, model, &MessageListModel::msgsReceived); QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); + QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid() && current.row() < model->msgs.size()) { - current_msg_id = model->msgs[current.row()]; - emit msgSelectionChanged(current_msg_id); + if (model->msgs[current.row()] != current_msg_id) { + current_msg_id = model->msgs[current.row()]; + emit msgSelectionChanged(current_msg_id); + } } }); QObject::connect(model, &MessageListModel::modelReset, [this]() { if (int row = model->msgs.indexOf(current_msg_id); row != -1) - table_widget->selectionModel()->select(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); + table_widget->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); }); } From f38fe7cfb1b3011ea48a34b0500f352338e05b25 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 9 Nov 2022 14:53:41 -0800 Subject: [PATCH 0230/1179] ui: increase toggle confirmation font size (#26413) * ui: make toggle confirmation text larger * center title * reduce line breaks * slightly reduce font size --- selfdrive/ui/qt/widgets/controls.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 243c078f85..8679de57b0 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -142,8 +142,8 @@ public: ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const bool confirm, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { key = param.toStdString(); QObject::connect(this, &ParamControl::toggleFlipped, [=](bool state) { - QString content("

" + title + "



" - "

" + getDescription() + "

"); + QString content("

" + title + "


" + "

" + getDescription() + "

"); ConfirmationDialog dialog(content, tr("Ok"), tr("Cancel"), true, this); if (!confirm || !state || dialog.exec()) { params.putBool(key, state); From 584842488f4cab62bb9d5e4d8fc2cc3090634fb7 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Wed, 9 Nov 2022 20:13:17 -0300 Subject: [PATCH 0231/1179] Multilang: update pt-BR (#26420) * update pt-BR translations * fix some cutoff texts * Update pt-BR translations --- selfdrive/ui/translations/main_pt-BR.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index a5187af50f..c2ee98d340 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -240,11 +240,11 @@ Reset - + Resetar Review - + Revisar
@@ -476,11 +476,11 @@ trabalho definido ParamControl Ok - OK + OK Cancel - Cancelar + Cancelar @@ -868,7 +868,7 @@ trabalho definido Uninstall - + Desinstalar @@ -1008,15 +1008,15 @@ trabalho definido Experimental mode - + Modo Experimental <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - + <b>AVISO: o controle longitudinal openpilot é experimental para este carro e irá desabilitar AEB.</b><br> O padrão do openpilot é o ACC integrado do carro em vez do controle longitudinal do openpilot neste carro. Habilite isto para alternar para controle longitudinal do openpilot. 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. - + o padrão do openpilot é dirigir no <b>modo chill</b>. Modo experimental habilita <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Os recursos experimentais estão listados abaixo: <br> <h4>🌮 Controle Longitudinal de Ponta a Ponta 🌮</h4> Deixe o modelo de direção controlar o acelerador e os freios. openpilot irá conduzir como pensa que um ser humano faria, incluindo parar para sinais vermelhos e sinais de parada. @@ -1074,7 +1074,7 @@ trabalho definido Forget - + Esquecer From 048cce2149db34ea0e32df3673248fbbc8e804ad Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 16:04:19 -0800 Subject: [PATCH 0232/1179] Hyundai: add missing Sonata 2022 FW versions (#26428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added FW Versions for 2022 Elantra and 2022 Sonata. Added for CAR.ELANTRA_2021 : Ecu.transmission : b’\xf1\x87CXMQFM3421815JB2ww\x96y\xaa\x98x\x87\x88wtwTfuwWh\x9f\xff\x8a\xff\xff\xffE\xe3\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00' Ecu.engine : b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82CNDWD0AMFCXCSG8A' Added for CAR.SONATA : Ecu.engine : b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_J10' Ecu.transmission: b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE' b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02832A1 \xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE' b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x82VDN8T25XXX832NS8' * Update values.py * Removed FW Versions for Elantra_2021. * fix Co-authored-by: humza2000 <111622889+humza2000@users.noreply.github.com> --- 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 e5ddc5cac7..b7e28825c3 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -468,6 +468,7 @@ FW_VERSIONS = { b'\xf1\x82DNBWN5TMDCXXXG2E', b'\xf1\x82DNCVN5GMCCXXXF0A', b'\xf1\x82DNCVN5GMCCXXXG2B', + b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_J10', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82DNDWN5TMDCXXXJ1A', b'\xf1\x87391162M003', b'\xf1\x87391162M013', @@ -492,6 +493,7 @@ FW_VERSIONS = { b'\xf1\x8756310L0010\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0010\x00 4DNAC101', b'\xf1\x8756310L0210\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC101', b'\xf1\x8757700-L0000\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100', + b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP101', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.02 99211-L1000 190422', @@ -512,6 +514,7 @@ FW_VERSIONS = { b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92', b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB2\x00\x00\x00\x00\x00\x00\x08\xc9O:', b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', + b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x87SAKFBA2926554GJ2VefVww\x87xwwwww\x88\x87xww\x87wTo\xfb\xffvUo\xff\x8d\x16\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', b'\xf1\x87SAKFBA3030524GJ2UVugww\x97yx\x88\x87\x88vw\x87gww\x87wto\xf9\xfffUo\xff\xa2\x0c\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', From 52378c97ecde4c489e18e23d01021f27c3acf073 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Wed, 9 Nov 2022 21:06:36 -0300 Subject: [PATCH 0233/1179] Toyota: Add missing Corolla Cross FW verions (#26426) * add geraldo fingerprint * add to non-H * Update selfdrive/car/tests/routes.py * Update non-us cross model years * add test route * Update routes.py Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 04f7712016..07bcf44257 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -167,7 +167,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Camry Hybrid 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla Cross (Non-US only) 2020-21|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 9e96118085..2ce1cba92c 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -119,7 +119,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ ToyotaCarInfo("Toyota Corolla 2020-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), - ToyotaCarInfo("Toyota Corolla Cross (Non-US only) 2020-21", min_enable_speed=7.5), + ToyotaCarInfo("Toyota Corolla Cross (Non-US only) 2020-23", min_enable_speed=7.5), ToyotaCarInfo("Toyota Corolla Hatchback 2019-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), ], CAR.COROLLAH_TSS2: [ @@ -713,6 +713,7 @@ FW_VERSIONS = { }, CAR.COROLLA_TSS2: { (Ecu.engine, 0x700, None): [ + b'\x01896630A22000\x00\x00\x00\x00', b'\x01896630ZG2000\x00\x00\x00\x00', b'\x01896630ZG5000\x00\x00\x00\x00', b'\x01896630ZG5100\x00\x00\x00\x00', @@ -792,6 +793,7 @@ FW_VERSIONS = { b'F152602191\x00\x00\x00\x00\x00\x00', b'\x01F152612862\x00\x00\x00\x00\x00\x00', b'\x01F152612B91\x00\x00\x00\x00\x00\x00', + b'\x01F15260A070\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301100\x00\x00\x00\x00', @@ -809,6 +811,7 @@ FW_VERSIONS = { b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1202200\x00\x00\x00\x008646G2601500\x00\x00\x00\x00', b'\x028646F1601100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', + b'\x028646F1601300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', ], }, CAR.COROLLAH_TSS2: { From 26d66ac671a6b15be4611face27844bae90b185f Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Thu, 10 Nov 2022 09:15:44 +0900 Subject: [PATCH 0234/1179] Multilang: Korean translation update (#26424) fix --- selfdrive/ui/translations/main_ko.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index e9b4943650..ff09581e61 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1004,15 +1004,15 @@ location set Experimental mode - + 실험 모드 <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - + <b>경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 AEB를 비활성화합니다.</b><br> openpilot은 차량의 내장 ACC로 기본 설정됩니다. 롱컨트롤으로 전환하려면 이 옵션을 활성화하세요. 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. - + openpilot은 <b>chill 모드</b>로 기본 설정됩니다. 실험 모드는 chill 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 <br> <h4>🌮 E2E 롱컨트롤 🌮</h4> 주행모델이 가속과 감속을 제어하도록 합니다. openpilot은 신호등과 정지표지판을 보고 멈추는 것을 포함하여 운전자가 생각하는것처럼 주행합니다. From f540002e3fb6bcb15323add59d87269e7da6d00f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 16:49:17 -0800 Subject: [PATCH 0235/1179] translation badges: add number of unfinished translations (#26429) * some clean up and add missing translations * unfinished * set proper width * make this variable common --- selfdrive/ui/tests/test_translations.py | 3 ++- selfdrive/ui/translations/create_badges.py | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/selfdrive/ui/tests/test_translations.py b/selfdrive/ui/tests/test_translations.py index 11ecd30ae0..26d6c39349 100755 --- a/selfdrive/ui/tests/test_translations.py +++ b/selfdrive/ui/tests/test_translations.py @@ -9,6 +9,7 @@ import xml.etree.ElementTree as ET from selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE, update_translations TMP_TRANSLATIONS_DIR = os.path.join(TRANSLATIONS_DIR, "tmp") +UNFINISHED_TRANSLATION_TAG = "" not in cur_translations, + self.assertTrue(UNFINISHED_TRANSLATION_TAG not in cur_translations, f"{file} ({name}) translation file has unfinished translations. Finish translations or mark them as completed in Qt Linguist") def test_vanished_translations(self): diff --git a/selfdrive/ui/translations/create_badges.py b/selfdrive/ui/translations/create_badges.py index 32904f242a..e403972e36 100755 --- a/selfdrive/ui/translations/create_badges.py +++ b/selfdrive/ui/translations/create_badges.py @@ -2,19 +2,22 @@ import json import os import requests +import xml.etree.ElementTree as ET from common.basedir import BASEDIR +from selfdrive.ui.tests.test_translations import UNFINISHED_TRANSLATION_TAG from selfdrive.ui.update_translations import LANGUAGES_FILE, TRANSLATIONS_DIR TRANSLATION_TAG = "'] + badge_svg = [] + max_badge_width = 0 # keep track of max width to set parent element for idx, (name, file) in enumerate(translation_files.items()): with open(os.path.join(TRANSLATIONS_DIR, f"{file}.ts"), "r") as tr_f: tr_file = tr_f.read() @@ -28,19 +31,28 @@ if __name__ == "__main__": unfinished_translations += 1 percent_finished = int(100 - (unfinished_translations / total_translations * 100.)) - color = "green" if percent_finished == 100 else "orange" if percent_finished >= 70 else "red" + color = "green" if percent_finished == 100 else "orange" if percent_finished > 90 else "red" - r = requests.get(f"https://img.shields.io/badge/LANGUAGE {name}-{percent_finished}%25 complete-{color}", timeout=10) + # Download badge + badge_label = f"LANGUAGE {name}" + badge_message = f"{percent_finished}% complete" + if unfinished_translations != 0: + badge_message += f" ({unfinished_translations} unfinished translations)" + + r = requests.get(f"{SHIELDS_URL}/{badge_label}-{badge_message}-{color}", timeout=10) assert r.status_code == 200, "Error downloading badge" content_svg = r.content.decode("utf-8") - # make tag ids in each badge unique + max_badge_width = max(max_badge_width, int(ET.fromstring(content_svg).get("width"))) + + # Make tag ids in each badge unique to combine them into one svg for tag in ("r", "s"): content_svg = content_svg.replace(f'id="{tag}"', f'id="{tag}{idx}"') content_svg = content_svg.replace(f'"url(#{tag})"', f'"url(#{tag}{idx})"') badge_svg.extend([f'', content_svg, ""]) + badge_svg.insert(0, f'') badge_svg.append("") with open(os.path.join(BASEDIR, "translation_badge.svg"), "w") as badge_f: From d8327bd9bed9833eb3d58a51097215c2de803d1b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 16:58:02 -0800 Subject: [PATCH 0236/1179] multilang badges: no need to handle plurals --- selfdrive/ui/translations/create_badges.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/translations/create_badges.py b/selfdrive/ui/translations/create_badges.py index e403972e36..893ac1b412 100755 --- a/selfdrive/ui/translations/create_badges.py +++ b/selfdrive/ui/translations/create_badges.py @@ -37,7 +37,7 @@ if __name__ == "__main__": badge_label = f"LANGUAGE {name}" badge_message = f"{percent_finished}% complete" if unfinished_translations != 0: - badge_message += f" ({unfinished_translations} unfinished translations)" + badge_message += f" ({unfinished_translations} unfinished)" r = requests.get(f"{SHIELDS_URL}/{badge_label}-{badge_message}-{color}", timeout=10) assert r.status_code == 200, "Error downloading badge" From bbc14656d937cadacbcb87ed88cb8800eb6b62fa Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 17:30:33 -0800 Subject: [PATCH 0237/1179] Multilang badges: assert width exists in xml --- selfdrive/ui/translations/create_badges.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/translations/create_badges.py b/selfdrive/ui/translations/create_badges.py index 893ac1b412..575584dd50 100755 --- a/selfdrive/ui/translations/create_badges.py +++ b/selfdrive/ui/translations/create_badges.py @@ -43,7 +43,9 @@ if __name__ == "__main__": assert r.status_code == 200, "Error downloading badge" content_svg = r.content.decode("utf-8") - max_badge_width = max(max_badge_width, int(ET.fromstring(content_svg).get("width"))) + xml = ET.fromstring(content_svg) + assert "width" in xml.attrib + max_badge_width = max(max_badge_width, int(xml.attrib["width"])) # Make tag ids in each badge unique to combine them into one svg for tag in ("r", "s"): From 6c03e093c6d1d9d45dc342cce2374656b80ecaa9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 17:31:58 -0800 Subject: [PATCH 0238/1179] Multilang: mark some translations finished (#26430) * mark finished translations * fix * cleanup * revert --- selfdrive/ui/translations/main_ja.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHS.ts | 6 +++--- selfdrive/ui/translations/main_zh-CHT.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 039ad7b2a4..3ddf71518c 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -475,11 +475,11 @@ location set ParamControl Ok - OK + OK Cancel - キャンセル + キャンセル diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 44e707e49c..28ec6f750a 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -376,7 +376,7 @@ Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai - 订阅comma prime以获取导航。 + 订阅comma prime以获取导航。 立即注册:https://connect.comma.ai @@ -473,11 +473,11 @@ location set ParamControl Ok - 好的 + 好的 Cancel - 取消 + 取消 diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 274cff3a5a..c99b818cbf 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -475,11 +475,11 @@ location set ParamControl Ok - 確定 + 確定 Cancel - 取消 + 取消 From e1001a3036fb93d6d0340d139d4ae2a1f2419d52 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 18:27:30 -0800 Subject: [PATCH 0239/1179] Toyota: factor on cluster speed to match dash (#26408) * add a minimum factort * Update ref_commit --- selfdrive/car/toyota/carstate.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index a959633281..8efb2c79e3 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -54,6 +54,7 @@ class CarState(CarStateBase): ) ret.vEgoRaw = mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr]) ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) + ret.vEgoCluster = ret.vEgo * 1.015 # minimum of all the cars ret.standstill = ret.vEgoRaw == 0 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index da954d76a6..cac678ca1f 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -372a67c524342bbf15e22f0caea08d2038973281 +a36f7e2fd922fcadca6f8a3d777f4db787cba016 From 1fda075c7306976099bcfbb6b0a6303e819036b4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 9 Nov 2022 18:42:51 -0800 Subject: [PATCH 0240/1179] UI: add set speed clarification for e2e long --- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/translations/main_ja.ts | 2 +- selfdrive/ui/translations/main_ko.ts | 4 ++-- selfdrive/ui/translations/main_pt-BR.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHS.ts | 2 +- selfdrive/ui/translations/main_zh-CHT.ts | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 29069155b2..a30b66a2fd 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -125,7 +125,7 @@ void TogglesPanel::updateToggles() { Experimental features are listed below:\
\

🌮 End-to-End Longitudinal Control 🌮

\ - 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."); + 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 which speed to drive, the set speed will only act as an upper bound."); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 3ddf71518c..be3fbe104c 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1011,7 +1011,7 @@ location set - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound.
diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index ff09581e61..4e11e80332 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1011,8 +1011,8 @@ location set <b>경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 AEB를 비활성화합니다.</b><br> openpilot은 차량의 내장 ACC로 기본 설정됩니다. 롱컨트롤으로 전환하려면 이 옵션을 활성화하세요. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. - openpilot은 <b>chill 모드</b>로 기본 설정됩니다. 실험 모드는 chill 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 <br> <h4>🌮 E2E 롱컨트롤 🌮</h4> 주행모델이 가속과 감속을 제어하도록 합니다. openpilot은 신호등과 정지표지판을 보고 멈추는 것을 포함하여 운전자가 생각하는것처럼 주행합니다. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index c2ee98d340..fde669c919 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1015,8 +1015,8 @@ trabalho definido <b>AVISO: o controle longitudinal openpilot é experimental para este carro e irá desabilitar AEB.</b><br> O padrão do openpilot é o ACC integrado do carro em vez do controle longitudinal do openpilot neste carro. Habilite isto para alternar para controle longitudinal do openpilot. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. - o padrão do openpilot é dirigir no <b>modo chill</b>. Modo experimental habilita <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Os recursos experimentais estão listados abaixo: <br> <h4>🌮 Controle Longitudinal de Ponta a Ponta 🌮</h4> Deixe o modelo de direção controlar o acelerador e os freios. openpilot irá conduzir como pensa que um ser humano faria, incluindo parar para sinais vermelhos e sinais de parada. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 28ec6f750a..230205a4a8 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1009,7 +1009,7 @@ location set - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index c99b818cbf..4e8d733933 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1011,7 +1011,7 @@ location set - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. From 5a3c5e7a4b78853d6b350f551432a1bb6050eba9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 19:33:42 -0800 Subject: [PATCH 0241/1179] Multilang: clean up translation string (#26435) * update translations * do pt * do pt * do ko * do ko * Update selfdrive/ui/translations/main_pt-BR.ts --- selfdrive/ui/qt/offroad/settings.cc | 5 +++-- selfdrive/ui/translations/main_ja.ts | 8 ++++++-- selfdrive/ui/translations/main_ko.ts | 12 ++++++++---- selfdrive/ui/translations/main_pt-BR.ts | 12 ++++++++---- selfdrive/ui/translations/main_zh-CHS.ts | 8 ++++++-- selfdrive/ui/translations/main_zh-CHT.ts | 8 ++++++-- 6 files changed, 37 insertions(+), 16 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index a30b66a2fd..bf886ae159 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -46,8 +46,9 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { { "ExperimentalLongitudinalEnabled", tr("Experimental openpilot longitudinal control"), - tr("WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.
\ - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control."), + QString("%1
%2") + .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.")) + .arg(tr("openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control.")), "../assets/offroad/icon_speed_limit.png", true, }, diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index be3fbe104c..2e38295368 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1007,11 +1007,15 @@ location set - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + + + + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 4e11e80332..42b73430f1 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1006,14 +1006,18 @@ location set Experimental mode 실험 모드 - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - <b>경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 AEB를 비활성화합니다.</b><br> openpilot은 차량의 내장 ACC로 기본 설정됩니다. 롱컨트롤으로 전환하려면 이 옵션을 활성화하세요. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + + WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + 경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 AEB를 비활성화합니다. + + + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + openpilot은 차량의 내장 ACC로 기본 설정됩니다. 롱컨트롤으로 전환하려면 이 옵션을 활성화하세요. + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index fde669c919..394d73c86a 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1010,14 +1010,18 @@ trabalho definido Experimental mode Modo Experimental - - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - <b>AVISO: o controle longitudinal openpilot é experimental para este carro e irá desabilitar AEB.</b><br> O padrão do openpilot é o ACC integrado do carro em vez do controle longitudinal do openpilot neste carro. Habilite isto para alternar para controle longitudinal do openpilot. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + + WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + AVISO: o controle longitudinal openpilot é experimental para este carro e irá desabilitar AEB. + + + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + O padrão do openpilot é o ACC integrado do carro em vez do controle longitudinal do openpilot neste carro. Habilite isto para alternar para controle longitudinal do openpilot. + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 230205a4a8..541ed20dee 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1005,11 +1005,15 @@ location set - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + + + + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 4e8d733933..99c64a194b 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1007,11 +1007,15 @@ location set - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b><br> openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. + WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + + + + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. From a3cd50c5bbb924eaf40ab18d76f603edfc2f5a2a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 19:38:17 -0800 Subject: [PATCH 0242/1179] ParamControl dialog: more explicit confirmation text (#26431) * Use enable * vanish * fill in missing translation * Update selfdrive/ui/translations/main_pt-BR.ts --- selfdrive/ui/qt/widgets/controls.h | 2 +- selfdrive/ui/translations/main_ja.ts | 8 ++++---- selfdrive/ui/translations/main_ko.ts | 8 ++++---- selfdrive/ui/translations/main_pt-BR.ts | 8 ++++---- selfdrive/ui/translations/main_zh-CHS.ts | 8 ++++---- selfdrive/ui/translations/main_zh-CHT.ts | 8 ++++---- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 8679de57b0..b67224b33d 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -144,7 +144,7 @@ public: QObject::connect(this, &ParamControl::toggleFlipped, [=](bool state) { QString content("

" + title + "


" "

" + getDescription() + "

"); - ConfirmationDialog dialog(content, tr("Ok"), tr("Cancel"), true, this); + ConfirmationDialog dialog(content, tr("Enable"), tr("Cancel"), true, this); if (!confirm || !state || dialog.exec()) { params.putBool(key, state); } else { diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 2e38295368..14c3404ad1 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -473,14 +473,14 @@ location set ParamControl - - Ok - OK - Cancel キャンセル + + Enable + を有効化 + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 42b73430f1..9ca28e9e2c 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -473,14 +473,14 @@ location set ParamControl - - Ok - 확인 - Cancel 취소 + + Enable + 사용 + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 394d73c86a..3559d4b422 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -474,14 +474,14 @@ trabalho definido ParamControl - - Ok - OK - Cancel Cancelar + + Enable + Ativar + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 541ed20dee..3dfd7794ec 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -471,14 +471,14 @@ location set ParamControl - - Ok - 好的 - Cancel 取消 + + Enable + 启用 + PrimeAdWidget diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 99c64a194b..35fd944ddb 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -473,14 +473,14 @@ location set ParamControl - - Ok - 確定 - Cancel 取消 + + Enable + 啟用 + PrimeAdWidget From af84f1b3506082d644c2f52f88390fabcc9f7835 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 19:42:34 -0800 Subject: [PATCH 0243/1179] experimental long toggle: adjust description (#26437) * Spell out AEB * vanish --- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/translations/main_ja.ts | 4 ++-- selfdrive/ui/translations/main_ko.ts | 8 ++++---- selfdrive/ui/translations/main_pt-BR.ts | 8 ++++---- selfdrive/ui/translations/main_zh-CHS.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHT.ts | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index bf886ae159..2acbb4ed7d 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -47,7 +47,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "ExperimentalLongitudinalEnabled", tr("Experimental openpilot longitudinal control"), QString("%1
%2") - .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.")) + .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB).")) .arg(tr("openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control.")), "../assets/offroad/icon_speed_limit.png", true, diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 14c3404ad1..78434439dd 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1011,11 +1011,11 @@ location set - WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB).
diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 9ca28e9e2c..9409f82a1d 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1010,14 +1010,14 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - - WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. - 경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 AEB를 비활성화합니다. - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. openpilot은 차량의 내장 ACC로 기본 설정됩니다. 롱컨트롤으로 전환하려면 이 옵션을 활성화하세요. + + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 3559d4b422..55ae75d20e 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1014,14 +1014,14 @@ trabalho definido 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - - WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. - AVISO: o controle longitudinal openpilot é experimental para este carro e irá desabilitar AEB. - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. O padrão do openpilot é o ACC integrado do carro em vez do controle longitudinal do openpilot neste carro. Habilite isto para alternar para controle longitudinal do openpilot. + + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 3dfd7794ec..165aacfa5a 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1009,11 +1009,11 @@ location set - WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 35fd944ddb..e3cd908d18 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1011,11 +1011,11 @@ location set - WARNING: openpilot longitudinal control is experimental for this car and will disable AEB. + openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). From d3122cc77e169d8eb87663741bacc165f7062d56 Mon Sep 17 00:00:00 2001 From: Nelson Chen Date: Wed, 9 Nov 2022 19:59:12 -0800 Subject: [PATCH 0244/1179] Toyota: add missing engine FW for RAV4H_TSS2 (#26432) "rav4 hybrid xse 2020" From Rogrhoa#2158 on Discord. Example Route: 64edc30d23cad8cb|2022-11-09--20-02-03 --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 2ce1cba92c..ba26c7e03b 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1392,6 +1392,7 @@ FW_VERSIONS = { b'\x02896634A14001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', b'\x02896634A23000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02896634A23001\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', + b'\x02896634A23101\x00\x00\x00\x00897CF1203001\x00\x00\x00\x00', b'\x02896634A14001\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896634A14101\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', ], From 0941e40177eb0eb7a49bb08628e5aad2deb19c7f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 20:31:38 -0800 Subject: [PATCH 0245/1179] ui: static color non-e2e path (#26406) * remove orientation color changing * "just green" --- selfdrive/ui/qt/onroad.cc | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 37c1913743..23986726c8 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -478,21 +478,9 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { bg.setColorAt(0.5, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.35)); bg.setColorAt(1.0, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.0)); } else { - const auto &orientation = (*s->sm)["modelV2"].getModelV2().getOrientation(); - float orientation_future = 0; - if (orientation.getZ().size() > 16) { - orientation_future = std::abs(orientation.getZ()[16]); // 2.5 seconds - } - start_hue = 148; - // straight: 112, in turns: 70 - end_hue = fmax(70, 112 - (orientation_future * 420)); - - // FIXME: painter.drawPolygon can be slow if hue is not rounded - end_hue = int(end_hue * 100 + 0.5) / 100; - - bg.setColorAt(0.0, QColor::fromHslF(start_hue / 360., 0.94, 0.51, 0.4)); - bg.setColorAt(0.5, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.35)); - bg.setColorAt(1.0, QColor::fromHslF(end_hue / 360., 1.0, 0.68, 0.0)); + bg.setColorAt(0.0, QColor::fromHslF(148 / 360., 0.94, 0.51, 0.4)); + bg.setColorAt(0.5, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.35)); + bg.setColorAt(1.0, QColor::fromHslF(112 / 360., 1.0, 0.68, 0.0)); } painter.setBrush(bg); From 4efb01ece2a9ef54152682c1dc3756d3e4161241 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 9 Nov 2022 20:33:01 -0800 Subject: [PATCH 0246/1179] Toggle titles: proper capitalization (#26438) * proper caps * update translations update translations update translations * Update selfdrive/ui/translations/main_pt-BR.ts --- selfdrive/ui/qt/offroad/settings.cc | 6 +++--- selfdrive/ui/translations/main_ar.ts | 4 ++-- selfdrive/ui/translations/main_ja.ts | 6 +++--- selfdrive/ui/translations/main_ko.ts | 6 +++--- selfdrive/ui/translations/main_nl.ts | 4 ++-- selfdrive/ui/translations/main_pl.ts | 4 ++-- selfdrive/ui/translations/main_pt-BR.ts | 6 +++--- selfdrive/ui/translations/main_th.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHS.ts | 6 +++--- selfdrive/ui/translations/main_zh-CHT.ts | 6 +++--- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 2acbb4ed7d..a03cf02010 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -38,14 +38,14 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { }, { "ExperimentalMode", - tr("Experimental mode"), + tr("Experimental Mode"), "", "../assets/offroad/icon_road.png", false, }, { "ExperimentalLongitudinalEnabled", - tr("Experimental openpilot longitudinal control"), + tr("Experimental openpilot Longitudinal Control"), QString("%1
%2") .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB).")) .arg(tr("openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control.")), @@ -75,7 +75,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { }, { "DisengageOnAccelerator", - tr("Disengage On Accelerator Pedal"), + tr("Disengage on Accelerator Pedal"), tr("When enabled, pressing the accelerator pedal will disengage openpilot."), "../assets/offroad/icon_disengage_on_accelerator.svg", false, diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index 3c47e6e8e8..07a84fca08 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -1023,7 +1023,7 @@ location set قم بتحميل البيانات من الكاميرا المواجهة للسائق وساعد في تحسين خوارزمية مراقبة السائق. - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal فك الارتباط على دواسة التسريع @@ -1059,7 +1059,7 @@ location set - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 78434439dd..87c60516fc 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -967,7 +967,7 @@ location set 車内カメラの映像をアップロードし、ドライバー監視システムのアルゴリズムの向上に役立てます。 - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control 実験段階のopenpilotによるアクセル制御 @@ -979,7 +979,7 @@ location set ここ機能を使う為には、「実験段階のopenpilotによるアクセル制御」を先に有効化してください。 - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal アクセルを踏むと openpilot を中断 @@ -1003,7 +1003,7 @@ location set 分割画面表示の場合、ディスプレイの左側にマップを表示します。 - Experimental mode + Experimental Mode diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 9409f82a1d..0bbae22517 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -967,7 +967,7 @@ location set 운전자 카메라에서 데이터를 업로드하고 운전자 모니터링 알고리즘을 개선합니다. - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control openpilot 롱컨트롤 (실험적) @@ -979,7 +979,7 @@ location set openpilot 롱컨트롤을 활성화합니다. (실험적) - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal 가속페달 조작시 해제 @@ -1003,7 +1003,7 @@ location set 분할 화면 보기에서 지도를 왼쪽에 표시합니다. - Experimental mode + Experimental Mode 실험 모드 diff --git a/selfdrive/ui/translations/main_nl.ts b/selfdrive/ui/translations/main_nl.ts index 24d2031f31..10651a4160 100644 --- a/selfdrive/ui/translations/main_nl.ts +++ b/selfdrive/ui/translations/main_nl.ts @@ -1007,7 +1007,7 @@ ingesteld Upload gegevens van de bestuurders camera en help het algoritme voor het monitoren van de bestuurder te verbeteren. - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal Deactiveren Met Gaspedaal @@ -1043,7 +1043,7 @@ ingesteld - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control diff --git a/selfdrive/ui/translations/main_pl.ts b/selfdrive/ui/translations/main_pl.ts index bdce181375..4f8b03ef50 100644 --- a/selfdrive/ui/translations/main_pl.ts +++ b/selfdrive/ui/translations/main_pl.ts @@ -1011,7 +1011,7 @@ nie zostało ustawione Prześlij dane z kamery skierowanej na kierowcę i pomóż poprawiać algorytm monitorowania kierowcy. - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal Odłącz poprzez naciśnięcie gazu @@ -1047,7 +1047,7 @@ nie zostało ustawione - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 55ae75d20e..702702a8be 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -971,7 +971,7 @@ trabalho definido Upload dados da câmera voltada para o motorista e ajude a melhorar o algoritmo de monitoramentor. - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control Controle longitudinal experimental openpilot @@ -983,7 +983,7 @@ trabalho definido Habilite o controle longitudinal experimental para habilitar isso. - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal Desacionar Com Pedal Do Acelerador @@ -1007,7 +1007,7 @@ trabalho definido Exibir mapa do lado esquerdo quando a tela for dividida. - Experimental mode + Experimental Mode Modo Experimental diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 95880e69c9..0de0ba5f9a 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -951,7 +951,7 @@ location set อัปโหลดข้อมูลจากกล้องที่หันหน้าไปทางคนขับ และช่วยปรับปรุงอัลกอริธึมการตรวจสอบผู้ขับขี่ - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal ยกเลิกระบบช่วยขับเมื่อเหยียบคันเร่ง @@ -979,7 +979,7 @@ location set 🌮 ควบคุมเร่ง/เบรคแบบ End-to-end (อยู่ขั้นพัฒนา) 🌮 - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control ทดลองใช้ระบบควบคุมการเร่ง/เบรคโดย openpilot diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 165aacfa5a..558a6cec4f 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -965,7 +965,7 @@ location set 上传驾驶员摄像头的数据,帮助改进驾驶员监控算法。 - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control @@ -977,7 +977,7 @@ location set - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal 踩油门时取消控制 @@ -1001,7 +1001,7 @@ location set 在分屏模式中,将地图置于屏幕左侧。 - Experimental mode + Experimental Mode diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index e3cd908d18..0f6bc981cf 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -967,7 +967,7 @@ location set 上傳駕駛監控的錄像來協助我們提升駕駛監控的準確率。 - Experimental openpilot longitudinal control + Experimental openpilot Longitudinal Control 使用 openpilot 縱向控制(實驗) @@ -979,7 +979,7 @@ location set 打開縱向控制(實驗)以啟用此功能。 - Disengage On Accelerator Pedal + Disengage on Accelerator Pedal 油門取消控車 @@ -1003,7 +1003,7 @@ location set 進入分割畫面後,地圖將會顯示在畫面的左側。 - Experimental mode + Experimental Mode From 5eaf525c18becad63205fd3add4bfe540f70b01a Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 9 Nov 2022 21:49:24 -0800 Subject: [PATCH 0247/1179] camerad: fix OX flicker (#26439) --- system/camerad/cameras/camera_qcom2.cc | 28 +++++++++++--------------- system/camerad/cameras/camera_qcom2.h | 3 ++- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 78848af5be..2ee06e372a 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -80,30 +80,26 @@ const float sensor_analog_gains_AR0231[] = { 7.0/2.0, 8.0/2.0, 8.0/1.0}; // 12, 13, 14, 15 = bypass const float sensor_analog_gains_OX03C10[] = { - 1.0, 1.125, 1.25, 1.3125, 1.5625, - 1.6875, 2.0, 2.25, 2.625, 3.125, - 3.625, 4.0, 4.5, 5.0, 5.5, - 6.0, 6.5, 7.0, 7.5, 8.0, - 8.5, 9.0, 9.5, 10.0, 10.5, - 11.0, 11.5, 12.0, 12.5, 13.0, - 13.5, 14.0, 14.5, 15.0, 15.5}; + 1.0, 1.0625, 1.125, 1.1875, 1.25, 1.3125, 1.375, 1.4375, 1.5, 1.5625, 1.6875, + 1.8125, 1.9375, 2.0, 2.125, 2.25, 2.375, 2.5, 2.625, 2.75, 2.875, 3.0, + 3.125, 3.375, 3.625, 3.875, 4.0, 4.25, 4.5, 4.75, 5.0, 5.25, 5.5, + 5.75, 6.0, 6.25, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, + 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 14.5, 15.0, 15.5}; const uint32_t ox03c10_analog_gains_reg[] = { - 0x100, 0x120, 0x140, 0x150, 0x190, - 0x1B0, 0x200, 0x240, 0x2A0, 0x320, - 0x3A0, 0x400, 0x480, 0x500, 0x580, - 0x600, 0x680, 0x700, 0x780, 0x800, - 0x880, 0x900, 0x980, 0xA00, 0xA80, - 0xB00, 0xB80, 0xC00, 0xC80, 0xD00, - 0xD80, 0xE00, 0xE80, 0xF00, 0xF80}; + 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160, 0x170, 0x180, 0x190, 0x1B0, + 0x1D0, 0x1F0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, + 0x320, 0x360, 0x3A0, 0x3E0, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580, + 0x5C0, 0x600, 0x640, 0x680, 0x700, 0x780, 0x800, 0x880, 0x900, 0x980, 0xA00, + 0xA80, 0xB00, 0xB80, 0xC00, 0xC80, 0xD00, 0xD80, 0xE00, 0xE80, 0xF00, 0xF80}; const int ANALOG_GAIN_MIN_IDX_AR0231 = 0x1; // 0.25x const int ANALOG_GAIN_REC_IDX_AR0231 = 0x6; // 0.8x const int ANALOG_GAIN_MAX_IDX_AR0231 = 0xD; // 4.0x const int ANALOG_GAIN_MIN_IDX_OX03C10 = 0x0; -const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x6; // 2x -const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0x22; +const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x11; // 2.5x +const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0x36; const int EXPOSURE_TIME_MIN_AR0231 = 2; // with HDR, fastest ss const int EXPOSURE_TIME_MAX_AR0231 = 0x0855; // with HDR, slowest ss, 40ms diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 5023c82458..1e25e605c5 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -12,6 +12,7 @@ #include "common/util.h" #define FRAME_BUF_COUNT 4 +#define ANALOG_GAIN_MAX_CNT 55 class CameraState { public: @@ -36,7 +37,7 @@ public: float dc_gain_on_grey; float dc_gain_off_grey; - float sensor_analog_gains[35]; + float sensor_analog_gains[ANALOG_GAIN_MAX_CNT]; int analog_gain_min_idx; int analog_gain_max_idx; int analog_gain_rec_idx; From 737408066895452f31f08144c129551b94e64662 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Wed, 9 Nov 2022 22:04:57 -0800 Subject: [PATCH 0248/1179] min lane change speed 20mph (#26434) --- selfdrive/controls/lib/desire_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py index d41d6780e3..4790b8f0eb 100644 --- a/selfdrive/controls/lib/desire_helper.py +++ b/selfdrive/controls/lib/desire_helper.py @@ -5,7 +5,7 @@ from common.realtime import DT_MDL LaneChangeState = log.LateralPlan.LaneChangeState LaneChangeDirection = log.LateralPlan.LaneChangeDirection -LANE_CHANGE_SPEED_MIN = 15 * CV.MPH_TO_MS +LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS LANE_CHANGE_TIME_MAX = 10. DESIRES = { From b320ac6c237eb0d31ab54227066e8ea6ba0f4dec Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 10 Nov 2022 14:05:18 +0800 Subject: [PATCH 0249/1179] Cabana: improve the BinaryView & fix known issues (#26409) * fix flipping issue * dragging up to create little endian signal * transform between little & big endian * complete selection functions * scroll to top after msg updated * remove empty line * cleanup code * remove extra semicolon * fix indentation * minmax * dont select hex column * create msg if not existed --- tools/cabana/binaryview.cc | 153 +++++++++++++++++------------------ tools/cabana/binaryview.h | 14 ++-- tools/cabana/dbcmanager.cc | 6 +- tools/cabana/dbcmanager.h | 2 +- tools/cabana/detailwidget.cc | 42 ++++++---- tools/cabana/detailwidget.h | 2 +- tools/cabana/signaledit.cc | 14 +++- 7 files changed, 127 insertions(+), 106 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index ba50b101fc..678fe5f876 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -13,6 +13,10 @@ const int CELL_HEIGHT = 26; +inline int get_bit_index(const QModelIndex &index, bool little_endian) { + return index.row() * 8 + (little_endian ? 7 - index.column() : index.column()); +} + BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { model = new BinaryViewModel(this); setModel(model); @@ -37,31 +41,49 @@ void BinaryView::highlight(const Signal *sig) { } void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) { - QModelIndex tl = indexAt({qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())}); - QModelIndex br = indexAt({qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())}); - if (!tl.isValid() || !br.isValid()) + auto index = indexAt(viewport()->mapFromGlobal(QCursor::pos())); + if (!anchor_index.isValid() || !index.isValid()) return; - if (tl < anchor_index) { - br = anchor_index; - } else if (anchor_index < br) { - tl = anchor_index; - } QItemSelection 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 [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); + } } selectionModel()->select(selection, flags); } void BinaryView::mousePressEvent(QMouseEvent *event) { delegate->setSelectionColor(style()->standardPalette().color(QPalette::Active, QPalette::Highlight)); - anchor_index = indexAt(event->pos()); - if (getResizingSignal() != nullptr) { + if (auto index = indexAt(event->pos()); index.isValid() && index.column() != 8) { + anchor_index = index; auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); - delegate->setSelectionColor(item->bg_color); + 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; + } + } + } } QTableView::mousePressEvent(event); } @@ -80,23 +102,35 @@ void BinaryView::mouseMoveEvent(QMouseEvent *event) { void BinaryView::mouseReleaseEvent(QMouseEvent *event) { QTableView::mouseReleaseEvent(event); - if (auto indexes = selectedIndexes(); !indexes.isEmpty()) { - int from = indexes.first().row() * 8 + indexes.first().column(); - int to = indexes.back().row() * 8 + indexes.back().column(); - if (auto sig = getResizingSignal()) { - auto [sig_from, sig_to] = getSignalRange(sig); - if (from >= sig_from && to <= sig_to) { // reduce size - emit(from == sig_from ? resizeSignal(sig, std::min(to + 1, sig_to), sig_to) - : resizeSignal(sig, sig_from, std::max(from - 1, sig_from))); - } else { // increase size - emit resizeSignal(sig, std::min(from, sig_from), std::max(to, sig_to)); + 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); } else { - emit addSignal(from, to); + auto [sart_bit, end_bit] = std::minmax(archor_bit_idx, release_bit_idx); + emit addSignal(sart_bit, end_bit - sart_bit + 1, little_endian); } - clearSelection(); } + clearSelection(); anchor_index = QModelIndex(); + resize_sig = nullptr; } void BinaryView::leaveEvent(QEvent *event) { @@ -107,34 +141,17 @@ void BinaryView::leaveEvent(QEvent *event) { void BinaryView::setMessage(const QString &message_id) { model->setMessage(message_id); clearSelection(); + anchor_index = QModelIndex(); + resize_sig = nullptr; + hovered_sig = nullptr; updateState(); } -const Signal *BinaryView::getResizingSignal() const { - if (anchor_index.isValid()) { - auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); - if (item && item->sigs.size() > 0) { - int archor_pos = anchor_index.row() * 8 + anchor_index.column(); - for (auto s : item->sigs) { - auto [sig_from, sig_to] = getSignalRange(s); - if (archor_pos == sig_from || archor_pos == sig_to) - return s; - } - } - } - return nullptr; -} - QSet BinaryView::getOverlappingSignals() const { QSet overlapping; - for (int i = 0; i < model->rowCount(); ++i) { - for (int j = 0; j < model->columnCount() - 1; ++j) { - auto item = (const BinaryViewModel::Item *)model->index(i, j).internalPointer(); - if (item && item->sigs.size() > 1) { - for (auto s : item->sigs) - overlapping.insert(s); - } - } + for (auto &item : model->items) { + if (item.sigs.size() > 1) + for (auto s : item.sigs) overlapping += s; } return overlapping; } @@ -142,53 +159,37 @@ QSet BinaryView::getOverlappingSignals() const { // BinaryViewModel void BinaryViewModel::setMessage(const QString &message_id) { - msg_id = message_id; - beginResetModel(); + msg_id = message_id; items.clear(); - row_count = 0; - - dbc_msg = dbc()->msg(msg_id); - if (dbc_msg) { + if ((dbc_msg = dbc()->msg(msg_id))) { 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]; auto [start, end] = getSignalRange(&sig); for (int j = start; j <= end; ++j) { - int idx = column_count * (j / 8) + j % 8; + 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 " << 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; - } + 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(&dbc_msg->sigs[i]); + items[idx].sigs.push_back(&sig); } } } else { row_count = can->lastMessage(msg_id).dat.size(); items.resize(row_count * column_count); } - 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) { @@ -198,7 +199,6 @@ void BinaryViewModel::updateState() { 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) { @@ -248,9 +248,8 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op BinaryView *bin_view = (BinaryView *)parent(); painter->save(); - bool hover = std::find_if(item->sigs.begin(), item->sigs.end(), [=](auto s) { return s == bin_view->hoveredSignal(); }) != - item->sigs.end(); // 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; @@ -258,7 +257,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->fillRect(option.rect, bg_color); // text - if (index.column() == 8) { // hex column + if (index.column() == 8) { // hex column painter->setFont(hex_font); } else if (hover) { painter->setPen(Qt::white); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index a907a673bf..05bfe7e79f 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -28,12 +28,16 @@ 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; } + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override { + return createIndex(row, column, (void *)&items[row * column_count + column]); + } + Qt::ItemFlags flags(const QModelIndex &index) const override { + return (index.column() == column_count - 1) ? Qt::ItemIsEnabled : Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } struct Item { QColor bg_color = QColor(Qt::white); @@ -42,13 +46,13 @@ public: QString val = "0"; QList sigs; }; + std::vector items; private: QString msg_id; const Msg *dbc_msg; int row_count = 0; const int column_count = 9; - std::vector items; }; class BinaryView : public QTableView { @@ -64,7 +68,7 @@ public: signals: void signalHovered(const Signal *sig); - void addSignal(int from, int size); + void addSignal(int start_bit, int size, bool little_endian); void resizeSignal(const Signal *sig, int from, int size); private: @@ -73,10 +77,10 @@ private: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void leaveEvent(QEvent *event) override; - const Signal *getResizingSignal() const; QModelIndex anchor_index; BinaryViewModel *model; BinaryItemDelegate *delegate; + const Signal *resize_sig = nullptr; const Signal *hovered_sig = nullptr; }; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 184fab38eb..abdd9a08df 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -147,9 +147,9 @@ double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) { return value; } -void updateSigSizeParamsFromRange(Signal &s, int from, int to) { - s.start_bit = s.is_little_endian ? from : bigEndianBitIndex(from); - s.size = to - from + 1; +void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size) { + s.start_bit = s.is_little_endian ? start_bit : bigEndianBitIndex(start_bit); + s.size = size; if (s.is_little_endian) { s.lsb = s.start_bit; s.msb = s.start_bit + s.size - 1; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 2b6aca41d7..81c723a20d 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -49,7 +49,7 @@ private: double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig); int bigEndianStartBitsIndex(int start_bit); int bigEndianBitIndex(int index); -void updateSigSizeParamsFromRange(Signal &s, int from, int to); +void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size); std::pair getSignalRange(const Signal *s); DBCManager *dbc(); inline QString msgName(const QString &id, const char *def = "untitled") { diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 287c75a617..f96b60847b 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -130,15 +130,13 @@ void DetailWidget::setMessage(const QString &message_id) { break; } } + msg_id = message_id; if (index == -1) { index = tabbar->addTab(message_id); tabbar->setTabToolTip(index, msgName(message_id)); } tabbar->setCurrentIndex(index); - msg_id = message_id; dbcMsgChanged(); - - scroll->verticalScrollBar()->setValue(0); } void DetailWidget::dbcMsgChanged(int show_form_idx) { @@ -187,6 +185,7 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { warning_label->setText(warnings.join('\n')); warning_widget->setVisible(!warnings.isEmpty()); setUpdatesEnabled(true); + scroll->verticalScrollBar()->setValue(0); } void DetailWidget::updateState() { @@ -232,24 +231,34 @@ void DetailWidget::removeMsg() { } } -void DetailWidget::addSignal(int from, int to) { - if (auto msg = dbc()->msg(msg_id)) { - Signal sig = {}; +void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { + auto msg = dbc()->msg(msg_id); + if (!msg) { for (int i = 1; /**/; ++i) { - sig.name = "NEW_SIGNAL_" + std::to_string(i); - auto it = std::find_if(msg->sigs.begin(), msg->sigs.end(), [&](auto &s) { return sig.name == s.name; }); - if (it == msg->sigs.end()) break; + std::string name = "NEW_MSG_" + std::to_string(i); + auto it = std::find_if(dbc()->getDBC()->msgs.begin(), dbc()->getDBC()->msgs.end(), [&](auto &m) { return m.name == name; }); + if (it == dbc()->getDBC()->msgs.end()) { + dbc()->updateMsg(msg_id, name.c_str(), can->lastMessage(msg_id).dat.size()); + msg = dbc()->msg(msg_id); + break; + } } - sig.is_little_endian = false, - updateSigSizeParamsFromRange(sig, from, to); - dbc()->addSignal(msg_id, sig); - dbcMsgChanged(msg->sigs.size() - 1); } + Signal sig = {}; + for (int i = 1; /**/; ++i) { + sig.name = "NEW_SIGNAL_" + std::to_string(i); + auto it = std::find_if(msg->sigs.begin(), msg->sigs.end(), [&](auto &s) { return sig.name == s.name; }); + if (it == msg->sigs.end()) break; + } + sig.is_little_endian = little_endian; + updateSigSizeParamsFromRange(sig, start_bit, size); + dbc()->addSignal(msg_id, sig); + dbcMsgChanged(msg->sigs.size() - 1); } -void DetailWidget::resizeSignal(const Signal *sig, int from, int to) { +void DetailWidget::resizeSignal(const Signal *sig, int start_bit, int size) { Signal s = *sig; - updateSigSizeParamsFromRange(s, from, to); + updateSigSizeParamsFromRange(s, start_bit, size); saveSignal(sig, s); } @@ -272,8 +281,7 @@ void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) { } dbc()->updateSignal(msg_id, sig->name.c_str(), new_sig); - // update binary view and history log - updateState(); + dbcMsgChanged(); } void DetailWidget::removeSignal(const Signal *sig) { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 7cb3a505ee..915e0bde60 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -30,7 +30,7 @@ public: private: void updateChartState(const QString &id, const Signal *sig, bool opened); void showTabBarContextMenu(const QPoint &pt); - void addSignal(int start_bit, int to); + void addSignal(int start_bit, int size, bool little_endian); void resizeSignal(const Signal *sig, int from, int to); void saveSignal(const Signal *sig, const Signal &new_sig); void removeSignal(const Signal *sig); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index ee91887d0a..99365294b8 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -28,7 +28,6 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { endianness->addItems({"Little", "Big"}); form_layout->addRow(tr("Endianness"), endianness); - ; form_layout->addRow(tr("lsb"), lsb = new QLabel()); form_layout->addRow(tr("msb"), msb = new QLabel()); @@ -130,7 +129,18 @@ void SignalEdit::saveSignal() { s.offset = form->offset->text().toDouble(); s.factor = form->factor->text().toDouble(); s.is_signed = form->sign->currentIndex() == 0; - s.is_little_endian = form->endianness->currentIndex() == 0; + bool little_endian = form->endianness->currentIndex() == 0; + if (little_endian != s.is_little_endian) { + int start = std::floor(s.start_bit / 8); + if (little_endian) { + int end = std::floor((s.start_bit - s.size + 1) / 8); + s.start_bit = start == end ? s.start_bit - s.size + 1 : bigEndianStartBitsIndex(s.start_bit); + } else { + int end = std::floor((s.start_bit + s.size - 1) / 8); + s.start_bit = start == end ? s.start_bit + s.size - 1 : bigEndianBitIndex(s.start_bit); + } + s.is_little_endian = little_endian; + } if (s.is_little_endian) { s.lsb = s.start_bit; s.msb = s.start_bit + s.size - 1; From 7c922eafe9d9c8e07de80f8bafcd9b2dc2932c13 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 11 Nov 2022 02:37:38 +0800 Subject: [PATCH 0250/1179] Cabana: Added support for undo & redo (#26440) * undo/redo * display command list to rolling the state backwards or forward * update detailview after rolling states * add * to title bar to indicate dbc has changed * fix signal pointer address changed after removed * cleanup * fix id error * clear undo stack after dbc file changed * cleanup * use map * cleanup * typo --- tools/cabana/SConscript | 2 +- tools/cabana/binaryview.cc | 7 +-- tools/cabana/binaryview.h | 2 +- tools/cabana/chartswidget.cc | 2 +- tools/cabana/commands.cc | 75 +++++++++++++++++++++++++++++++ tools/cabana/commands.h | 63 ++++++++++++++++++++++++++ tools/cabana/dbcmanager.cc | 75 ++++++++++++++++--------------- tools/cabana/dbcmanager.h | 25 +++++++---- tools/cabana/detailwidget.cc | 60 +++++++++++-------------- tools/cabana/detailwidget.h | 2 + tools/cabana/historylog.cc | 8 +++- tools/cabana/historylog.h | 2 +- tools/cabana/mainwin.cc | 25 ++++++++++- tools/cabana/tests/test_cabana.cc | 39 ++++++++-------- 14 files changed, 277 insertions(+), 110 deletions(-) create mode 100644 tools/cabana/commands.cc create mode 100644 tools/cabana/commands.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index b7321e1f8d..3ff4862800 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -19,7 +19,7 @@ prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_env.Execute('./generate_dbc_json.py --out car_fingerprint_to_dbc.json') cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', - 'canmessages.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 678fe5f876..bcd2b88a81 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -165,14 +165,14 @@ void BinaryViewModel::setMessage(const QString &message_id) { if ((dbc_msg = dbc()->msg(msg_id))) { 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]; + int i = 0; + for (auto &[name, sig] : dbc_msg->sigs) { auto [start, end] = getSignalRange(&sig); for (int j = start; j <= end; ++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 " << sig.name.c_str() << "out of bounds.start_bit:" << sig.start_bit << "size:" << sig.size; + qWarning() << "signal " << name << "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; @@ -180,6 +180,7 @@ void BinaryViewModel::setMessage(const QString &message_id) { items[idx].bg_color = getColor(i); items[idx].sigs.push_back(&sig); } + ++i; } } else { row_count = can->lastMessage(msg_id).dat.size(); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 05bfe7e79f..2d6fc5c18b 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -50,7 +50,7 @@ public: private: QString msg_id; - const Msg *dbc_msg; + const DBCMsg *dbc_msg; int row_count = 0; const int column_count = 9; }; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3a170bccdc..875ed80ac5 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -240,7 +240,7 @@ void ChartView::resizeEvent(QResizeEvent *event) { void ChartView::updateTitle() { chart()->setTitle(signal->name.c_str()); - msg_title->setHtml(tr("%1 %2").arg(dbc()->msg(id)->name.c_str()).arg(id)); + msg_title->setHtml(tr("%1 %2").arg(dbc()->msg(id)->name).arg(id)); } void ChartView::updateFromSettings() { diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc new file mode 100644 index 0000000000..b3f5cb1c66 --- /dev/null +++ b/tools/cabana/commands.cc @@ -0,0 +1,75 @@ +#include "tools/cabana/commands.h" + +// EditMsgCommand + +EditMsgCommand::EditMsgCommand(const QString &id, const QString &title, int size, QUndoCommand *parent) + : id(id), new_title(title), new_size(size), QUndoCommand(parent) { + if (auto msg = dbc()->msg(id)) { + old_title = msg->name; + old_size = msg->size; + } + setText(QObject::tr("Edit message %1:%2").arg(DBCManager::parseId(id).second).arg(title)); +} + +void EditMsgCommand::undo() { + if (old_title.isEmpty()) + dbc()->removeMsg(id); + else + dbc()->updateMsg(id, old_title, old_size); +} + +void EditMsgCommand::redo() { + dbc()->updateMsg(id, new_title, new_size); +} + +// RemoveMsgCommand + +RemoveMsgCommand::RemoveMsgCommand(const QString &id, QUndoCommand *parent) : id(id), QUndoCommand(parent) { + if (auto msg = dbc()->msg(id)) { + message = *msg; + setText(QObject::tr("Remove message %1:%2").arg(DBCManager::parseId(id).second).arg(message.name)); + } +} + +void RemoveMsgCommand::undo() { + if (!message.name.isEmpty()) { + dbc()->updateMsg(id, message.name, message.size); + for (auto &[name, s] : message.sigs) + dbc()->addSignal(id, s); + } +} + +void RemoveMsgCommand::redo() { + if (!message.name.isEmpty()) + dbc()->removeMsg(id); +} + +// AddSigCommand + +AddSigCommand::AddSigCommand(const QString &id, const Signal &sig, QUndoCommand *parent) + : id(id), signal(sig), QUndoCommand(parent) { + setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(DBCManager::parseId(id).second)); +} + +void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name.c_str()); } +void AddSigCommand::redo() { dbc()->addSignal(id, signal); } + +// RemoveSigCommand + +RemoveSigCommand::RemoveSigCommand(const QString &id, const Signal *sig, QUndoCommand *parent) + : id(id), signal(*sig), QUndoCommand(parent) { + setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(DBCManager::parseId(id).second)); +} + +void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } +void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name.c_str()); } + +// EditSignalCommand + +EditSignalCommand::EditSignalCommand(const QString &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) + : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { + setText(QObject::tr("Edit signal %1").arg(old_signal.name.c_str())); +} + +void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name.c_str(), old_signal); } +void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name.c_str(), new_signal); } diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h new file mode 100644 index 0000000000..7ea1f66653 --- /dev/null +++ b/tools/cabana/commands.h @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "tools/cabana/canmessages.h" +#include "tools/cabana/dbcmanager.h" + +class EditMsgCommand : public QUndoCommand { +public: + EditMsgCommand(const QString &id, const QString &title, int size, QUndoCommand *parent = nullptr); + void undo() override; + void redo() override; + +private: + const QString id; + QString old_title, new_title; + int old_size = 0, new_size = 0; +}; + +class RemoveMsgCommand : public QUndoCommand { +public: + RemoveMsgCommand(const QString &id, QUndoCommand *parent = nullptr); + void undo() override; + void redo() override; + +private: + const QString id; + DBCMsg message; +}; + +class AddSigCommand : public QUndoCommand { +public: + AddSigCommand(const QString &id, const Signal &sig, QUndoCommand *parent = nullptr); + void undo() override; + void redo() override; + +private: + const QString id; + Signal signal = {}; +}; + +class RemoveSigCommand : public QUndoCommand { +public: + RemoveSigCommand(const QString &id, const Signal *sig, QUndoCommand *parent = nullptr); + void undo() override; + void redo() override; + +private: + const QString id; + Signal signal = {}; +}; + +class EditSignalCommand : public QUndoCommand { +public: + EditSignalCommand(const QString &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr); + void undo() override; + void redo() override; + +private: + const QString id; + Signal old_signal = {}; + Signal new_signal = {}; +}; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index abdd9a08df..ebad2387cf 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -10,32 +10,36 @@ DBCManager::~DBCManager() {} void DBCManager::open(const QString &dbc_file_name) { dbc = const_cast(dbc_lookup(dbc_file_name.toStdString())); - updateMsgMap(); - emit DBCFileChanged(); + initMsgMap(); } void DBCManager::open(const QString &name, const QString &content) { std::istringstream stream(content.toStdString()); dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); - updateMsgMap(); - emit DBCFileChanged(); + initMsgMap(); } -void DBCManager::updateMsgMap() { - msg_map.clear(); - for (auto &msg : dbc->msgs) - msg_map[msg.address] = &msg; +void DBCManager::initMsgMap() { + msgs.clear(); + for (auto &msg : dbc->msgs) { + auto &m = msgs[msg.address]; + m.name = msg.name.c_str(); + m.size = msg.size; + for (auto &s : msg.sigs) + m.sigs[QString::fromStdString(s.name)] = s; + } + emit DBCFileChanged(); } QString DBCManager::generateDBC() { if (!dbc) return {}; QString dbc_string; - for (auto &m : dbc->msgs) { - dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(m.address).arg(m.name.c_str()).arg(m.size); - for (auto &sig : m.sigs) { + for (auto &[address, m] : msgs) { + dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); + for (auto &[name, sig] : m.sigs) { dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [0|0] \"\" XXX\n") - .arg(sig.name.c_str()) + .arg(name) .arg(sig.start_bit) .arg(sig.size) .arg(sig.is_little_endian ? '1' : '0') @@ -49,48 +53,45 @@ QString DBCManager::generateDBC() { } void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size) { - auto [bus, address] = parseId(id); - if (auto m = const_cast(msg(address))) { - m->name = name.toStdString(); - m->size = size; - } else { - m = &dbc->msgs.emplace_back(Msg{.address = address, .name = name.toStdString(), .size = size}); - msg_map[address] = m; - } + auto [_, address] = parseId(id); + auto &m = msgs[address]; + m.name = name; + m.size = size; emit msgUpdated(address); } void DBCManager::removeMsg(const QString &id) { uint32_t address = parseId(id).second; - auto it = std::find_if(dbc->msgs.begin(), dbc->msgs.end(), [address](auto &m) { return m.address == address; }); - if (it != dbc->msgs.end()) { - dbc->msgs.erase(it); - updateMsgMap(); - emit msgRemoved(address); - } + msgs.erase(address); + emit msgRemoved(address); } void DBCManager::addSignal(const QString &id, const Signal &sig) { - if (Msg *m = const_cast(msg(id))) { - emit signalAdded(&m->sigs.emplace_back(sig)); + if (auto m = const_cast(msg(id))) { + auto &s = m->sigs[sig.name.c_str()]; + s = sig; + emit signalAdded(&s); } } void DBCManager::updateSignal(const QString &id, const QString &sig_name, const Signal &sig) { - 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)); - } + if (auto m = const_cast(msg(id))) { + // change key name + QString new_name = QString::fromStdString(sig.name); + auto node = m->sigs.extract(sig_name); + node.key() = new_name; + auto it = m->sigs.insert(std::move(node)); + auto &s = m->sigs[new_name]; + s = sig; + emit signalUpdated(&s); } } 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 (auto m = const_cast(msg(id))) { + auto it = m->sigs.find(sig_name); if (it != m->sigs.end()) { - emit signalRemoved(&(*it)); + emit signalRemoved(&(it->second)); m->sigs.erase(it); } } diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 81c723a20d..d2262527d4 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -1,9 +1,16 @@ #pragma once +#include #include - +#include #include "opendbc/can/common_dbc.h" +struct DBCMsg { + QString name; + uint32_t size; + std::map sigs; +}; + class DBCManager : public QObject { Q_OBJECT @@ -24,11 +31,11 @@ public: void updateMsg(const QString &id, const QString &name, uint32_t size); void removeMsg(const QString &id); - inline const DBC *getDBC() const { return dbc; } - inline const Msg *msg(const QString &id) const { return msg(parseId(id).second); } - inline const Msg *msg(uint32_t address) const { - auto it = msg_map.find(address); - return it != msg_map.end() ? it->second : nullptr; + inline const std::map &messages() const { return msgs; } + inline const DBCMsg *msg(const QString &id) const { return msg(parseId(id).second); } + inline const DBCMsg *msg(uint32_t address) const { + auto it = msgs.find(address); + return it != msgs.end() ? &it->second : nullptr; } signals: @@ -40,9 +47,9 @@ signals: void DBCFileChanged(); private: - void updateMsgMap(); + void initMsgMap(); DBC *dbc = nullptr; - std::unordered_map msg_map; + std::map msgs; }; // TODO: Add helper function in dbc.h @@ -54,5 +61,5 @@ std::pair getSignalRange(const Signal *s); DBCManager *dbc(); inline QString msgName(const QString &id, const char *def = "untitled") { auto msg = dbc()->msg(id); - return msg ? msg->name.c_str() : def; + return msg ? msg->name : def; } diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index f96b60847b..6d07727303 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -10,16 +10,19 @@ #include "selfdrive/ui/qt/util.h" #include "tools/cabana/canmessages.h" +#include "tools/cabana/commands.h" #include "tools/cabana/dbcmanager.h" // DetailWidget DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { + undo_stack = new QUndoStack(this); + QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); - // tabbar + // tabbar tabbar = new QTabBar(this); tabbar->setTabsClosable(true); tabbar->setDrawBase(false); @@ -99,6 +102,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); QObject::connect(charts, &ChartsWidget::chartOpened, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, true); }); QObject::connect(charts, &ChartsWidget::chartClosed, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, false); }); + QObject::connect(undo_stack, &QUndoStack::indexChanged, [this]() { dbcMsgChanged(); }); } void DetailWidget::showTabBarContextMenu(const QPoint &pt) { @@ -143,12 +147,17 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { if (msg_id.isEmpty()) return; setUpdatesEnabled(false); + + binary_view->setMessage(msg_id); + history_log->setMessage(msg_id); + QStringList warnings; for (auto f : signal_list) f->hide(); - const Msg *msg = dbc()->msg(msg_id); + const DBCMsg *msg = dbc()->msg(msg_id); if (msg) { - for (int i = 0; i < msg->sigs.size(); ++i) { + int i = 0; + for (auto &[name, sig] : msg->sigs) { SignalEdit *form = i < signal_list.size() ? signal_list[i] : nullptr; if (!form) { form = new SignalEdit(i); @@ -161,9 +170,10 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { signals_container->layout()->addWidget(form); signal_list.push_back(form); } - form->setSignal(msg_id, &(msg->sigs[i]), i == show_form_idx); - form->setChartOpened(charts->isChartOpened(msg_id, &(msg->sigs[i]))); + form->setSignal(msg_id, &sig, i == show_form_idx); + form->setChartOpened(charts->isChartOpened(msg_id, &sig)); form->show(); + ++i; } if (msg->size != can->lastMessage(msg_id).dat.size()) warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); @@ -173,9 +183,6 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { remove_msg_act->setEnabled(msg != nullptr); name_label->setText(msgName(msg_id)); - binary_view->setMessage(msg_id); - history_log->setMessage(msg_id); - // Check overlapping bits if (auto overlapping = binary_view->getOverlappingSignals(); !overlapping.isEmpty()) { for (auto s : overlapping) @@ -215,19 +222,13 @@ void DetailWidget::editMsg() { int size = msg ? msg->size : can->lastMessage(id).dat.size(); EditMessageDialog dlg(id, msgName(id), size, this); if (dlg.exec()) { - dbc()->updateMsg(id, dlg.name_edit->text(), dlg.size_spin->value()); - dbcMsgChanged(); + undo_stack->push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); } } void DetailWidget::removeMsg() { - QString id = msg_id; - if (auto msg = dbc()->msg(id)) { - QString text = tr("Are you sure you want to remove '%1'").arg(msg->name.c_str()); - if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove Message"), text)) { - dbc()->removeMsg(id); - dbcMsgChanged(); - } + if (auto msg = dbc()->msg(msg_id)) { + undo_stack->push(new RemoveMsgCommand(msg_id)); } } @@ -235,10 +236,10 @@ void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { auto msg = dbc()->msg(msg_id); if (!msg) { for (int i = 1; /**/; ++i) { - std::string name = "NEW_MSG_" + std::to_string(i); - auto it = std::find_if(dbc()->getDBC()->msgs.begin(), dbc()->getDBC()->msgs.end(), [&](auto &m) { return m.name == name; }); - if (it == dbc()->getDBC()->msgs.end()) { - dbc()->updateMsg(msg_id, name.c_str(), can->lastMessage(msg_id).dat.size()); + QString name = QString("NEW_MSG_%1").arg(i); + auto it = std::find_if(dbc()->messages().begin(), dbc()->messages().end(), [&](auto &m) { return m.second.name == name; }); + if (it == dbc()->messages().end()) { + undo_stack->push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size())); msg = dbc()->msg(msg_id); break; } @@ -247,13 +248,12 @@ void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { Signal sig = {}; for (int i = 1; /**/; ++i) { sig.name = "NEW_SIGNAL_" + std::to_string(i); - auto it = std::find_if(msg->sigs.begin(), msg->sigs.end(), [&](auto &s) { return sig.name == s.name; }); + auto it = msg->sigs.find(sig.name.c_str()); if (it == msg->sigs.end()) break; } sig.is_little_endian = little_endian; updateSigSizeParamsFromRange(sig, start_bit, size); - dbc()->addSignal(msg_id, sig); - dbcMsgChanged(msg->sigs.size() - 1); + undo_stack->push(new AddSigCommand(msg_id, sig)); } void DetailWidget::resizeSignal(const Signal *sig, int start_bit, int size) { @@ -265,14 +265,13 @@ void DetailWidget::resizeSignal(const Signal *sig, int start_bit, int size) { void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) { auto msg = dbc()->msg(msg_id); if (new_sig.name != sig->name) { - auto it = std::find_if(msg->sigs.begin(), msg->sigs.end(), [&](auto &s) { return s.name == new_sig.name; }); + auto it = msg->sigs.find(new_sig.name.c_str()); if (it != msg->sigs.end()) { QString warning_str = tr("There is already a signal with the same name '%1'").arg(new_sig.name.c_str()); QMessageBox::warning(this, tr("Failed to save signal"), warning_str); return; } } - auto [start, end] = getSignalRange(&new_sig); if (start < 0 || end >= msg->size * 8) { QString warning_str = tr("Signal size [%1] exceed limit").arg(new_sig.size); @@ -280,16 +279,11 @@ void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) { return; } - dbc()->updateSignal(msg_id, sig->name.c_str(), new_sig); - dbcMsgChanged(); + undo_stack->push(new EditSignalCommand(msg_id, sig, new_sig)); } void DetailWidget::removeSignal(const Signal *sig) { - QString text = tr("Are you sure you want to remove signal '%1'").arg(sig->name.c_str()); - if (QMessageBox::Yes == QMessageBox::question(this, tr("Remove signal"), text)) { - dbc()->removeSignal(msg_id, sig->name.c_str()); - dbcMsgChanged(); - } + undo_stack->push(new RemoveSigCommand(msg_id, sig)); } // EditMessageDialog diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 915e0bde60..dc40eae159 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" @@ -26,6 +27,7 @@ public: DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const QString &message_id); void dbcMsgChanged(int show_form_idx = -1); + QUndoStack *undo_stack = nullptr; private: void updateChartState(const QString &id, const Signal *sig, bool opened); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 4b1818cf68..28e344a46e 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -4,6 +4,10 @@ // HistoryLogModel +inline const Signal &get_signal(const DBCMsg *m, int index) { + return std::next(m->sigs.begin(), index)->second; +} + QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); if (role == Qt::DisplayRole) { @@ -11,7 +15,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { 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])) + return has_signal ? QString::number(get_raw_value((uint8_t *)m.dat.begin(), m.dat.size(), get_signal(dbc_msg, index.column() - 1))) : toHex(m.dat); } else if (role == Qt::FontRole && index.column() == 1 && !has_signal) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); @@ -37,7 +41,7 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return has_signal ? QString::fromStdString(dbc_msg->sigs[section - 1].name).replace('_', ' ') : "Data"; + return has_signal ? QString::fromStdString(get_signal(dbc_msg, section - 1).name).replace('_', ' ') : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && has_signal) { return QBrush(QColor(getColor(section - 1))); } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index e8b0f5a35b..21be8fc129 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -28,7 +28,7 @@ private: QString msg_id; int row_count = 0; int column_count = 2; - const Msg *dbc_msg = nullptr; + const DBCMsg *dbc_msg = nullptr; std::deque messages; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 9b85ba7e8d..b8913a3aa7 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include "tools/replay/util.h" @@ -41,9 +43,7 @@ MainWindow::MainWindow() : QMainWindow() { dbc_combo->addItem(QString::fromStdString(name)); } dbc_combo->model()->sort(0); - dbc_combo->setEditable(true); dbc_combo->setInsertPolicy(QComboBox::NoInsert); - dbc_combo->completer()->setCompletionMode(QCompleter::PopupCompletion); messages_layout->addWidget(dbc_combo); messages_widget = new MessagesWidget(this); @@ -102,9 +102,13 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); QObject::connect(can, &CANMessages::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { + detail_widget->undo_stack->clear(); dbc_combo->setCurrentText(QFileInfo(dbc()->name()).baseName()); setWindowTitle(tr("%1 - Cabana").arg(dbc()->name())); }); + QObject::connect(detail_widget->undo_stack, &QUndoStack::indexChanged, [this](int index) { + setWindowTitle(tr("%1%2 - Cabana").arg(index > 0 ? "* " : "").arg(dbc()->name())); + }); } void MainWindow::createActions() { @@ -116,6 +120,23 @@ void MainWindow::createActions() { file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveDBCToClipboard); file_menu->addSeparator(); file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption); + + QMenu *edit_menu = menuBar()->addMenu(tr("&Edit")); + auto undo_act = detail_widget->undo_stack->createUndoAction(this, tr("&Undo")); + undo_act->setShortcuts(QKeySequence::Undo); + edit_menu->addAction(undo_act); + auto redo_act = detail_widget->undo_stack->createRedoAction(this, tr("&Rndo")); + redo_act->setShortcuts(QKeySequence::Redo); + edit_menu->addAction(redo_act); + edit_menu->addSeparator(); + + QMenu *commands_menu = edit_menu->addMenu(tr("Command &List")); + auto undo_view = new QUndoView(detail_widget->undo_stack); + undo_view->setWindowTitle(tr("Command List")); + QWidgetAction *commands_act = new QWidgetAction(this); + commands_act->setDefaultWidget(undo_view); + commands_menu->addAction(commands_act); + QMenu *help_menu = menuBar()->addMenu(tr("&Help")); help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index d0aa2cbb4f..d2d9dc1d2a 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -10,26 +10,25 @@ TEST_CASE("DBCManager::generateDBC") { DBCManager dbc_from_generated(nullptr); dbc_from_generated.open("", dbc_string); - auto dbc = dbc_origin.getDBC(); - auto new_dbc = dbc_from_generated.getDBC(); - REQUIRE(dbc->msgs.size() == new_dbc->msgs.size()); - for (int i = 0; i < dbc->msgs.size(); ++i) { - REQUIRE(dbc->msgs[i].name == new_dbc->msgs[i].name); - REQUIRE(dbc->msgs[i].address == new_dbc->msgs[i].address); - REQUIRE(dbc->msgs[i].size == new_dbc->msgs[i].size); - REQUIRE(dbc->msgs[i].sigs.size() == new_dbc->msgs[i].sigs.size()); - auto &sig = dbc->msgs[i].sigs; - auto &new_sig = new_dbc->msgs[i].sigs; - for (int j = 0; j < sig.size(); ++j) { - REQUIRE(sig[j].name == new_sig[j].name); - REQUIRE(sig[j].start_bit == new_sig[j].start_bit); - REQUIRE(sig[j].msb == new_sig[j].msb); - REQUIRE(sig[j].lsb == new_sig[j].lsb); - REQUIRE(sig[j].size == new_sig[j].size); - REQUIRE(sig[j].is_signed == new_sig[j].is_signed); - REQUIRE(sig[j].factor == new_sig[j].factor); - REQUIRE(sig[j].offset == new_sig[j].offset); - REQUIRE(sig[j].is_little_endian == new_sig[j].is_little_endian); + auto &msgs = dbc_origin.messages(); + auto &new_msgs = dbc_from_generated.messages(); + REQUIRE(msgs.size() == new_msgs.size()); + for (auto &[address, m] : msgs) { + auto new_m = new_msgs.at(address); + REQUIRE(m.name == new_m.name); + REQUIRE(m.size == new_m.size); + REQUIRE(m.sigs.size() == new_m.sigs.size()); + for (auto &[name, sig] : m.sigs) { + auto &new_sig = new_m.sigs[name]; + REQUIRE(sig.name == new_sig.name); + REQUIRE(sig.start_bit == new_sig.start_bit); + REQUIRE(sig.msb == new_sig.msb); + REQUIRE(sig.lsb == new_sig.lsb); + REQUIRE(sig.size == new_sig.size); + REQUIRE(sig.is_signed == new_sig.is_signed); + REQUIRE(sig.factor == new_sig.factor); + REQUIRE(sig.offset == new_sig.offset); + REQUIRE(sig.is_little_endian == new_sig.is_little_endian); } } } From 122c0ec135804ac6a106f1e06f4cb3467fb13b1a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 11 Nov 2022 02:37:52 +0800 Subject: [PATCH 0251/1179] Cabana: remember last directory in open file dialog (#26449) * remember last directory in open file dialog * use QFileInfo --- tools/cabana/mainwin.cc | 8 ++++++-- tools/cabana/settings.cc | 5 ++++- tools/cabana/settings.h | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index b8913a3aa7..7ae97379f6 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -156,8 +156,9 @@ void MainWindow::loadDBCFromName(const QString &name) { } void MainWindow::loadDBCFromFile() { - QString file_name = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::homePath(), "DBC (*.dbc)"); + QString file_name = QFileDialog::getOpenFileName(this, tr("Open File"), settings.last_dir, "DBC (*.dbc)"); if (!file_name.isEmpty()) { + settings.last_dir = QFileInfo(file_name).absolutePath(); QFile file(file_name); if (file.open(QIODevice::ReadOnly)) { auto dbc_name = QFileInfo(file_name).baseName(); @@ -185,8 +186,9 @@ void MainWindow::loadDBCFromFingerprint() { void MainWindow::saveDBCToFile() { QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), - QDir::homePath() + "/untitled.dbc", tr("DBC (*.dbc)")); + QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); if (!file_name.isEmpty()) { + settings.last_dir = QFileInfo(file_name).absolutePath(); QFile file(file_name); if (file.open(QIODevice::WriteOnly)) file.write(dbc()->generateDBC().toUtf8()); @@ -228,6 +230,8 @@ void MainWindow::closeEvent(QCloseEvent *event) { main_win = nullptr; if (floating_window) floating_window->deleteLater(); + + settings.save(); QWidget::closeEvent(event); } diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index b173b41df3..b3a4ed4872 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -1,6 +1,7 @@ #include "tools/cabana/settings.h" #include +#include #include #include @@ -19,7 +20,7 @@ void Settings::save() { s.setValue("chart_height", chart_height); s.setValue("chart_theme", chart_theme); s.setValue("max_chart_x_range", max_chart_x_range); - emit changed(); + s.setValue("last_dir", last_dir); } void Settings::load() { @@ -30,6 +31,7 @@ void Settings::load() { chart_height = s.value("chart_height", 200).toInt(); 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(); } // SettingsDlg @@ -90,4 +92,5 @@ void SettingsDlg::save() { settings.max_chart_x_range = max_chart_x_range->value() * 60; settings.save(); accept(); + emit settings.changed(); } diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index cb858de873..e08d0ae55e 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -18,6 +18,7 @@ public: int chart_height = 200; int chart_theme = 0; int max_chart_x_range = 3 * 60; // 3 minutes + QString last_dir; signals: void changed(); From 2961f8a7d8b891dd95912e0d21f54cf1f4afb696 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Thu, 10 Nov 2022 17:27:25 -0300 Subject: [PATCH 0252/1179] Multilang: Update pt-BR translations (#26444) * update pt-BR translations * fix some cutoff texts * Delete main_pt-BR.ts * Add files via upload * Delete main_pt-BR.ts * Add files via upload --- selfdrive/ui/translations/main_pt-BR.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 702702a8be..6a1d32f87a 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1012,7 +1012,7 @@ trabalho definido 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - + openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: <br> <h4>🌮 Controle Longitudinal de Ponta a Ponta 🌮</h4> Deixe o modelo de condução controlar o acelerador e os freios. Uma vez que o modelo de condução decide qual velocidade dirigir, a velocidade definida só funcionará como um limite superior. openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. @@ -1020,7 +1020,7 @@ trabalho definido WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - + ATENÇÃO: o controle longitudinal do openpilot é experimental para este carro e desativará a Frenagem Automática de Emergência (AEB). From e08896c45d84f4005de156317ae902d601e9b895 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 11 Nov 2022 04:57:52 +0800 Subject: [PATCH 0253/1179] Cabana: confirm exit without saving (#26452) * confirm exit without saving * typo --- tools/cabana/mainwin.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 7ae97379f6..40a99a7a56 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -227,6 +227,16 @@ void MainWindow::dockCharts(bool dock) { } void MainWindow::closeEvent(QCloseEvent *event) { + if (detail_widget->undo_stack->index() > 0) { + auto ret = QMessageBox::question(this, tr("Unsaved Changes"), + tr("Are you sure you want to exit without saving?\nAny unsaved changes will be lost."), + QMessageBox::Yes | QMessageBox::No); + if (ret == QMessageBox::No) { + event->ignore(); + return; + } + } + main_win = nullptr; if (floating_window) floating_window->deleteLater(); From df145ae99f80d53667533f848b661768b7d5c269 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Fri, 11 Nov 2022 09:56:28 +0900 Subject: [PATCH 0254/1179] Multilang: kor translation update (#26445) * Multilang: kor translation update * fix --- selfdrive/ui/translations/main_ko.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 0bbae22517..31c910a910 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1004,11 +1004,11 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - + openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 <br> <h4>🌮 E2E 롱컨트롤 🌮</h4> 주행모델이 가속과 감속을 제어하도록 합니다. openpilot은 신호등과 정지표지판을 보고 멈추는 것을 포함하여 운전자가 생각하는것처럼 주행합니다. 주행 모델이 주행할 속도를 결정하므로 설정된 속도는 상한선으로만 작용합니다. openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. @@ -1016,7 +1016,7 @@ location set WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - + 경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 자동긴급제동(AEB)를 비활성화합니다. From f5bf3cd21bef0069e0f470ad79ccac3da361a295 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 10 Nov 2022 18:37:10 -0800 Subject: [PATCH 0255/1179] boardd: verify SPI checksum (#26454) * verify checksum * import from panda Co-authored-by: Comma Device --- selfdrive/boardd/panda_comms.h | 12 ++- selfdrive/boardd/spi.cc | 142 +++++++++++++++++---------------- 2 files changed, 81 insertions(+), 73 deletions(-) diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index 08d0c1a2af..aef7b41d07 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -5,11 +5,16 @@ #include #include +#include + #include + #define TIMEOUT 0 #define SPI_BUF_SIZE 1024 +const bool PANDA_NO_RETRY = getenv("PANDA_NO_RETRY"); + // comms base class class PandaCommsHandle { @@ -65,9 +70,10 @@ public: private: int spi_fd = -1; - int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); - int wait_for_ack(); - uint8_t tx_buf[SPI_BUF_SIZE]; uint8_t rx_buf[SPI_BUF_SIZE]; + + int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack); + int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); + int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); }; diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 1ec5e89c71..3969b313f0 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -6,6 +6,7 @@ #include "common/util.h" #include "common/swaglog.h" +#include "panda/board/comms_definitions.h" #include "selfdrive/boardd/panda_comms.h" @@ -22,13 +23,6 @@ struct __attribute__((packed)) spi_header { uint16_t max_rx_len; }; -struct __attribute__((packed)) spi_control_packet { - uint16_t request; - uint16_t param1; - uint16_t param2; - uint16_t length; -}; - PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { LOGD("opening SPI panda: %s", serial.c_str()); @@ -40,7 +34,7 @@ PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { spi_fd = open(serial.c_str(), O_RDWR); if (spi_fd < 0) { - LOGE("failed setting SPI mode %d", err); + LOGE("failed opening SPI device %d", err); goto fail; } @@ -85,41 +79,23 @@ void PandaSpiHandle::cleanup() { int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout) { - int err; - - std::lock_guard lk(hw_lock); - do { - spi_control_packet packet = { - .request = request, - .param1 = param1, - .param2 = param2, - .length = 0 - }; - - // TODO: handle error - err = spi_transfer(0, (uint8_t *) &packet, sizeof(packet), NULL, 0); - } while (err < 0 && connected); - - return err; + ControlPacket_t packet = { + .request = request, + .param1 = param1, + .param2 = param2, + .length = 0 + }; + return spi_transfer_retry(0, (uint8_t *) &packet, sizeof(packet), NULL, 0); } int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout) { - int err; - - std::lock_guard lk(hw_lock); - do { - spi_control_packet packet = { - .request = request, - .param1 = param1, - .param2 = param2, - .length = length - }; - - // TODO: handle error - err = spi_transfer(0, (uint8_t *) &packet, sizeof(packet), data, length); - } while (err < 0 && connected); - - return err; + ControlPacket_t packet = { + .request = request, + .param1 = param1, + .param2 = param2, + .length = length + }; + return spi_transfer_retry(0, (uint8_t *) &packet, sizeof(packet), data, length); } int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { @@ -144,6 +120,46 @@ void add_checksum(uint8_t *data, int data_len) { } } +bool check_checksum(uint8_t *data, int data_len) { + uint8_t checksum = SPI_CHECKSUM_START; + for (uint16_t i = 0U; i < data_len; i++) { + checksum ^= data[i]; + } + return checksum == 0U; +} + + +int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { + int err; + + std::lock_guard lk(hw_lock); + do { + // TODO: handle error + err = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); + } while (err < 0 && connected && !PANDA_NO_RETRY); + + return err; +} + +int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { + // TODO: add timeout? + while (true) { + int ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); + if (ret < 0) { + LOGE("SPI: failed to send ACK request"); + return ret; + } + + if (rx_buf[0] == ack) { + break; + } else if (rx_buf[0] == SPI_NACK) { + LOGW("SPI: got header NACK"); + return -1; + } + } + + return 0; +} int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { int ret; @@ -178,19 +194,9 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx // Wait for (N)ACK tx_buf[0] = 0x12; transfer.len = 1; - while (true) { - ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); - if (ret < 0) { - LOGE("SPI: failed to send ACK request"); - goto transfer_fail; - } - - if (rx_buf[0] == SPI_HACK) { - break; - } else if (rx_buf[0] == SPI_NACK) { - LOGW("SPI: got header NACK"); - goto transfer_fail; - } + ret = wait_for_ack(transfer, SPI_HACK); + if (ret < 0) { + goto transfer_fail; } // Send data @@ -208,44 +214,40 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx // Wait for (N)ACK tx_buf[0] = 0xab; transfer.len = 1; - while (true) { - ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); - if (ret < 0) { - LOGE("SPI: failed to send ACK request"); - goto transfer_fail; - } - - if (rx_buf[0] == SPI_DACK) { - break; - } else if (rx_buf[0] == SPI_NACK) { - LOGE("SPI: got data NACK"); - goto transfer_fail; - } + ret = wait_for_ack(transfer, SPI_DACK); + if (ret < 0) { + goto transfer_fail; } // Read data len transfer.len = 2; + transfer.rx_buf = (uint64_t)(rx_buf + 1); ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); if (ret < 0) { LOGE("SPI: failed to read rx data len"); goto transfer_fail; } - rx_data_len = *(uint16_t *)rx_buf; + rx_data_len = *(uint16_t *)(rx_buf+1); assert(rx_data_len < SPI_BUF_SIZE); // Read data transfer.len = rx_data_len + 1; + transfer.rx_buf = (uint64_t)(rx_buf + 2 + 1); ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); if (ret < 0) { LOGE("SPI: failed to read rx data"); goto transfer_fail; } - // TODO: check checksum + if (!check_checksum(rx_buf, rx_data_len + 4)) { + LOGE("SPI: bad checksum"); + goto transfer_fail; + } if (rx_data != NULL) { - memcpy(rx_data, rx_buf, rx_data_len); + memcpy(rx_data, rx_buf + 3, rx_data_len); } - ret = rx_data_len; + + return rx_data_len; transfer_fail: return ret; From 765761d7d0e813a3397728dcbe81a23a30051288 Mon Sep 17 00:00:00 2001 From: eFini Date: Fri, 11 Nov 2022 11:02:58 +0800 Subject: [PATCH 0256/1179] Multilang: add missing Chinese (Traditional) translations (#26433) * update cht translation * fix ellipsis -> spaces Co-authored-by: Shane Smiskol --- selfdrive/ui/translations/main_zh-CHT.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 0f6bc981cf..c9810597b5 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -60,11 +60,11 @@ Cellular Metered - + 行動網路 Prevent large data uploads when on a metered connection - + 防止使用行動網路上傳大量的數據 @@ -240,11 +240,11 @@ Reset - + 重設 Review - + 回顧 @@ -864,7 +864,7 @@ location set Uninstall - + 卸載 @@ -1004,19 +1004,19 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - + openpilot 默認以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。 實驗功能如下: <br> <h4>🌮端到端縱向控制🌮</h4> 讓駕駛模型控制油門和剎車。 openpilot 將像人類一樣駕駛,包括紅燈和停車標誌時停車,因為是由駕駛模型來決定車速,所以定速的設定值只會作為上限。 openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - + openpilot 默認使用汽車內置的主動巡航控制 (ACC),而不是使用 openpilot 縱向控制。啟用此選項可切換到 openpilot 縱向控制。 WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - + 警告:openpilot 縱向控制在這輛車上仍屬實驗性質,啟用後會喪失自動緊急煞車 (AEB) 功能。 @@ -1074,7 +1074,7 @@ location set Forget - + 清除 From 74b6e22a7dc8e0b1ec051f00037506d23a017ae8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 10 Nov 2022 19:06:31 -0800 Subject: [PATCH 0257/1179] controls: disengage on regen paddle independently (#26453) * add regen braking field that's just used to add a pedalPressed * bump * bump * Update ref_commit * we want the standstill check we want the standstill check * see what diff is now * Update ref_commit --- cereal | 2 +- selfdrive/car/gm/carstate.py | 2 +- selfdrive/car/tests/test_models.py | 4 ++-- selfdrive/controls/controlsd.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cereal b/cereal index cdba1aafec..afafa0a2a5 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit cdba1aafec5e36505ef6ace675568e1f15003c47 +Subproject commit afafa0a2a537d775842ab2e1bf20cb9a33b34f9a diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index f4b3f88e99..df1b4b2866 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -63,7 +63,7 @@ class CarState(CarStateBase): # Regen braking is braking if self.CP.transmissionType == TransmissionType.direct: - ret.brakePressed = ret.brakePressed or pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0 + ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0 ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254. ret.gasPressed = ret.gas > 1e-5 diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index ee25b8205f..56530dd738 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -251,8 +251,8 @@ class TestCarModelBase(unittest.TestCase): if CS.brakePressed and not self.safety.get_brake_pressed_prev(): if self.CP.carFingerprint in (HONDA.PILOT, HONDA.PASSPORT, HONDA.RIDGELINE) and CS.brake > 0.05: brake_pressed = False - safety_brake_pressed = self.safety.get_brake_pressed_prev() or self.safety.get_regen_braking_prev() - checks['brakePressed'] += brake_pressed != safety_brake_pressed + checks['brakePressed'] += brake_pressed != self.safety.get_brake_pressed_prev() + checks['regenBraking'] += CS.regenBraking != self.safety.get_regen_braking_prev() if self.CP.pcmCruise: # On most pcmCruise cars, openpilot's state is always tied to the PCM's cruise state. diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 0bdaadf6ef..3b241045b1 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -250,7 +250,8 @@ class Controls: # Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0 if (CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator) or \ - (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)): + (CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) or \ + (CS.regenBraking and (not self.CS_prev.regenBraking or not CS.standstill)): self.events.add(EventName.pedalPressed) if CS.gasPressed: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index cac678ca1f..e3c5390c3b 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a36f7e2fd922fcadca6f8a3d777f4db787cba016 +9e37e8ee8013515cfd75cf352a1a2b9aa447c441 From b549e8174e4f8ccd2be3c324e47333e721db3914 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 10 Nov 2022 21:10:34 -0800 Subject: [PATCH 0258/1179] agnos 6.2 (#26441) * agnos 6.2 * staging manifest * production --- launch_env.sh | 2 +- system/hardware/tici/agnos.json | 12 ++++++------ system/hardware/tici/hardware.py | 3 --- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/launch_env.sh b/launch_env.sh index 88e1f2a9c5..3059ec268e 100755 --- a/launch_env.sh +++ b/launch_env.sh @@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1 export VECLIB_MAXIMUM_THREADS=1 if [ -z "$AGNOS_VERSION" ]; then - export AGNOS_VERSION="6.1" + export AGNOS_VERSION="6.2" fi if [ -z "$PASSIVE" ]; then diff --git a/system/hardware/tici/agnos.json b/system/hardware/tici/agnos.json index 8534c8a978..7876b1af1f 100644 --- a/system/hardware/tici/agnos.json +++ b/system/hardware/tici/agnos.json @@ -1,9 +1,9 @@ [ { "name": "boot", - "url": "https://commadist.azureedge.net/agnosupdate/boot-57626d7737ab2fa1318e8707a202b1295b5da79ad2fa0a36377cc9481ad0d136.img.xz", - "hash": "57626d7737ab2fa1318e8707a202b1295b5da79ad2fa0a36377cc9481ad0d136", - "hash_raw": "57626d7737ab2fa1318e8707a202b1295b5da79ad2fa0a36377cc9481ad0d136", + "url": "https://commadist.azureedge.net/agnosupdate/boot-72662ec5d586c7a22659a1c8b140932d5472914176020fe76ba4204edbbb214a.img.xz", + "hash": "72662ec5d586c7a22659a1c8b140932d5472914176020fe76ba4204edbbb214a", + "hash_raw": "72662ec5d586c7a22659a1c8b140932d5472914176020fe76ba4204edbbb214a", "size": 14780416, "sparse": false, "full_check": true, @@ -41,9 +41,9 @@ }, { "name": "system", - "url": "https://commadist.azureedge.net/agnosupdate/system-b40b08912576bb972907acba7c201c1399395cbc0cba06ce6e5e3f70ab565cb5.img.xz", - "hash": "6e8fbcc21a265f7f58062abce7675dc05540e2b60cee2df56992a151ba64936f", - "hash_raw": "b40b08912576bb972907acba7c201c1399395cbc0cba06ce6e5e3f70ab565cb5", + "url": "https://commadist.azureedge.net/agnosupdate/system-9efdc9368f05e06008a7a1dbbee21b564e89988dc94d6ddee3a3a88e42268f0e.img.xz", + "hash": "48209ce7e8cc2fff4ec024f0cd82fc2e3e097b5c0629be2b292acf64e6701449", + "hash_raw": "9efdc9368f05e06008a7a1dbbee21b564e89988dc94d6ddee3a3a88e42268f0e", "size": 10737418240, "sparse": true, "full_check": false, diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index c5b931ddae..e2fd20c1be 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -431,9 +431,6 @@ class Tici(HardwareBase): def initialize_hardware(self): self.amplifier.initialize_configuration() - # TODO: this should go in AGNOS - os.system("sudo chmod 666 /dev/spidev0.0") - # Allow thermald to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") From f23296bc87a79c59d9ab011f2ba35ed1049beb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 11 Nov 2022 10:46:03 -0500 Subject: [PATCH 0259/1179] Add force decel to e2e long (#26448) * add force decel to e2e * Update longitudinal_planner.py --- .../controls/lib/longitudinal_mpc_lib/long_mpc.py | 14 +++++++------- selfdrive/controls/lib/longitudinal_planner.py | 9 ++++++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 080782ad0f..6b79813117 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -301,8 +301,10 @@ class LongitudinalMpc: return lead_xv def set_accel_limits(self, min_a, max_a): + # TODO this sets a max accel limit, but the minimum limit is only for cruise decel + # needs refactor self.cruise_min_a = min_a - self.cruise_max_a = max_a + self.max_a = max_a def update(self, carstate, radarstate, v_cruise, x, v, a, j): v_ego = self.x0[1] @@ -317,16 +319,17 @@ class LongitudinalMpc: lead_0_obstacle = lead_xv_0[:,0] + get_stopped_equivalence_factor(lead_xv_0[:,1]) lead_1_obstacle = lead_xv_1[:,0] + get_stopped_equivalence_factor(lead_xv_1[:,1]) + self.params[:,0] = MIN_ACCEL + self.params[:,1] = self.max_a + # Update in ACC mode or ACC/e2e blend if self.mode == 'acc': - self.params[:,0] = MIN_ACCEL - self.params[:,1] = self.cruise_max_a self.params[:,5] = LEAD_DANGER_FACTOR # Fake an obstacle for cruise, this ensures smooth acceleration to set speed # when the leads are no factor. v_lower = v_ego + (T_IDXS * self.cruise_min_a * 1.05) - v_upper = v_ego + (T_IDXS * self.cruise_max_a * 1.05) + v_upper = v_ego + (T_IDXS * self.max_a * 1.05) v_cruise_clipped = np.clip(v_cruise * np.ones(N+1), v_lower, v_upper) @@ -338,9 +341,6 @@ class LongitudinalMpc: x[:], v[:], a[:], j[:] = 0.0, 0.0, 0.0, 0.0 elif self.mode == 'blended': - self.params[:,0] = MIN_ACCEL - self.params[:,1] = MAX_ACCEL - self.params[:,5] = 1.0 x_obstacles = np.column_stack([lead_0_obstacle, diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 2fa13bfb15..cae378453c 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -10,7 +10,7 @@ from common.params import Params from common.realtime import DT_MDL from selfdrive.modeld.constants import T_IDXS from selfdrive.controls.lib.longcontrol import LongCtrlState -from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc +from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc, MIN_ACCEL, MAX_ACCEL from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, CONTROL_N from system.swaglog import cloudlog @@ -103,8 +103,11 @@ class LongitudinalPlanner: # No change cost when user is controlling the speed, or when standstill prev_accel_constraint = not (reset_state or sm['carState'].standstill) - accel_limits = [A_CRUISE_MIN, get_max_accel(v_ego)] - accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngleDeg, accel_limits, self.CP) + if self.mpc.mode == 'acc': + accel_limits = [A_CRUISE_MIN, get_max_accel(v_ego)] + accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngleDeg, accel_limits, self.CP) + else: + accel_limits_turns = [MIN_ACCEL, MAX_ACCEL] if reset_state: self.v_desired_filter.x = v_ego From 6cf9fff9193f3d61c81de65e88ba9ea908552062 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 12 Nov 2022 02:34:25 +0800 Subject: [PATCH 0260/1179] Cabana: fix segfault on exit (#26465) fix segfault on exit --- tools/cabana/detailwidget.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 6d07727303..8549ed4641 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -102,7 +102,10 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); QObject::connect(charts, &ChartsWidget::chartOpened, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, true); }); QObject::connect(charts, &ChartsWidget::chartClosed, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, false); }); - QObject::connect(undo_stack, &QUndoStack::indexChanged, [this]() { dbcMsgChanged(); }); + QObject::connect(undo_stack, &QUndoStack::indexChanged, [this]() { + if (undo_stack->count() > 0) + dbcMsgChanged(); + }); } void DetailWidget::showTabBarContextMenu(const QPoint &pt) { From 3c507e8ad7a4de1d03402b178389de2bee9c4363 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 12 Nov 2022 02:34:49 +0800 Subject: [PATCH 0261/1179] Cabana: auto update signal on field changes (#26464) * auto update signal on field changes * better icon --- tools/cabana/dbcmanager.cc | 8 +++ tools/cabana/dbcmanager.h | 2 + tools/cabana/detailwidget.cc | 69 ++++++-------------- tools/cabana/detailwidget.h | 5 +- tools/cabana/signaledit.cc | 105 +++++++++++++++--------------- tools/cabana/signaledit.h | 22 ++++--- tools/cabana/tests/test_cabana.cc | 18 +---- 7 files changed, 99 insertions(+), 130 deletions(-) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index ebad2387cf..18f103d34c 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -165,3 +165,11 @@ std::pair getSignalRange(const Signal *s) { int to = from + s->size - 1; return {from, to}; } + +bool operator==(const Signal &l, const Signal &r) { + return l.name == r.name && l.size == r.size && + l.start_bit == r.start_bit && + l.msb == r.msb && l.lsb == r.lsb && + l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian && + l.factor == r.factor && l.offset == r.offset; +} diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index d2262527d4..b1d2082969 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -54,6 +54,8 @@ private: // TODO: Add helper function in dbc.h double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig); +bool operator==(const Signal &l, const Signal &r); +inline bool operator!=(const Signal &l, const Signal &r) { return !(l == r); } int bigEndianStartBitsIndex(int start_bit); int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 8549ed4641..25c3a528f9 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -6,7 +6,6 @@ #include #include #include -#include #include "selfdrive/ui/qt/util.h" #include "tools/cabana/canmessages.h" @@ -81,9 +80,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart container_layout->addWidget(binary_view); // signals - signals_container = new QWidget(this); - signals_container->setLayout(new QVBoxLayout); - container_layout->addWidget(signals_container); + signals_layout = new QVBoxLayout(); + container_layout->addLayout(signals_layout); // history log history_log = new HistoryLog(this); @@ -114,36 +112,25 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { QMenu menu(this); menu.addAction(tr("Close Other Tabs")); if (menu.exec(tabbar->mapToGlobal(pt))) { - tabbar->setCurrentIndex(index); - // remove all tabs before the one to keep - for (int i = 0; i < index; ++i) { - tabbar->removeTab(0); - } - // remove all tabs after the one to keep - while (tabbar->count() > 1) { + tabbar->moveTab(index, 0); + tabbar->setCurrentIndex(0); + while (tabbar->count() > 1) tabbar->removeTab(1); - } } } } void DetailWidget::setMessage(const QString &message_id) { - if (message_id.isEmpty()) return; - - int index = -1; - for (int i = 0; i < tabbar->count(); ++i) { - if (tabbar->tabText(i) == message_id) { - index = i; - break; - } - } msg_id = message_id; + int index = tabbar->count() - 1; + for (/**/; index >= 0 && tabbar->tabText(index) != msg_id; --index) { /**/ } if (index == -1) { index = tabbar->addTab(message_id); tabbar->setTabToolTip(index, msgName(message_id)); } tabbar->setCurrentIndex(index); dbcMsgChanged(); + scroll->verticalScrollBar()->setValue(0); } void DetailWidget::dbcMsgChanged(int show_form_idx) { @@ -154,48 +141,42 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { binary_view->setMessage(msg_id); history_log->setMessage(msg_id); + int i = 0; QStringList warnings; - for (auto f : signal_list) f->hide(); - const DBCMsg *msg = dbc()->msg(msg_id); if (msg) { - int i = 0; for (auto &[name, sig] : msg->sigs) { SignalEdit *form = i < signal_list.size() ? signal_list[i] : nullptr; if (!form) { form = new SignalEdit(i); - QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); QObject::connect(form, &SignalEdit::showChart, charts, &ChartsWidget::showChart); - signals_container->layout()->addWidget(form); + signals_layout->addWidget(form); signal_list.push_back(form); } - form->setSignal(msg_id, &sig, i == show_form_idx); + form->setSignal(msg_id, &sig); form->setChartOpened(charts->isChartOpened(msg_id, &sig)); - form->show(); ++i; } if (msg->size != can->lastMessage(msg_id).dat.size()) warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } + for (/**/; i < signal_list.size(); ++i) + signal_list[i]->hide(); toolbar->setVisible(!msg_id.isEmpty()); remove_msg_act->setEnabled(msg != nullptr); name_label->setText(msgName(msg_id)); - // Check overlapping bits - if (auto overlapping = binary_view->getOverlappingSignals(); !overlapping.isEmpty()) { - for (auto s : overlapping) - warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); - } + for (auto s : binary_view->getOverlappingSignals()) + warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); warning_label->setText(warnings.join('\n')); warning_widget->setVisible(!warnings.isEmpty()); - setUpdatesEnabled(true); - scroll->verticalScrollBar()->setValue(0); + QTimer::singleShot(1, [this]() { setUpdatesEnabled(true); }); } void DetailWidget::updateState() { @@ -206,14 +187,6 @@ void DetailWidget::updateState() { history_log->updateState(); } -void DetailWidget::showForm() { - SignalEdit *sender = qobject_cast(QObject::sender()); - setUpdatesEnabled(false); - for (auto f : signal_list) - f->setFormVisible(f == sender && !f->isFormVisible()); - QTimer::singleShot(1, [this]() { setUpdatesEnabled(true); }); -} - void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool opened) { for (auto f : signal_list) if (f->msg_id == id && f->sig == sig) f->setChartOpened(opened); @@ -230,9 +203,7 @@ void DetailWidget::editMsg() { } void DetailWidget::removeMsg() { - if (auto msg = dbc()->msg(msg_id)) { - undo_stack->push(new RemoveMsgCommand(msg_id)); - } + undo_stack->push(new RemoveMsgCommand(msg_id)); } void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { @@ -248,13 +219,11 @@ void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { } } } - Signal sig = {}; + Signal sig = {.is_little_endian = little_endian}; for (int i = 1; /**/; ++i) { sig.name = "NEW_SIGNAL_" + std::to_string(i); - auto it = msg->sigs.find(sig.name.c_str()); - if (it == msg->sigs.end()) break; + if (msg->sigs.count(sig.name.c_str()) == 0) break; } - sig.is_little_endian = little_endian; updateSigSizeParamsFromRange(sig, start_bit, size); undo_stack->push(new AddSigCommand(msg_id, sig)); } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index dc40eae159..815afa9bce 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -11,8 +11,6 @@ #include "tools/cabana/signaledit.h" class EditMessageDialog : public QDialog { - Q_OBJECT - public: EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent); @@ -38,13 +36,12 @@ private: void removeSignal(const Signal *sig); void editMsg(); void removeMsg(); - void showForm(); void updateState(); QString msg_id; QLabel *name_label, *time_label, *warning_label; QWidget *warning_widget; - QWidget *signals_container; + QVBoxLayout *signals_layout; QTabBar *tabbar; QToolBar *toolbar; QAction *remove_msg_act; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 99365294b8..1cf9b8ae57 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,12 +1,11 @@ #include "tools/cabana/signaledit.h" -#include #include #include #include -#include -#include #include +#include +#include #include #include "selfdrive/ui/qt/util.h" @@ -15,7 +14,6 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { QFormLayout *form_layout = new QFormLayout(this); - form_layout->setContentsMargins(0, 0, 0, 0); name = new QLineEdit(); form_layout->addRow(tr("Name"), name); @@ -58,6 +56,13 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { form_layout->addRow(tr("Maximum value"), max_val); val_desc = new QLineEdit(); form_layout->addRow(tr("Value descriptions"), val_desc); + + QObject::connect(name, &QLineEdit::textEdited, this, &SignalForm::changed); + QObject::connect(factor, &QLineEdit::textEdited, this, &SignalForm::changed); + QObject::connect(offset, &QLineEdit::textEdited, this, &SignalForm::changed); + QObject::connect(sign, SIGNAL(activated(int)), SIGNAL(changed())); + QObject::connect(endianness, SIGNAL(activated(int)), SIGNAL(changed())); + QObject::connect(size, SIGNAL(valueChanged(int)), SIGNAL(changed())); } // SignalEdit @@ -67,36 +72,25 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa main_layout->setContentsMargins(0, 0, 0, 0); // title bar - QHBoxLayout *title_layout = new QHBoxLayout(); + auto toolbar = new QToolBar(this); + toolbar->setStyleSheet("QToolButton {width:15px;height:15px;font-size:15px}"); icon = new QLabel(); - title_layout->addWidget(icon); + toolbar->addWidget(icon); title = new ElidedLabel(this); + title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); title->setStyleSheet(QString("font-weight:bold; color:%1").arg(getColor(index))); - title_layout->addWidget(title, 1); - - QPushButton *seek_btn = new QPushButton("⌕"); - seek_btn->setStyleSheet("QPushButton{font-weight:bold;font-size:18px}"); + toolbar->addWidget(title); + plot_btn = toolbar->addAction("", [this]() { emit showChart(msg_id, sig, !chart_opened); }); + auto seek_btn = toolbar->addAction(QIcon::fromTheme("edit-find"), "", [this]() { SignalFindDlg(msg_id, sig, this).exec(); }); seek_btn->setToolTip(tr("Find signal values")); - seek_btn->setFixedSize(25, 25); - title_layout->addWidget(seek_btn); - - plot_btn = new QPushButton(this); - plot_btn->setStyleSheet("QPushButton {font-size:18px}"); - plot_btn->setFixedSize(25, 25); - title_layout->addWidget(plot_btn); - main_layout->addLayout(title_layout); + auto remove_btn = toolbar->addAction("x", [this]() { emit remove(sig); }); + remove_btn->setToolTip(tr("Remove signal")); + main_layout->addWidget(toolbar); // signal form - form_container = new QWidget(this); - QVBoxLayout *v_layout = new QVBoxLayout(form_container); - QHBoxLayout *h = new QHBoxLayout(); - QPushButton *remove_btn = new QPushButton(tr("Remove Signal")); - h->addWidget(remove_btn); - h->addStretch(); - QPushButton *save_btn = new QPushButton(tr("Save")); - h->addWidget(save_btn); - v_layout->addLayout(h); - main_layout->addWidget(form_container); + form = new SignalForm(this); + form->setVisible(false); + main_layout->addWidget(form); // bottom line QFrame *hline = new QFrame(); @@ -104,25 +98,22 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa hline->setFrameShadow(QFrame::Sunken); main_layout->addWidget(hline); - QObject::connect(remove_btn, &QPushButton::clicked, [this]() { emit remove(this->sig); }); + QObject::connect(form, &SignalForm::changed, this, &SignalEdit::saveSignal); QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); - QObject::connect(save_btn, &QPushButton::clicked, this, &SignalEdit::saveSignal); - QObject::connect(plot_btn, &QPushButton::clicked, [this]() { emit showChart(msg_id, sig, !chart_opened); }); - QObject::connect(seek_btn, &QPushButton::clicked, [this]() { - SignalFindDlg dlg(msg_id, sig, this); - dlg.exec(); - }); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } -void SignalEdit::setSignal(const QString &message_id, const Signal *signal, bool show_form) { - msg_id = message_id; +void SignalEdit::setSignal(const QString &message_id, const Signal *signal) { sig = signal; + updateForm(msg_id == message_id && form->isVisible()); + msg_id = message_id; title->setText(QString("%1. %2").arg(form_idx + 1).arg(sig->name.c_str())); - setFormVisible(show_form); + show(); } void SignalEdit::saveSignal() { + if (!sig || !form->changed_by_user) return; + Signal s = *sig; s.name = form->name->text().toStdString(); s.size = form->size->text().toInt(); @@ -148,33 +139,38 @@ void SignalEdit::saveSignal() { s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); s.msb = s.start_bit; } - title->setText(QString("%1. %2").arg(form_idx + 1).arg(form->name->text())); - emit save(this->sig, s); + if (s != *sig) + emit save(this->sig, s); } void SignalEdit::setChartOpened(bool opened) { plot_btn->setText(opened ? "☒" : "📈"); - plot_btn->setToolTip(opened ? tr("Close Plot") :tr("Show Plot")); + plot_btn->setToolTip(opened ? tr("Close Plot") : tr("Show Plot")); chart_opened = opened; } -void SignalEdit::setFormVisible(bool visible) { - if (visible) { - if (!form) { - form = new SignalForm(this); - ((QVBoxLayout *)form_container->layout())->insertWidget(0, form); - } +void SignalEdit::updateForm(bool visible) { + if (visible && sig) { + form->changed_by_user = false; form->name->setText(sig->name.c_str()); - form->size->setValue(sig->size); form->endianness->setCurrentIndex(sig->is_little_endian ? 0 : 1); form->sign->setCurrentIndex(sig->is_signed ? 0 : 1); form->factor->setText(QString::number(sig->factor)); form->offset->setText(QString::number(sig->offset)); form->msb->setText(QString::number(sig->msb)); form->lsb->setText(QString::number(sig->lsb)); + form->size->setValue(sig->size); + form->changed_by_user = true; } - form_container->setVisible(visible); - icon->setText(visible ? "▼" : ">"); + form->setVisible(visible); + icon->setText(visible ? "▼ " : "> "); +} + +void SignalEdit::showFormClicked() { + parentWidget()->setUpdatesEnabled(false); + for (auto &edit : parentWidget()->findChildren()) + edit->updateForm(edit == this && !form->isVisible()); + QTimer::singleShot(1, [this]() { parentWidget()->setUpdatesEnabled(true); }); } void SignalEdit::signalHovered(const Signal *s) { @@ -182,6 +178,13 @@ void SignalEdit::signalHovered(const Signal *s) { title->setStyleSheet(QString("font-weight:bold; color:%1").arg(color.name())); } +void SignalEdit::hideEvent(QHideEvent *event) { + msg_id = ""; + sig = nullptr; + updateForm(false); + QWidget::hideEvent(event); +} + void SignalEdit::enterEvent(QEvent *event) { emit highlight(sig); QWidget::enterEvent(event); @@ -204,7 +207,7 @@ SignalFindDlg::SignalFindDlg(const QString &id, const Signal *signal, QWidget *p comp_box->addItems({">", "=", "<"}); h->addWidget(comp_box); QLineEdit *value_edit = new QLineEdit("0", this); - value_edit->setValidator( new QDoubleValidator(-500000, 500000, 6, this) ); + value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); h->addWidget(value_edit, 1); QPushButton *search_btn = new QPushButton(tr("Find"), this); h->addWidget(search_btn); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index dce9d27479..46ea1bfbe0 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -1,11 +1,12 @@ #pragma once +#include #include #include #include #include -#include #include +#include #include "selfdrive/ui/qt/widgets/controls.h" @@ -13,13 +14,17 @@ #include "tools/cabana/dbcmanager.h" class SignalForm : public QWidget { + Q_OBJECT public: SignalForm(QWidget *parent); - QLineEdit *name, *unit, *comment, *val_desc, *offset, *factor, *min_val, *max_val; QLabel *lsb, *msb; QSpinBox *size; QComboBox *sign, *endianness; + bool changed_by_user = false; + + signals: + void changed(); }; class SignalEdit : public QWidget { @@ -27,38 +32,35 @@ class SignalEdit : public QWidget { public: SignalEdit(int index, QWidget *parent = nullptr); - void setSignal(const QString &msg_id, const Signal *sig, bool show_form); + void setSignal(const QString &msg_id, const Signal *sig); void setChartOpened(bool opened); - void setFormVisible(bool show); void signalHovered(const Signal *sig); - inline bool isFormVisible() const { return form_container->isVisible(); } const Signal *sig = nullptr; QString msg_id; signals: void highlight(const Signal *sig); void showChart(const QString &name, const Signal *sig, bool show); - void showFormClicked(); void remove(const Signal *sig); void save(const Signal *sig, const Signal &new_sig); protected: + void hideEvent(QHideEvent *event) override; void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void saveSignal(); + void updateForm(bool show); + void showFormClicked(); SignalForm *form = nullptr; ElidedLabel *title; - QWidget *form_container; QLabel *icon; int form_idx = 0; bool chart_opened = false; - QPushButton *plot_btn; + QAction *plot_btn; }; class SignalFindDlg : public QDialog { - Q_OBJECT - public: SignalFindDlg(const QString &id, const Signal *signal, QWidget *parent); }; diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index d2d9dc1d2a..ee4a581529 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -5,10 +5,8 @@ TEST_CASE("DBCManager::generateDBC") { DBCManager dbc_origin(nullptr); dbc_origin.open("toyota_new_mc_pt_generated"); - QString dbc_string = dbc_origin.generateDBC(); - DBCManager dbc_from_generated(nullptr); - dbc_from_generated.open("", dbc_string); + dbc_from_generated.open("", dbc_origin.generateDBC()); auto &msgs = dbc_origin.messages(); auto &new_msgs = dbc_from_generated.messages(); @@ -18,17 +16,7 @@ TEST_CASE("DBCManager::generateDBC") { REQUIRE(m.name == new_m.name); REQUIRE(m.size == new_m.size); REQUIRE(m.sigs.size() == new_m.sigs.size()); - for (auto &[name, sig] : m.sigs) { - auto &new_sig = new_m.sigs[name]; - REQUIRE(sig.name == new_sig.name); - REQUIRE(sig.start_bit == new_sig.start_bit); - REQUIRE(sig.msb == new_sig.msb); - REQUIRE(sig.lsb == new_sig.lsb); - REQUIRE(sig.size == new_sig.size); - REQUIRE(sig.is_signed == new_sig.is_signed); - REQUIRE(sig.factor == new_sig.factor); - REQUIRE(sig.offset == new_sig.offset); - REQUIRE(sig.is_little_endian == new_sig.is_little_endian); - } + for (auto &[name, sig] : m.sigs) + REQUIRE(sig == new_m.sigs[name]); } } From c4f9f2d206b68d5c4032ab7d31eb85639ce064d1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 11 Nov 2022 11:05:47 -0800 Subject: [PATCH 0262/1179] Update RELEASES.md --- RELEASES.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 18817bda4d..ad51b7af3f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,19 +1,19 @@ -Version 0.8.17 (2022-11-XX) +Version 0.8.17 (2022-11-21) ======================== * New driving model - * Internal feature space information content increased tenfold during training (to ~700 bits), this makes the model dramatically more accurate + * Internal feature space information content increased tenfold during training (to ~700 bits), which makes the model dramatically more accurate * Less reliance on previous frames makes model more reactive and snappy * Trained in new reprojective simulator - * Model trained in openpilot was trained in 36hrs from scratch, compared to around 1 week of previous releases - * Model training now simulates lateral and longitudinal behavior, this allows openpilot to slow down for turns, stop at traffic lights, etc,... in experimental mode + * Trained in 36hrs from scratch, compared to one week for previous releases + * Training now simulates both lateral and longitudinal behavior, which allows openpilot to slow down for turns, stop at traffic lights, and more in experimental mode * New driver monitoring model * New end-to-end distracted trigger * Experimental driving mode * End-to-end longitudinal control - * Stops for red lights and stop signs + * Stops for traffic lights and stop signs + * Slows down for turns * openpilot defaults to chill mode, enable experimental in settings -* Self-tuning torque lateral controller parameters - * Parameters learned live for each car +* Self-tuning torque controller: learns parameters live for each car * Torque controller used on all Toyota, Lexus, Hyundai, Kia, and Genesis models * UI updates * Multi-language in navigation @@ -21,8 +21,10 @@ Version 0.8.17 (2022-11-XX) * Improved update experience * Border turns grey while overriding steering * Bookmark events while driving; view them in comma connect + * New onroad visualization for experimental mode * AGNOS 6 * tools: new and improved cabana thanks to deanlee! +* Experimental longitudinal support for Volkswagen, CAN-FD Hyundai, and new GM models * Genesis GV70 2022-23 support thanks to zunichky and sunnyhaibin! * Hyundai Santa Cruz 2021-22 support thanks to sunnyhaibin! * Kia Sportage 2023 support thanks to sunnyhaibin! From f6189b32351b21ad528486ee69c55666a1ef0d55 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 11 Nov 2022 14:40:21 -0500 Subject: [PATCH 0263/1179] HKG: Bump Kia Telluride support to 2022 (#26467) --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 07bcf44257..32da6126bd 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -107,7 +107,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Sportage 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Telluride 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index b7e28825c3..1dba3a5442 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -142,7 +142,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { ], CAR.PALISADE: [ HyundaiCarInfo("Hyundai Palisade 2020-22", "All", "https://youtu.be/TAnDqjF4fDY?t=456", harness=Harness.hyundai_h), - HyundaiCarInfo("Kia Telluride 2020", "All", harness=Harness.hyundai_h), + HyundaiCarInfo("Kia Telluride 2020-22", "All", harness=Harness.hyundai_h), ], CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e), CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a), From 4ab13300892e4d00d6ce7583c117a465c062adde Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Fri, 11 Nov 2022 12:48:41 -0800 Subject: [PATCH 0264/1179] Update RELEASES.md --- RELEASES.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ad51b7af3f..bf89b667fa 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,8 +6,9 @@ Version 0.8.17 (2022-11-21) * Trained in new reprojective simulator * Trained in 36hrs from scratch, compared to one week for previous releases * Training now simulates both lateral and longitudinal behavior, which allows openpilot to slow down for turns, stop at traffic lights, and more in experimental mode -* New driver monitoring model - * New end-to-end distracted trigger +* Driver monitoring updates + * New bigger model with added end-to-end distracted trigger + * Reduced false positives during driver calibration * Experimental driving mode * End-to-end longitudinal control * Stops for traffic lights and stop signs From 714ab491b0ff90170353df99f43f09bbae1ab00d Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 11 Nov 2022 12:51:14 -0800 Subject: [PATCH 0265/1179] boardd: SPI bulk read + write (#26462) * bulk read * write * write * fix write Co-authored-by: Comma Device --- selfdrive/boardd/panda_comms.h | 3 ++- selfdrive/boardd/spi.cc | 49 ++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index aef7b41d07..f42eadc5b2 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -34,7 +34,7 @@ public: virtual int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; protected: - std::mutex hw_lock; + std::recursive_mutex hw_lock; }; class PandaUsbHandle : public PandaCommsHandle { @@ -74,6 +74,7 @@ private: uint8_t rx_buf[SPI_BUF_SIZE]; int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack); + int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len); int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); }; diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 3969b313f0..2803f58db0 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include "common/util.h" @@ -99,13 +100,45 @@ int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t para } int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { - return 0; + return bulk_transfer(endpoint, data, length, NULL, 0); +} +int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + return bulk_transfer(endpoint, NULL, 0, data, length); } -int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { - return 0; +int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len) { + std::lock_guard lk(hw_lock); + + const int xfer_size = 0x40; + + int ret = 0; + uint16_t length = (tx_data != NULL) ? tx_len : rx_len; + for (int i = 0; i < (int)std::ceil((float)length / xfer_size); i++) { + int d; + if (tx_data != NULL) { + int len = std::min(xfer_size, tx_len - (xfer_size * i)); + d = spi_transfer_retry(endpoint, tx_data + (xfer_size * i), len, NULL, 0); + } else { + d = spi_transfer_retry(endpoint, NULL, 0, rx_data + (xfer_size * i), xfer_size); + } + + if (d < 0) { + LOGE("SPI: bulk transfer failed with %d", d); + comms_healthy = false; + return -1; + } + + ret += d; + if ((rx_data != NULL) && d < xfer_size) { + break; + } + } + + return ret; } + + std::vector PandaSpiHandle::list() { // TODO: list all pandas available over SPI return {}; @@ -130,15 +163,15 @@ bool check_checksum(uint8_t *data, int data_len) { int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { - int err; + int ret; std::lock_guard lk(hw_lock); do { // TODO: handle error - err = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); - } while (err < 0 && connected && !PANDA_NO_RETRY); + ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); + } while (ret < 0 && connected && !PANDA_NO_RETRY); - return err; + return ret; } int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { @@ -153,7 +186,7 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { if (rx_buf[0] == ack) { break; } else if (rx_buf[0] == SPI_NACK) { - LOGW("SPI: got header NACK"); + LOGW("SPI: got NACK"); return -1; } } From 98206fb92e6a071127f6d6e4fec456d0c437444f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 13:22:56 -0800 Subject: [PATCH 0266/1179] planner: fix undeclared variable (#26468) * undeclared variable * run first second disabled * revert test * rev --- selfdrive/controls/lib/longitudinal_planner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index cae378453c..c6621f606d 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -107,6 +107,7 @@ class LongitudinalPlanner: accel_limits = [A_CRUISE_MIN, get_max_accel(v_ego)] accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngleDeg, accel_limits, self.CP) else: + accel_limits = [MIN_ACCEL, MAX_ACCEL] accel_limits_turns = [MIN_ACCEL, MAX_ACCEL] if reset_state: From 9f80a97eee52d128559b7fef0593b8c328a6142d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 14:02:09 -0800 Subject: [PATCH 0267/1179] longitudinal tests: add disabled maneuver (#26470) * undeclared variable * run first second disabled * only test * test disabled as a new maneuver * bottom --- .../controls/lib/longitudinal_planner.py | 3 ++- .../test/longitudinal_maneuvers/maneuver.py | 12 +++++++----- .../test/longitudinal_maneuvers/plant.py | 19 ++++++++++--------- .../test_longitudinal.py | 9 ++++++++- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index c6621f606d..def0a1208a 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -69,7 +69,8 @@ class LongitudinalPlanner: e2e = self.params.get_bool('ExperimentalMode') and self.CP.openpilotLongitudinalControl self.mpc.mode = 'blended' if e2e else 'acc' - def parse_model(self, model_msg, model_error): + @staticmethod + def parse_model(model_msg, model_error): if (len(model_msg.position.x) == 33 and len(model_msg.velocity.x) == 33 and len(model_msg.acceleration.x) == 33): diff --git a/selfdrive/test/longitudinal_maneuvers/maneuver.py b/selfdrive/test/longitudinal_maneuvers/maneuver.py index dad5d89844..071eaada12 100644 --- a/selfdrive/test/longitudinal_maneuvers/maneuver.py +++ b/selfdrive/test/longitudinal_maneuvers/maneuver.py @@ -17,6 +17,7 @@ class Maneuver(): self.only_lead2 = kwargs.get("only_lead2", False) self.only_radar = kwargs.get("only_radar", False) self.ensure_start = kwargs.get("ensure_start", False) + self.enabled = kwargs.get("enabled", True) self.duration = duration self.title = title @@ -26,23 +27,24 @@ class Maneuver(): lead_relevancy=self.lead_relevancy, speed=self.speed, distance_lead=self.distance_lead, + enabled=self.enabled, only_lead2=self.only_lead2, only_radar=self.only_radar, ) valid = True logs = [] - while plant.current_time() < self.duration: - speed_lead = np.interp(plant.current_time(), self.breakpoints, self.speed_lead_values) - prob = np.interp(plant.current_time(), self.breakpoints, self.prob_lead_values) - cruise = np.interp(plant.current_time(), self.breakpoints, self.cruise_values) + while plant.current_time < self.duration: + speed_lead = np.interp(plant.current_time, self.breakpoints, self.speed_lead_values) + prob = np.interp(plant.current_time, self.breakpoints, self.prob_lead_values) + cruise = np.interp(plant.current_time, self.breakpoints, self.cruise_values) log = plant.step(speed_lead, prob, cruise) d_rel = log['distance_lead'] - log['distance'] if self.lead_relevancy else 200. v_rel = speed_lead - log['speed'] if self.lead_relevancy else 0. log['d_rel'] = d_rel log['v_rel'] = v_rel - logs.append(np.array([plant.current_time(), + logs.append(np.array([plant.current_time, log['distance'], log['distance_lead'], log['speed'], diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index e81510e9ba..c3af1eee03 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -10,11 +10,12 @@ from selfdrive.modeld.constants import T_IDXS from selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU -class Plant(): + +class Plant: messaging_initialized = False def __init__(self, lead_relevancy=False, speed=0.0, distance_lead=2.0, - only_lead2=False, only_radar=False): + enabled=True, only_lead2=False, only_radar=False): self.rate = 1. / DT_MDL if not Plant.messaging_initialized: @@ -32,10 +33,11 @@ class Plant(): self.speeds = [] # lead car - self.distance_lead = distance_lead self.lead_relevancy = lead_relevancy - self.only_lead2=only_lead2 - self.only_radar=only_radar + self.distance_lead = distance_lead + self.enabled = enabled + self.only_lead2 = only_lead2 + self.only_radar = only_radar self.rk = Ratekeeper(self.rate, print_delay_threshold=100.0) self.ts = 1. / self.rate @@ -47,6 +49,7 @@ class Plant(): self.planner = LongitudinalPlanner(CarInterface.get_params(CAR.CIVIC), init_v=self.speed) + @property def current_time(self): return float(self.rk.frame) / self.rate @@ -104,9 +107,7 @@ class Plant(): acceleration.x = [float(x) for x in np.zeros_like(T_IDXS)] model.modelV2.acceleration = acceleration - - - control.controlsState.longControlState = LongCtrlState.pid + control.controlsState.longControlState = LongCtrlState.pid if self.enabled else LongCtrlState.off control.controlsState.vCruise = float(v_cruise * 3.6) car_state.carState.vEgo = float(self.speed) car_state.carState.standstill = self.speed < 0.01 @@ -141,7 +142,7 @@ class Plant(): # print at 5hz if (self.rk.frame % (self.rate // 5)) == 0: print("%2.2f sec %6.2f m %6.2f m/s %6.2f m/s2 lead_rel: %6.2f m %6.2f m/s" - % (self.current_time(), self.distance, self.speed, self.acceleration, d_rel, v_rel)) + % (self.current_time, self.distance, self.speed, self.acceleration, d_rel, v_rel)) # ******** update prevs ******** diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py index 7cc95b104a..e859952445 100755 --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -10,7 +10,7 @@ from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver # TODO: make new FCW tests maneuvers = [ Maneuver( - 'approach stopped car at 20m/s, initial distance: 120m', + 'approach stopped car at 25m/s, initial distance: 120m', duration=20., initial_speed=25., lead_relevancy=True, @@ -118,6 +118,13 @@ maneuvers = [ breakpoints=[1., 10., 15.], ensure_start=True, ), + Maneuver( + 'cruising at 25 m/s while disabled', + duration=20., + initial_speed=25., + lead_relevancy=False, + enabled=False, + ), ] From 89b88fc7a23c393b1d74c5c74aacd5c4ee254d81 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 14:49:38 -0800 Subject: [PATCH 0268/1179] Hyundai: fix button enable controls mismatch (#26471) * bump panda * buttonCancel needs to be a noEntry * bompo * Update ref_commit --- panda | 2 +- selfdrive/controls/lib/events.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/panda b/panda index 281eb7731b..d573111268 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 281eb7731b4338fef049977593fdf3315adf09e9 +Subproject commit d57311126860c9a87edf5b7b9f81a2a038866a26 diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 44426620e9..a761cceecb 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -597,6 +597,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { EventName.buttonCancel: { ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage), + ET.NO_ENTRY: NoEntryAlert("Cancel Pressed"), }, EventName.brakeHold: { diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index e3c5390c3b..2ff423a84a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -9e37e8ee8013515cfd75cf352a1a2b9aa447c441 +b5c833a8f5b3e6202a52746fc16809c7b649d591 From 811c096e6454dc2bbdd1e15a08952979c3fb7be1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 18:53:48 -0800 Subject: [PATCH 0269/1179] controlsd: add cruise speed helper class (#26472) * fix runaway set speed for GM * fix runaway set speed for GM * Handle resuming to exit standstill generically * clean that up * ugh i want to fix all the formatting * class that manages v_cruise * better name * move around * add depressed_state * fine to update on pressed change, better name * revert gm stuff * revert standstill stuff * remove * revert that * we can put this in here now! * below update * actually only used here * one line --- selfdrive/controls/controlsd.py | 52 ++------- selfdrive/controls/lib/drive_helpers.py | 141 +++++++++++++++--------- 2 files changed, 102 insertions(+), 91 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 3b241045b1..f69e9e7fd1 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -16,8 +16,7 @@ from system.version import is_tested_branch, get_short_branch from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can from selfdrive.controls.lib.lateral_planner import CAMERA_OFFSET -from selfdrive.controls.lib.drive_helpers import V_CRUISE_INITIAL, update_v_cruise, initialize_v_cruise -from selfdrive.controls.lib.drive_helpers import get_lag_adjusted_curvature +from selfdrive.controls.lib.drive_helpers import VCruiseHelper, get_lag_adjusted_curvature from selfdrive.controls.lib.latcontrol import LatControl from selfdrive.controls.lib.longcontrol import LongControl from selfdrive.controls.lib.latcontrol_pid import LatControlPID @@ -49,7 +48,6 @@ Desire = log.LateralPlan.Desire LaneChangeState = log.LateralPlan.LaneChangeState LaneChangeDirection = log.LateralPlan.LaneChangeDirection EventName = car.CarEvent.EventName -ButtonEvent = car.CarState.ButtonEvent ButtonType = car.CarState.ButtonEvent.Type SafetyModel = car.CarParams.SafetyModel @@ -173,9 +171,6 @@ class Controls: self.active = False self.can_rcv_timeout = False self.soft_disable_timer = 0 - self.v_cruise_kph = V_CRUISE_INITIAL - self.v_cruise_cluster_kph = V_CRUISE_INITIAL - self.v_cruise_kph_last = 0 self.mismatch_counter = 0 self.cruise_mismatch_counter = 0 self.can_rcv_timeout_counter = 0 @@ -185,11 +180,11 @@ class Controls: self.events_prev = [] self.current_alert_types = [ET.PERMANENT] self.logged_comm_issue = None - self.button_timers = {ButtonEvent.Type.decelCruise: 0, ButtonEvent.Type.accelCruise: 0} self.last_actuators = car.CarControl.Actuators.new_message() self.steer_limited = False self.desired_curvature = 0.0 self.desired_curvature_rate = 0.0 + self.v_cruise_helper = VCruiseHelper(self.CP) # TODO: no longer necessary, aside from process replay self.sm['liveParameters'].valid = True @@ -219,7 +214,7 @@ class Controls: controls_state = Params().get("ReplayControlsState") if controls_state is not None: controls_state = log.ControlsState.from_bytes(controls_state) - self.v_cruise_kph = controls_state.vCruise + self.v_cruise_helper.v_cruise_kph = controls_state.vCruise if any(ps.controlsAllowed for ps in self.sm['pandaStates']): self.state = State.enabled @@ -245,7 +240,7 @@ class Controls: # Block resume if cruise never previously enabled resume_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in CS.buttonEvents) - if not self.CP.pcmCruise and self.v_cruise_kph == V_CRUISE_INITIAL and resume_pressed: + if not self.CP.pcmCruise and not self.v_cruise_helper.v_cruise_initialized and resume_pressed: self.events.add(EventName.resumeBlocked) # Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0 @@ -478,20 +473,7 @@ class Controls: def state_transition(self, CS): """Compute conditional state transitions and execute actions on state transitions""" - self.v_cruise_kph_last = self.v_cruise_kph - - if CS.cruiseState.available: - # if stock cruise is completely disabled, then we can use our own set speed logic - if not self.CP.pcmCruise: - self.v_cruise_kph = update_v_cruise(self.v_cruise_kph, CS.vEgo, CS.gasPressed, CS.buttonEvents, - self.button_timers, self.enabled, self.is_metric) - self.v_cruise_cluster_kph = self.v_cruise_kph - else: - self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH - self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH - else: - self.v_cruise_kph = V_CRUISE_INITIAL - self.v_cruise_cluster_kph = V_CRUISE_INITIAL + self.v_cruise_helper.update_v_cruise(CS, self.enabled, self.is_metric) # decrement the soft disable timer at every step, as it's reset on # entrance in SOFT_DISABLING state @@ -569,9 +551,7 @@ class Controls: else: self.state = State.enabled self.current_alert_types.append(ET.ENABLE) - if not self.CP.pcmCruise: - self.v_cruise_kph = initialize_v_cruise(CS.vEgo, CS.buttonEvents, self.v_cruise_kph_last) - self.v_cruise_cluster_kph = self.v_cruise_kph + self.v_cruise_helper.initialize_v_cruise(CS) # Check if openpilot is engaged and actuators are enabled self.enabled = self.state in ENABLED_STATES @@ -619,7 +599,7 @@ class Controls: if not self.joystick_mode: # accel PID loop - pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, self.v_cruise_kph * CV.KPH_TO_MS) + pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, self.v_cruise_helper.v_cruise_kph * CV.KPH_TO_MS) t_since_plan = (self.sm.frame - self.sm.rcv_frame['longitudinalPlan']) * DT_CTRL actuators.accel = self.LoC.update(CC.longActive, CS, long_plan, pid_accel_limits, t_since_plan) @@ -683,16 +663,6 @@ class Controls: return CC, lac_log - def update_button_timers(self, buttonEvents): - # increment timer for buttons still pressed - for k in self.button_timers: - if self.button_timers[k] > 0: - self.button_timers[k] += 1 - - for b in buttonEvents: - if b.type.raw in self.button_timers: - self.button_timers[b.type.raw] = 1 if b.pressed else 0 - def publish_logs(self, CS, start_time, CC, lac_log): """Send actuators and hud commands to the car, send controlsstate and MPC logging""" @@ -715,7 +685,7 @@ class Controls: CC.cruiseControl.resume = self.enabled and CS.cruiseState.standstill and speeds[-1] > 0.1 hudControl = CC.hudControl - hudControl.setSpeed = float(self.v_cruise_cluster_kph * CV.KPH_TO_MS) + hudControl.setSpeed = float(self.v_cruise_helper.v_cruise_cluster_kph * CV.KPH_TO_MS) hudControl.speedVisible = self.enabled hudControl.lanesVisible = self.enabled hudControl.leadVisible = self.sm['longitudinalPlan'].hasLead @@ -798,8 +768,8 @@ class Controls: controlsState.engageable = not self.events.any(ET.NO_ENTRY) controlsState.longControlState = self.LoC.long_control_state controlsState.vPid = float(self.LoC.v_pid) - controlsState.vCruise = float(self.v_cruise_kph) - controlsState.vCruiseCluster = float(self.v_cruise_cluster_kph) + controlsState.vCruise = float(self.v_cruise_helper.v_cruise_kph) + controlsState.vCruiseCluster = float(self.v_cruise_helper.v_cruise_cluster_kph) controlsState.upAccelCmd = float(self.LoC.pid.p) controlsState.uiAccelCmd = float(self.LoC.pid.i) controlsState.ufAccelCmd = float(self.LoC.pid.f) @@ -880,7 +850,6 @@ class Controls: self.publish_logs(CS, start_time, CC, lac_log) self.prof.checkpoint("Sent") - self.update_button_timers(CS.buttonEvents) self.CS_prev = CS def controlsd_thread(self): @@ -889,6 +858,7 @@ class Controls: self.rk.monitor_time() self.prof.display() + def main(sm=None, pm=None, logcan=None): controls = Controls(sm, pm, logcan) controls.controlsd_thread() diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index e74be7199e..27e53d1dd3 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -22,6 +22,7 @@ CAR_ROTATION_RADIUS = 0.0 # EU guidelines MAX_LATERAL_JERK = 5.0 +ButtonEvent = car.CarState.ButtonEvent ButtonType = car.CarState.ButtonEvent.Type CRUISE_LONG_PRESS = 50 CRUISE_NEAREST_FUNC = { @@ -34,6 +35,96 @@ CRUISE_INTERVAL_SIGN = { } +class VCruiseHelper: + def __init__(self, CP): + self.CP = CP + self.v_cruise_kph = V_CRUISE_INITIAL + self.v_cruise_cluster_kph = V_CRUISE_INITIAL + self.v_cruise_kph_last = 0 + self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} + + @property + def v_cruise_initialized(self): + return self.v_cruise_kph != V_CRUISE_INITIAL + + def update_v_cruise(self, CS, enabled, is_metric): + self.v_cruise_kph_last = self.v_cruise_kph + + if CS.cruiseState.available: + if not self.CP.pcmCruise: + # if stock cruise is completely disabled, then we can use our own set speed logic + self._update_v_cruise_non_pcm(CS, enabled, is_metric) + self.v_cruise_cluster_kph = self.v_cruise_kph + self.update_button_timers(CS) + else: + self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH + self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH + else: + self.v_cruise_kph = V_CRUISE_INITIAL + self.v_cruise_cluster_kph = V_CRUISE_INITIAL + + def _update_v_cruise_non_pcm(self, CS, enabled, is_metric): + # handle button presses. TODO: this should be in state_control, but a decelCruise press + # would have the effect of both enabling and changing speed is checked after the state transition + if not enabled: + return + + long_press = False + button_type = None + + # should be CV.MPH_TO_KPH, but this causes rounding errors + v_cruise_delta = 1. if is_metric else 1.6 + + for b in CS.buttonEvents: + if b.type.raw in self.button_timers and not b.pressed: + if self.button_timers[b.type.raw] > CRUISE_LONG_PRESS: + return # end long press + button_type = b.type.raw + break + else: + for k in self.button_timers.keys(): + if self.button_timers[k] and self.button_timers[k] % CRUISE_LONG_PRESS == 0: + button_type = k + long_press = True + break + + if button_type: + v_cruise_delta = v_cruise_delta * (5 if long_press else 1) + if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval + self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta + else: + self.v_cruise_kph += v_cruise_delta * CRUISE_INTERVAL_SIGN[button_type] + + # If set is pressed while overriding, clip cruise speed to minimum of vEgo + if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise): + self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH) + + self.v_cruise_kph = clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX) + + def update_button_timers(self, CS): + # increment timer for buttons still pressed + for k in self.button_timers: + if self.button_timers[k] > 0: + self.button_timers[k] += 1 + + for b in CS.buttonEvents: + if b.type.raw in self.button_timers: + self.button_timers[b.type.raw] = 1 if b.pressed else 0 + + def initialize_v_cruise(self, CS): + # initializing is handled by the PCM + if self.CP.pcmCruise: + return + + # 250kph or above probably means we never had a set speed + if any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) and self.v_cruise_kph_last < 250: + self.v_cruise_kph = self.v_cruise_kph_last + else: + self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, V_CRUISE_ENABLE_MIN, V_CRUISE_MAX))) + + self.v_cruise_cluster_kph = self.v_cruise_kph + + def apply_deadzone(error, deadzone): if error > deadzone: error -= deadzone @@ -48,56 +139,6 @@ def rate_limit(new_value, last_value, dw_step, up_step): return clip(new_value, last_value + dw_step, last_value + up_step) -def update_v_cruise(v_cruise_kph, v_ego, gas_pressed, buttonEvents, button_timers, enabled, metric): - # handle button presses. TODO: this should be in state_control, but a decelCruise press - # would have the effect of both enabling and changing speed is checked after the state transition - if not enabled: - return v_cruise_kph - - long_press = False - button_type = None - - # should be CV.MPH_TO_KPH, but this causes rounding errors - v_cruise_delta = 1. if metric else 1.6 - - for b in buttonEvents: - if b.type.raw in button_timers and not b.pressed: - if button_timers[b.type.raw] > CRUISE_LONG_PRESS: - return v_cruise_kph # end long press - button_type = b.type.raw - break - else: - for k in button_timers.keys(): - if button_timers[k] and button_timers[k] % CRUISE_LONG_PRESS == 0: - button_type = k - long_press = True - break - - if button_type: - v_cruise_delta = v_cruise_delta * (5 if long_press else 1) - if long_press and v_cruise_kph % v_cruise_delta != 0: # partial interval - v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](v_cruise_kph / v_cruise_delta) * v_cruise_delta - else: - v_cruise_kph += v_cruise_delta * CRUISE_INTERVAL_SIGN[button_type] - - # If set is pressed while overriding, clip cruise speed to minimum of vEgo - if gas_pressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise): - v_cruise_kph = max(v_cruise_kph, v_ego * CV.MS_TO_KPH) - - v_cruise_kph = clip(round(v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX) - - return v_cruise_kph - - -def initialize_v_cruise(v_ego, buttonEvents, v_cruise_last): - for b in buttonEvents: - # 250kph or above probably means we never had a set speed - if b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) and v_cruise_last < 250: - return v_cruise_last - - return int(round(clip(v_ego * CV.MS_TO_KPH, V_CRUISE_ENABLE_MIN, V_CRUISE_MAX))) - - def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates): if len(psis) != CONTROL_N: psis = [0.0]*CONTROL_N From 76ac3d4c99df24f068aee3baedb796f65dfcca66 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 19:43:30 -0800 Subject: [PATCH 0270/1179] controlsd: resume does not increment speed while cruise standstill (#25470) * fix runaway set speed for GM * fix runaway set speed for GM * Handle resuming to exit standstill generically * clean that up * ugh i want to fix all the formatting * class that manages v_cruise * better name * move around * add depressed_state * fine to update on pressed change, better name * cmt * we need to check CS. button_change_state only works if we exit standstill on rising edge not falling edge * no defaultdict --- selfdrive/car/gm/interface.py | 8 +------- selfdrive/controls/lib/drive_helpers.py | 8 ++++++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 2420098b4a..49cae998e8 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -211,13 +211,7 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback) if self.CS.cruise_buttons != self.CS.prev_cruise_buttons and self.CS.prev_cruise_buttons != CruiseButtons.INIT: - be = create_button_event(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT, CruiseButtons.UNPRESS) - - # Suppress resume button if we're resuming from stop so we don't adjust speed. - if be.type == ButtonType.accelCruise and (ret.cruiseState.enabled and ret.standstill): - be.type = ButtonType.unknown - - ret.buttonEvents = [be] + ret.buttonEvents = [create_button_event(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT, CruiseButtons.UNPRESS)] events = self.create_common_events(ret, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.eco, GearShifter.manumatic], diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 27e53d1dd3..5ca5319ba5 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -42,6 +42,7 @@ class VCruiseHelper: self.v_cruise_cluster_kph = V_CRUISE_INITIAL self.v_cruise_kph_last = 0 self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} + self.button_change_state = {btn: {"standstill": False} for btn in self.button_timers} @property def v_cruise_initialized(self): @@ -88,6 +89,11 @@ class VCruiseHelper: long_press = True break + # Don't adjust speed when pressing resume to exit standstill + cruise_standstill = self.button_change_state[button_type]["standstill"] or CS.cruiseState.standstill + if button_type == ButtonType.accelCruise and cruise_standstill: + button_type = None + if button_type: v_cruise_delta = v_cruise_delta * (5 if long_press else 1) if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval @@ -109,7 +115,9 @@ class VCruiseHelper: for b in CS.buttonEvents: if b.type.raw in self.button_timers: + # Start/end timer and store current state on change of button pressed self.button_timers[b.type.raw] = 1 if b.pressed else 0 + self.button_change_state[b.type.raw].update({"standstill": CS.cruiseState.standstill}) def initialize_v_cruise(self, CS): # initializing is handled by the PCM From d3f971b365613329a35a3140b9418977baebd856 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 20:10:12 -0800 Subject: [PATCH 0271/1179] controlsd v_cruise: fix unknown buttons (#26474) Fix button being None --- selfdrive/controls/lib/drive_helpers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 5ca5319ba5..e9d74c54a9 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -90,8 +90,7 @@ class VCruiseHelper: break # Don't adjust speed when pressing resume to exit standstill - cruise_standstill = self.button_change_state[button_type]["standstill"] or CS.cruiseState.standstill - if button_type == ButtonType.accelCruise and cruise_standstill: + if button_type == ButtonType.accelCruise and (self.button_change_state[button_type]["standstill"] or CS.cruiseState.standstill): button_type = None if button_type: From 5f094b836851c392b89429cc654082c659f7caec Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 12 Nov 2022 06:50:09 +0100 Subject: [PATCH 0272/1179] CI: regroup devices (#26436) * regroup ci devices * cleanup looopback test * split loopback devices Co-authored-by: Kurt Nistelberger --- Jenkinsfile | 27 +++++++++++++++++++------- release/files_common | 1 + selfdrive/manager/test/test_manager.py | 6 ++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0d624954ea..696446c65f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -111,7 +111,7 @@ pipeline { R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}" } steps { - phone_steps("tici", [ + phone_steps("tici-needs-can", [ ["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR EXTRA_FILES='tools/' ./build_devel.sh"], ["build openpilot", "cd selfdrive/manager && ./build.py"], ["check dirty", "release/check-dirty.sh"], @@ -122,16 +122,24 @@ pipeline { } } + stage('loopback-tests') { + agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } + steps { + phone_steps("tici-loopback", [ + ["build openpilot", "cd selfdrive/manager && ./build.py"], + ["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"], + ]) + } + } + stage('HW + Unit Tests') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { - phone_steps("tici2", [ + phone_steps("tici-common", [ ["build", "cd selfdrive/manager && ./build.py"], ["test power draw", "python system/hardware/tici/test_power_draw.py"], - ["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], - ["test sensord", "python selfdrive/sensord/tests/test_sensord.py"], ["test pigeond", "python selfdrive/sensord/tests/test_pigeond.py"], ]) } @@ -159,27 +167,32 @@ pipeline { } } - stage('sensord (LSM-C)') { + stage('sensord') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { phone_steps("tici-lsmc", [ ["build", "cd selfdrive/manager && ./build.py"], ["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"], ]) + phone_steps("tici-bmx-lsm", [ + ["build", "cd selfdrive/manager && ./build.py"], + ["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"], + ]) } } stage('replay') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { - phone_steps("tici3", [ + phone_steps("tici-common", [ ["build", "cd selfdrive/manager && ./build.py"], ["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], ]) } } - } + } } + } } diff --git a/release/files_common b/release/files_common index 26662f1ef1..a294e1e5b5 100644 --- a/release/files_common +++ b/release/files_common @@ -95,6 +95,7 @@ selfdrive/boardd/panda_comms.h selfdrive/boardd/panda_comms.cc selfdrive/boardd/set_time.py selfdrive/boardd/pandad.py +selfdrive/boardd/tests/test_boardd_loopback.py selfdrive/car/__init__.py selfdrive/car/docs_definitions.py diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index 7ac2c5f506..6d4df0423a 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -4,6 +4,7 @@ import signal import time import unittest +from common.params import Params import selfdrive.manager.manager as manager from selfdrive.manager.process import DaemonProcess from selfdrive.manager.process_config import managed_processes @@ -20,6 +21,10 @@ class TestManager(unittest.TestCase): os.environ['PASSIVE'] = '0' HARDWARE.set_power_save(False) + # ensure clean CarParams + params = Params() + params.clear_all() + def tearDown(self): manager.manager_cleanup() @@ -40,6 +45,7 @@ class TestManager(unittest.TestCase): Ensure all processes exit cleanly when stopped. """ HARDWARE.set_power_save(False) + manager.manager_init() manager.manager_prepare() for p in ALL_PROCESSES: managed_processes[p].start() From a638afb98e2b9d7844c04b1ec55c79d3274bc9b1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 23:11:49 -0800 Subject: [PATCH 0273/1179] controlsd: add tests around cruise speed (#26478) * start to add some tests * test !pcmCruise * test !pcmCruise * better test * fix pylint * new test for making sure we adjust on falling edge of buttons --- selfdrive/controls/tests/test_cruise_speed.py | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) mode change 100644 => 100755 selfdrive/controls/tests/test_cruise_speed.py diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py old mode 100644 new mode 100755 index ca070f1c3f..72b7dddc20 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -1,11 +1,17 @@ #!/usr/bin/env python3 -import unittest import numpy as np +from parameterized import parameterized_class +import unittest + +from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN +from cereal import car from common.params import Params - - from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver +ButtonEvent = car.CarState.ButtonEvent +ButtonType = car.CarState.ButtonEvent.Type + + def run_cruise_simulation(cruise, t_end=20.): man = Maneuver( '', @@ -19,7 +25,7 @@ def run_cruise_simulation(cruise, t_end=20.): ) valid, output = man.evaluate() assert valid - return output[-1,3] + return output[-1, 3] class TestCruiseSpeed(unittest.TestCase): @@ -35,5 +41,57 @@ class TestCruiseSpeed(unittest.TestCase): self.assertAlmostEqual(simulation_steady_state, cruise_speed, delta=.01, msg=f'Did not reach {speed} m/s') +# TODO: test pcmCruise +@parameterized_class(('pcm_cruise',), [(False,)]) +class TestVCruiseHelper(unittest.TestCase): + def setUp(self): + self.CP = car.CarParams(pcmCruise=self.pcm_cruise) # pylint: disable=E1101 + self.v_cruise_helper = VCruiseHelper(self.CP) + + def test_adjust_speed(self): + """ + Asserts speed changes on falling edges of buttons. + """ + + self.v_cruise_helper.initialize_v_cruise(car.CarState()) + + for btn in (ButtonType.accelCruise, ButtonType.decelCruise): + initial_v_cruise = self.v_cruise_helper.v_cruise_kph + for pressed in (True, False): + CS = car.CarState(cruiseState={"available": True}) + CS.buttonEvents = [ButtonEvent(type=btn, pressed=pressed)] + + self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) + self.assertEqual(pressed, (initial_v_cruise == self.v_cruise_helper.v_cruise_kph)) + + def test_resume_in_standstill(self): + """ + Asserts we don't increment set speed if user presses resume/accel to exit cruise standstill. + """ + + self.v_cruise_helper.initialize_v_cruise(car.CarState()) + initial_v_cruise = self.v_cruise_helper.v_cruise_kph + + for standstill in (True, False): + for pressed in (True, False): + CS = car.CarState(cruiseState={"available": True, "standstill": standstill}) + CS.buttonEvents = [ButtonEvent(type=ButtonType.accelCruise, pressed=pressed)] + + self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) + # speed should only update if not at standstill and button falling edge + should_equal = standstill or pressed + self.assertEqual(should_equal, (initial_v_cruise == self.v_cruise_helper.v_cruise_kph)) + + def test_initialize_v_cruise(self): + """ + Asserts allowed cruise speeds on enabling with SET + """ + + for v_ego in np.linspace(0, 100, 101): + self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=float(v_ego))) + self.assertTrue(V_CRUISE_ENABLE_MIN <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) + self.assertTrue(self.v_cruise_helper.v_cruise_initialized) + + if __name__ == "__main__": unittest.main() From 870b79818566ab91159d23f1197183f3e6567608 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 11 Nov 2022 23:56:35 -0800 Subject: [PATCH 0274/1179] controlsd: clean up v_cruise updating (#26479) * clean up * clean up * clean up --- selfdrive/controls/lib/drive_helpers.py | 31 ++++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index e9d74c54a9..37dacf5fb2 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -42,7 +42,7 @@ class VCruiseHelper: self.v_cruise_cluster_kph = V_CRUISE_INITIAL self.v_cruise_kph_last = 0 self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} - self.button_change_state = {btn: {"standstill": False} for btn in self.button_timers} + self.button_change_states = {btn: {"standstill": False} for btn in self.button_timers} @property def v_cruise_initialized(self): @@ -89,22 +89,25 @@ class VCruiseHelper: long_press = True break + if button_type is None: + return + # Don't adjust speed when pressing resume to exit standstill - if button_type == ButtonType.accelCruise and (self.button_change_state[button_type]["standstill"] or CS.cruiseState.standstill): - button_type = None + cruise_standstill = self.button_change_states[button_type]["standstill"] or CS.cruiseState.standstill + if button_type == ButtonType.accelCruise and cruise_standstill: + return - if button_type: - v_cruise_delta = v_cruise_delta * (5 if long_press else 1) - if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval - self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta - else: - self.v_cruise_kph += v_cruise_delta * CRUISE_INTERVAL_SIGN[button_type] + v_cruise_delta = v_cruise_delta * (5 if long_press else 1) + if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval + self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta + else: + self.v_cruise_kph += v_cruise_delta * CRUISE_INTERVAL_SIGN[button_type] - # If set is pressed while overriding, clip cruise speed to minimum of vEgo - if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise): - self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH) + # If set is pressed while overriding, clip cruise speed to minimum of vEgo + if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise): + self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH) - self.v_cruise_kph = clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX) + self.v_cruise_kph = clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX) def update_button_timers(self, CS): # increment timer for buttons still pressed @@ -116,7 +119,7 @@ class VCruiseHelper: if b.type.raw in self.button_timers: # Start/end timer and store current state on change of button pressed self.button_timers[b.type.raw] = 1 if b.pressed else 0 - self.button_change_state[b.type.raw].update({"standstill": CS.cruiseState.standstill}) + self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill} def initialize_v_cruise(self, CS): # initializing is handled by the PCM From 65f494d845bbfa47293ad3158a68bc38c1b4dcff Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 12 Nov 2022 02:02:30 -0800 Subject: [PATCH 0275/1179] GM: handle run-away set speed (#26480) * GM: Handle run-away set speed * bumpo * This is a test of both PRs combined * tempbump * Revert "tempbump" This reverts commit b73e04fca25e6a1bac889e44afac6430d5ad7c30. * Revert "This is a test of both PRs combined" This reverts commit 22cc0e6900e0f0470f14ed55e7846e4b1d570826. * fix * bump * fix that * Bump to master * fix fix --- panda | 2 +- selfdrive/car/gm/interface.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/panda b/panda index d573111268..0096d0c4fc 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d57311126860c9a87edf5b7b9f81a2a038866a26 +Subproject commit 0096d0c4fc50d199ca46c6fe40479e1547408aed diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 49cae998e8..c41aac0ae0 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -211,7 +211,12 @@ class CarInterface(CarInterfaceBase): ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback) if self.CS.cruise_buttons != self.CS.prev_cruise_buttons and self.CS.prev_cruise_buttons != CruiseButtons.INIT: - ret.buttonEvents = [create_button_event(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT, CruiseButtons.UNPRESS)] + buttonEvents = [create_button_event(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT, CruiseButtons.UNPRESS)] + # Handle ACCButtons changing buttons mid-press + if self.CS.cruise_buttons != CruiseButtons.UNPRESS and self.CS.prev_cruise_buttons != CruiseButtons.UNPRESS: + buttonEvents.append(create_button_event(CruiseButtons.UNPRESS, self.CS.prev_cruise_buttons, BUTTONS_DICT, CruiseButtons.UNPRESS)) + + ret.buttonEvents = buttonEvents events = self.create_common_events(ret, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.eco, GearShifter.manumatic], From 7b0f7312e577754958468ff6a176077976f1d6e2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 14 Nov 2022 04:55:46 +0800 Subject: [PATCH 0276/1179] Cabana: miscellaneous fixes (#26477) * update pos after adjusted margins * ts >=0 * output debug message to console * fix freq&count incorrect after replay auto loop restart replay * fix different height of play/pause * delay posting CAN message if UI thread is busy * >= * clear undo stack after saving * no space allowed in names * const referer --- tools/cabana/canmessages.cc | 11 +++++++---- tools/cabana/canmessages.h | 1 + tools/cabana/chartswidget.cc | 5 ++++- tools/cabana/detailwidget.cc | 1 + tools/cabana/mainwin.cc | 3 +++ tools/cabana/signaledit.cc | 1 + tools/cabana/videowidget.cc | 2 +- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index e670ee8c94..ce0b458c96 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -44,7 +44,7 @@ QList CANMessages::findSignalValues(const QString &id, const Signal *si for (auto &evt : *evts) { if (evt->which != cereal::Event::Which::CAN) continue; - for (auto c : evt->event.getCan()) { + for (const auto &c : evt->event.getCan()) { if (bus == c.getSrc() && address == c.getAddress()) { double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), *signal); if ((flag == EQ && val == value) || (flag == LT && val < value) || (flag == GT && val > value)) { @@ -65,6 +65,7 @@ void CANMessages::process(QHash *messages) { emit updated(); emit msgsReceived(messages); delete messages; + processing = false; } bool CANMessages::eventFilter(const Event *event) { @@ -78,7 +79,7 @@ bool CANMessages::eventFilter(const Event *event) { } double current_sec = replay->currentSeconds(); - if (counters_begin_sec == 0) { + if (counters_begin_sec == 0 || counters_begin_sec >= current_sec) { counters.clear(); counters_begin_sec = current_sec; } @@ -105,7 +106,9 @@ bool CANMessages::eventFilter(const Event *event) { } double ts = millis_since_boot(); - if ((ts - prev_update_ts) > (1000.0 / settings.fps)) { + if ((ts - prev_update_ts) > (1000.0 / settings.fps) && !processing) { + // delay posting CAN message if UI thread is busy + processing = true; prev_update_ts = ts; // use pointer to avoid data copy in queued connection. emit received(new_msgs.release()); @@ -120,7 +123,7 @@ const std::deque CANMessages::messages(const QString &id) { } void CANMessages::seekTo(double ts) { - replay->seekTo(ts, false); + replay->seekTo(std::max(double(0), ts), false); counters_begin_sec = 0; } diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 5ee33bce0d..c52ffdee04 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -63,6 +63,7 @@ protected: Replay *replay = nullptr; std::mutex lock; std::atomic counters_begin_sec = 0; + std::atomic processing = false; QHash counters; QHash> received_msgs; }; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 875ed80ac5..220685a86b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -192,6 +192,8 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) chart->createDefaultAxes(); chart->legend()->hide(); chart->layout()->setContentsMargins(0, 0, 0, 0); + // top margin for title + chart->setMargins({0, 11, 0, 0}); line_marker = new QGraphicsLineItem(chart); line_marker->setZValue(chart->zValue() + 10); @@ -265,6 +267,7 @@ 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()); } } @@ -290,7 +293,7 @@ void ChartView::updateSeries(const std::pair range) { 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 (auto c : (*it)->event.getCan()) { + 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); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 25c3a528f9..00145395fd 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -266,6 +266,7 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title form_layout->addRow("ID", new QLabel(msg_id)); name_edit = new QLineEdit(title, this); + name_edit->setValidator(new QRegExpValidator(QRegExp("^(\\w+)"), name_edit)); form_layout->addRow(tr("Name"), name_edit); size_spin = new QSpinBox(this); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 40a99a7a56..97d62cb4f4 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -1,5 +1,6 @@ #include "tools/cabana/mainwin.h" +#include #include #include #include @@ -20,6 +21,7 @@ static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { + if (type == QtDebugMsg) std::cout << msg.toStdString() << std::endl; if (main_win) emit main_win->showMessage(msg, 0); } @@ -192,6 +194,7 @@ void MainWindow::saveDBCToFile() { QFile file(file_name); if (file.open(QIODevice::WriteOnly)) file.write(dbc()->generateDBC().toUtf8()); + detail_widget->undo_stack->clear(); } } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 1cf9b8ae57..d96587e406 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -16,6 +16,7 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { QFormLayout *form_layout = new QFormLayout(this); name = new QLineEdit(); + name->setValidator(new QRegExpValidator(QRegExp("^(\\w+)"), name)); form_layout->addRow(tr("Name"), name); size = new QSpinBox(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index d5e640b5f7..d85b23b7e6 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -37,7 +37,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { // btn controls QHBoxLayout *control_layout = new QHBoxLayout(); play_btn = new QPushButton("⏸"); - play_btn->setStyleSheet("font-weight:bold"); + play_btn->setStyleSheet("font-weight:bold; height:16px"); control_layout->addWidget(play_btn); QButtonGroup *group = new QButtonGroup(this); From f924e797b745bf3a93201de85f807a0d101eaa0e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 14 Nov 2022 04:56:05 +0800 Subject: [PATCH 0277/1179] Cabana: remove bus time from can message (#26475) remove bustime --- tools/cabana/canmessages.cc | 1 - tools/cabana/canmessages.h | 1 - 2 files changed, 2 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index ce0b458c96..3bcaae4bbd 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -95,7 +95,6 @@ bool CANMessages::eventFilter(const Event *event) { } CanData &data = list.emplace_front(); data.ts = current_sec; - data.bus_time = c.getBusTime(); data.dat.append((char *)c.getDat().begin(), c.getDat().size()); data.count = ++counters[id]; diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index c52ffdee04..ff41edad54 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -16,7 +16,6 @@ struct CanData { double ts = 0.; uint32_t count = 0; uint32_t freq = 0; - uint16_t bus_time = 0; QByteArray dat; }; From 3d208567f34bac3f7f910c8f0343d9472b67bf6c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 14 Nov 2022 04:56:26 +0800 Subject: [PATCH 0278/1179] Cabana: added color labels to signal list (#26485) add color label --- tools/cabana/signaledit.cc | 55 +++++++++++++++++++++++++++----------- tools/cabana/signaledit.h | 5 ++-- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d96587e406..8737154c16 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -71,22 +71,40 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); // title bar - auto toolbar = new QToolBar(this); - toolbar->setStyleSheet("QToolButton {width:15px;height:15px;font-size:15px}"); - icon = new QLabel(); - toolbar->addWidget(icon); + auto title_bar = new QWidget(this); + title_bar->setFixedHeight(32); + QHBoxLayout *title_layout = new QHBoxLayout(title_bar); + title_layout->setContentsMargins(0, 0, 0, 0); + title_bar->setStyleSheet("QToolButton {width:15px;height:15px;font-size:15px}"); + color_label = new QLabel(this); + color_label->setFixedWidth(25); + color_label->setContentsMargins(5, 0, 0, 0); + title_layout->addWidget(color_label); + icon = new QLabel(this); + title_layout->addWidget(icon); title = new ElidedLabel(this); title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - title->setStyleSheet(QString("font-weight:bold; color:%1").arg(getColor(index))); - toolbar->addWidget(title); - plot_btn = toolbar->addAction("", [this]() { emit showChart(msg_id, sig, !chart_opened); }); - auto seek_btn = toolbar->addAction(QIcon::fromTheme("edit-find"), "", [this]() { SignalFindDlg(msg_id, sig, this).exec(); }); + title_layout->addWidget(title); + + plot_btn = new QToolButton(this); + plot_btn->setText("📈"); + plot_btn->setCheckable(true); + plot_btn->setAutoRaise(true); + title_layout->addWidget(plot_btn); + auto seek_btn = new QToolButton(this); + seek_btn->setIcon(QIcon::fromTheme("edit-find")); + seek_btn->setAutoRaise(true); seek_btn->setToolTip(tr("Find signal values")); - auto remove_btn = toolbar->addAction("x", [this]() { emit remove(sig); }); + title_layout->addWidget(seek_btn); + auto remove_btn = new QToolButton(this); + remove_btn->setAutoRaise(true); + remove_btn->setText("x"); remove_btn->setToolTip(tr("Remove signal")); - main_layout->addWidget(toolbar); + title_layout->addWidget(remove_btn); + main_layout->addWidget(title_bar); // signal form form = new SignalForm(this); @@ -99,8 +117,11 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa hline->setFrameShadow(QFrame::Sunken); main_layout->addWidget(hline); - QObject::connect(form, &SignalForm::changed, 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); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } @@ -108,7 +129,9 @@ void SignalEdit::setSignal(const QString &message_id, const Signal *signal) { sig = signal; updateForm(msg_id == message_id && form->isVisible()); msg_id = message_id; - title->setText(QString("%1. %2").arg(form_idx + 1).arg(sig->name.c_str())); + color_label->setText(QString::number(form_idx + 1)); + color_label->setStyleSheet(QString("background-color:%1").arg(getColor(form_idx))); + title->setText(sig->name.c_str()); show(); } @@ -145,9 +168,8 @@ void SignalEdit::saveSignal() { } void SignalEdit::setChartOpened(bool opened) { - plot_btn->setText(opened ? "☒" : "📈"); plot_btn->setToolTip(opened ? tr("Close Plot") : tr("Show Plot")); - chart_opened = opened; + plot_btn->setChecked(opened); } void SignalEdit::updateForm(bool visible) { @@ -175,8 +197,9 @@ void SignalEdit::showFormClicked() { } void SignalEdit::signalHovered(const Signal *s) { - auto color = sig == s ? hoverColor(getColor(form_idx)) : QColor(getColor(form_idx)); - title->setStyleSheet(QString("font-weight:bold; color:%1").arg(color.name())); + 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())); } void SignalEdit::hideEvent(QHideEvent *event) { diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 46ea1bfbe0..335e49a869 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -54,10 +53,10 @@ protected: SignalForm *form = nullptr; ElidedLabel *title; + QLabel *color_label; QLabel *icon; int form_idx = 0; - bool chart_opened = false; - QAction *plot_btn; + QToolButton *plot_btn; }; class SignalFindDlg : public QDialog { From 4ef941e954198a6ed77b4d1cf9389cd621da6aac Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 14 Nov 2022 04:56:48 +0800 Subject: [PATCH 0279/1179] Cabana: update detail view on change (#26476) update on changed --- tools/cabana/detailwidget.cc | 7 ++++--- tools/cabana/detailwidget.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 00145395fd..260c9dfec7 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -89,7 +89,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(binary_view, &BinaryView::resizeSignal, this, &DetailWidget::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, this, &DetailWidget::addSignal); - QObject::connect(can, &CANMessages::updated, this, &DetailWidget::updateState); + QObject::connect(can, &CANMessages::msgsReceived, this, &DetailWidget::updateState); QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { dbcMsgChanged(); }); QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { @@ -179,9 +179,10 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { QTimer::singleShot(1, [this]() { setUpdatesEnabled(true); }); } -void DetailWidget::updateState() { +void DetailWidget::updateState(const QHash * msgs) { time_label->setText(QString::number(can->currentSec(), 'f', 3)); - if (msg_id.isEmpty()) return; + if (!msgs->contains(msg_id)) + return; binary_view->updateState(); history_log->updateState(); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 815afa9bce..5fc6d122fe 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -36,7 +36,7 @@ private: void removeSignal(const Signal *sig); void editMsg(); void removeMsg(); - void updateState(); + void updateState(const QHash * msgs); QString msg_id; QLabel *name_label, *time_label, *warning_label; From 3524cc7f0bbb94ccb4d6b7b0504692d23288a05f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 13 Nov 2022 16:15:17 -0800 Subject: [PATCH 0280/1179] cruise speed tests: match controlsd initialization of cruise speed (#26491) * helper functions and fix resetting/enabling * comment (resume not yet tested) * make it clear how this resets * this is fine to enable once * same here --- selfdrive/controls/tests/test_cruise_speed.py | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index 72b7dddc20..396ff2b46f 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -5,6 +5,7 @@ import unittest from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN from cereal import car +from common.conversions import Conversions as CV from common.params import Params from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver @@ -47,40 +48,48 @@ class TestVCruiseHelper(unittest.TestCase): def setUp(self): self.CP = car.CarParams(pcmCruise=self.pcm_cruise) # pylint: disable=E1101 self.v_cruise_helper = VCruiseHelper(self.CP) + self.reset_cruise_speed_state() + + def reset_cruise_speed_state(self): + # Two resets previous cruise speed + for _ in range(2): + self.v_cruise_helper.update_v_cruise(car.CarState(cruiseState={"available": False}), enabled=False, is_metric=False) + + def enable(self, v_ego): + # Simulates user pressing set with a current speed + self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego)) def test_adjust_speed(self): """ Asserts speed changes on falling edges of buttons. """ - self.v_cruise_helper.initialize_v_cruise(car.CarState()) + self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) for btn in (ButtonType.accelCruise, ButtonType.decelCruise): - initial_v_cruise = self.v_cruise_helper.v_cruise_kph for pressed in (True, False): CS = car.CarState(cruiseState={"available": True}) CS.buttonEvents = [ButtonEvent(type=btn, pressed=pressed)] self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) - self.assertEqual(pressed, (initial_v_cruise == self.v_cruise_helper.v_cruise_kph)) + self.assertEqual(pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) def test_resume_in_standstill(self): """ Asserts we don't increment set speed if user presses resume/accel to exit cruise standstill. """ - self.v_cruise_helper.initialize_v_cruise(car.CarState()) - initial_v_cruise = self.v_cruise_helper.v_cruise_kph + self.enable(0) for standstill in (True, False): for pressed in (True, False): CS = car.CarState(cruiseState={"available": True, "standstill": standstill}) CS.buttonEvents = [ButtonEvent(type=ButtonType.accelCruise, pressed=pressed)] - self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) + # speed should only update if not at standstill and button falling edge should_equal = standstill or pressed - self.assertEqual(should_equal, (initial_v_cruise == self.v_cruise_helper.v_cruise_kph)) + self.assertEqual(should_equal, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) def test_initialize_v_cruise(self): """ @@ -88,7 +97,10 @@ class TestVCruiseHelper(unittest.TestCase): """ for v_ego in np.linspace(0, 100, 101): - self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=float(v_ego))) + self.reset_cruise_speed_state() + self.assertFalse(self.v_cruise_helper.v_cruise_initialized) + + self.enable(float(v_ego)) self.assertTrue(V_CRUISE_ENABLE_MIN <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) self.assertTrue(self.v_cruise_helper.v_cruise_initialized) From e46063086f079eff6292a32ae9aeeafa3aa523a3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 13 Nov 2022 16:34:26 -0800 Subject: [PATCH 0281/1179] controlsd: no speed increment if enabled on button rising edge (#26490) * don't increment speed if we enabled on rising edge * more realistic test --- selfdrive/controls/lib/drive_helpers.py | 10 ++++++--- selfdrive/controls/tests/test_cruise_speed.py | 21 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 37dacf5fb2..09550de7bb 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -56,7 +56,7 @@ class VCruiseHelper: # if stock cruise is completely disabled, then we can use our own set speed logic self._update_v_cruise_non_pcm(CS, enabled, is_metric) self.v_cruise_cluster_kph = self.v_cruise_kph - self.update_button_timers(CS) + self.update_button_timers(CS, enabled) else: self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH @@ -97,6 +97,10 @@ class VCruiseHelper: if button_type == ButtonType.accelCruise and cruise_standstill: return + # Don't adjust speed if we've enabled since the button was depressed (some ports enable on rising edge) + if not self.button_change_states[button_type]["enabled"]: + return + v_cruise_delta = v_cruise_delta * (5 if long_press else 1) if long_press and self.v_cruise_kph % v_cruise_delta != 0: # partial interval self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta @@ -109,7 +113,7 @@ class VCruiseHelper: self.v_cruise_kph = clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX) - def update_button_timers(self, CS): + def update_button_timers(self, CS, enabled): # increment timer for buttons still pressed for k in self.button_timers: if self.button_timers[k] > 0: @@ -119,7 +123,7 @@ class VCruiseHelper: if b.type.raw in self.button_timers: # Start/end timer and store current state on change of button pressed self.button_timers[b.type.raw] = 1 if b.pressed else 0 - self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill} + self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled} def initialize_v_cruise(self, CS): # initializing is handled by the PCM diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index 396ff2b46f..3d6f55931e 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -74,6 +74,25 @@ class TestVCruiseHelper(unittest.TestCase): self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) self.assertEqual(pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) + def test_rising_edge_enable(self): + """ + Some car interfaces may enable on rising edge of a button, + ensure we don't adjust speed if enabled changes mid-press. + """ + + # NOTE: enabled is always one frame behind the result from button press in controlsd + for enabled, pressed in ((False, False), + (False, True), + (True, False)): + CS = car.CarState(cruiseState={"available": True}) + CS.buttonEvents = [ButtonEvent(type=ButtonType.decelCruise, pressed=pressed)] + self.v_cruise_helper.update_v_cruise(CS, enabled=enabled, is_metric=False) + if pressed: + self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + + # Expected diff on enabling. Speed should not change on falling edge of pressed + self.assertEqual(not pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) + def test_resume_in_standstill(self): """ Asserts we don't increment set speed if user presses resume/accel to exit cruise standstill. @@ -93,7 +112,7 @@ class TestVCruiseHelper(unittest.TestCase): def test_initialize_v_cruise(self): """ - Asserts allowed cruise speeds on enabling with SET + Asserts allowed cruise speeds on enabling with SET. """ for v_ego in np.linspace(0, 100, 101): From ca37d0c8cc43a88189c2a96b02aed0edfe5aa32e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 13 Nov 2022 20:50:28 -0800 Subject: [PATCH 0282/1179] interfaces: disable on falling edge of cancel button (#26493) * both * Update ref_commit --- selfdrive/car/interfaces.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 982ba40b17..8e8872a539 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -250,8 +250,8 @@ class CarInterfaceBase(ABC): # Enable OP long on falling edge of enable buttons (defaults to accelCruise and decelCruise, overridable per-port) if not self.CP.pcmCruise and (b.type in enable_buttons and not b.pressed): events.add(EventName.buttonEnable) - # Disable on rising edge of cancel for both stock and OP long - if b.type == ButtonType.cancel and b.pressed: + # Disable on rising and falling edge of cancel for both stock and OP long + if b.type == ButtonType.cancel: events.add(EventName.buttonCancel) # Handle permanent and temporary steering faults diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 2ff423a84a..55788155b5 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -b5c833a8f5b3e6202a52746fc16809c7b649d591 +2ac5ecc79218aad0319e02218b050319a180e957 From 15383d30161de7646edf770153b0f81d15338c54 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 13 Nov 2022 21:13:46 -0800 Subject: [PATCH 0283/1179] GM: match stock enabling behavior (#26442) * add first draft enable button timeout * use allow_enable * it doesn't count if brakePressed * enable on rising edge of resume (matches stock) * not today * add comment describing the fault this avoids * cleaner * handle incrementing speed * rename * add test for not changing speed if enabled changes mid-press * spacey * ugh * bumpo * need this to fix a fault (draft) * already have * this should be cancel * fine to do for all * fine to do for all * bump * bumpo * bump to master * Update selfdrive/car/gm/interface.py * Update selfdrive/car/gm/interface.py * Update ref_commit --- panda | 2 +- selfdrive/car/gm/interface.py | 6 +++++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/panda b/panda index 0096d0c4fc..c0632cd32b 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 0096d0c4fc50d199ca46c6fe40479e1547408aed +Subproject commit c0632cd32b78279dfbb3ce28c7a10ded8090d40f diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index c41aac0ae0..eb5ab7329a 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -218,9 +218,13 @@ class CarInterface(CarInterfaceBase): ret.buttonEvents = buttonEvents + # The ECM allows enabling on falling edge of set, but only rising edge of resume events = self.create_common_events(ret, extra_gears=[GearShifter.sport, GearShifter.low, GearShifter.eco, GearShifter.manumatic], - pcm_enable=self.CP.pcmCruise) + pcm_enable=self.CP.pcmCruise, enable_buttons=(ButtonType.decelCruise,)) + if not self.CP.pcmCruise: + if any(b.type == ButtonType.accelCruise and b.pressed for b in ret.buttonEvents): + events.add(EventName.buttonEnable) # Enabling at a standstill with brake is allowed # TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 55788155b5..f35e23d45f 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -2ac5ecc79218aad0319e02218b050319a180e957 +aa2d370836588fd80b648dbed8d156765ec804d5 From 102669a232824c309dae269cfbdf763af5214da8 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 13 Nov 2022 22:28:27 -0800 Subject: [PATCH 0284/1179] compressed vipc: fix client connect --- tools/camerastream/compressed_vipc.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/camerastream/compressed_vipc.py b/tools/camerastream/compressed_vipc.py index 42a416985e..cab11493f2 100755 --- a/tools/camerastream/compressed_vipc.py +++ b/tools/camerastream/compressed_vipc.py @@ -91,9 +91,14 @@ def main(addr, cams, nvidia=False): vipc_server.create_buffers(vst, 4, False, W, H) vipc_server.start_listener() + procs = [] for k, v in cams.items(): - multiprocessing.Process(target=decoder, args=(addr, k, vipc_server, v, nvidia)).start() + p = multiprocessing.Process(target=decoder, args=(addr, k, vipc_server, v, nvidia)) + p.start() + procs.append(p) + for p in procs: + p.join() if __name__ == "__main__": parser = argparse.ArgumentParser(description="Decode video streams and broadcast on VisionIPC") From 29f24c7491d74ff2d2f7ca12e9a085dbe91c93fb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 15 Nov 2022 02:04:14 +0800 Subject: [PATCH 0285/1179] Cabana: Fix title overlapping on chart with long names (#26494) fix title overlapping --- tools/cabana/chartswidget.cc | 6 +----- tools/cabana/chartswidget.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 220685a86b..06387b3585 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -207,7 +207,6 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) item_group->setZValue(chart->zValue() + 10); // title - msg_title = new QGraphicsTextItem(chart); QToolButton *remove_btn = new QToolButton(); remove_btn->setText("X"); remove_btn->setAutoRaise(true); @@ -236,13 +235,11 @@ ChartView::ChartView(const QString &id, const Signal *sig, QWidget *parent) void ChartView::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); - msg_title->setPos(11, 6); close_btn_proxy->setPos(event->size().width() - close_btn_proxy->size().width() - 11, 8); } void ChartView::updateTitle() { - chart()->setTitle(signal->name.c_str()); - msg_title->setHtml(tr("%1 %2").arg(dbc()->msg(id)->name).arg(id)); + chart()->setTitle(tr("%1 %2 %3").arg(dbc()->msg(id)->name).arg(id).arg(signal->name.c_str())); } void ChartView::updateFromSettings() { @@ -250,7 +247,6 @@ void ChartView::updateFromSettings() { chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark); auto color = chart()->titleBrush().color(); line_marker->setPen(QPen(color, 2)); - msg_title->setDefaultTextColor(color); } void ChartView::setRange(double min, double max, bool force_update) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index e32a6697ce..20c673a757 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -44,7 +44,7 @@ private: QGraphicsItemGroup *item_group; QGraphicsLineItem *line_marker, *track_line; QGraphicsEllipseItem *track_ellipse; - QGraphicsTextItem *value_text, *msg_title; + QGraphicsTextItem *value_text; QGraphicsProxyWidget *close_btn_proxy; QVector vals; }; From ae40774425872b9d680448a41e2835c017c48e6c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 15 Nov 2022 02:13:16 +0800 Subject: [PATCH 0286/1179] Cabana: add test case for parsing can messages (#26495) * add test case for parsing can messages * require size equal * cleanup --- tools/cabana/tests/test_cabana.cc | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index ee4a581529..586422ffc8 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -1,6 +1,12 @@ +#include "opendbc/can/common.h" +#undef INFO #include "catch2/catch.hpp" #include "tools/cabana/dbcmanager.h" +#include "tools/replay/logreader.h" + +// demo route, first segment +const std::string TEST_RLOG_URL = "https://commadata2.blob.core.windows.net/commadata2/4cf7a6ad03080c90/2021-09-29--13-46-36/0/rlog.bz2"; TEST_CASE("DBCManager::generateDBC") { DBCManager dbc_origin(nullptr); @@ -20,3 +26,42 @@ TEST_CASE("DBCManager::generateDBC") { REQUIRE(sig == new_m.sigs[name]); } } + +TEST_CASE("Parse can messages") { + DBCManager dbc(nullptr); + dbc.open("toyota_new_mc_pt_generated"); + CANParser can_parser(0, "toyota_new_mc_pt_generated", {}, {}); + + LogReader log; + REQUIRE(log.load(TEST_RLOG_URL, nullptr, {}, true)); + REQUIRE(log.events.size() > 0); + for (auto e : log.events) { + if (e->which == cereal::Event::Which::CAN) { + std::map, std::vector> values_1; + for (const auto &c : e->event.getCan()) { + const auto msg = dbc.msg(c.getAddress()); + if (c.getSrc() == 0 && msg) { + for (auto &[name, sig] : msg->sigs) { + double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), sig); + values_1[{c.getAddress(), name.toStdString()}].push_back(val); + } + } + } + + can_parser.UpdateCans(e->mono_time, e->event.getCan()); + auto values_2 = can_parser.query_latest(); + for (auto &[key, v1] : values_1) { + bool found = false; + for (auto &v2 : values_2) { + if (v2.address == key.first && v2.name == key.second) { + REQUIRE(v2.all_values.size() == v1.size()); + REQUIRE(v2.all_values == v1); + found = true; + break; + } + } + REQUIRE(found); + } + } + } +} From f15d169289c0d806a49af123678bd49b8b3ba4f1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 14 Nov 2022 11:01:01 -0800 Subject: [PATCH 0287/1179] controlsd cruise speed: fix missing initial value --- selfdrive/controls/lib/drive_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 09550de7bb..bdbdb7023a 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -42,7 +42,7 @@ class VCruiseHelper: self.v_cruise_cluster_kph = V_CRUISE_INITIAL self.v_cruise_kph_last = 0 self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} - self.button_change_states = {btn: {"standstill": False} for btn in self.button_timers} + self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers} @property def v_cruise_initialized(self): From 41e5c79948216af2d416dcea2bceb1ba53855022 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Mon, 14 Nov 2022 15:04:59 -0500 Subject: [PATCH 0288/1179] =?UTF-8?q?VW=20MQB:=20Add=20missing=20FW=20for?= =?UTF-8?q?=202016=20=C5=A0koda=20Superb=20(#26484)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VW MQB: Add missing FW for 2016 Škoda Superb * regen CARS.md --- docs/CARS.md | 2 +- selfdrive/car/volkswagen/values.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 32da6126bd..b8a313386d 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -150,7 +150,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Škoda|Superb 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index babaffbcbe..cb2343e08f 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -233,7 +233,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21"), CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"), CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), - CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-18"), + CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-22"), CAR.SKODA_OCTAVIA_MK3: [ VWCarInfo("Škoda Octavia 2015, 2018-19"), VWCarInfo("Škoda Octavia RS 2016"), @@ -1064,6 +1064,7 @@ FW_VERSIONS = { }, CAR.SKODA_SUPERB_MK3: { (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704L906026ET\xf1\x891343', b'\xf1\x8704L906026FP\xf1\x891196', b'\xf1\x8704L906026KB\xf1\x894071', b'\xf1\x8704L906026KD\xf1\x894798', @@ -1074,9 +1075,11 @@ FW_VERSIONS = { b'\xf1\x870CW300042H \xf1\x891601', b'\xf1\x870D9300011T \xf1\x894801', b'\xf1\x870D9300012 \xf1\x894940', + b'\xf1\x870D9300041H \xf1\x894905', b'\xf1\x870GC300043 \xf1\x892301', ], (Ecu.srs, 0x715, None): [ + b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\x12111200111121001121110012211292221111', b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\022111200111121001121118112231292221111', b'\xf1\x875Q0959655AK\xf1\x890130\xf1\x82\022111200111121001121110012211292221111', b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02331310031313100313131013141319331413100', From fbf2f3816b18321ed921cf03042327134be68edb Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Mon, 14 Nov 2022 15:02:26 -0800 Subject: [PATCH 0289/1179] [locationd] Add input checks (#26460) * add input checks with same decay as reset_tracker * add observation timings check * typo * bugfix * improve offline locationd visibility * sbugfix offline lld Co-authored-by: Adeeb Shihadeh --- selfdrive/locationd/liblocationd.cc | 12 +++++ selfdrive/locationd/locationd.cc | 75 ++++++++++++++++++++++++++--- selfdrive/locationd/locationd.h | 9 +++- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/selfdrive/locationd/liblocationd.cc b/selfdrive/locationd/liblocationd.cc index 49404668a4..da57fb7ff4 100755 --- a/selfdrive/locationd/liblocationd.cc +++ b/selfdrive/locationd/liblocationd.cc @@ -26,4 +26,16 @@ extern "C" { memcpy(std_buff, stdev.data(), sizeof(double) * stdev.size()); } + bool is_gps_ok(Localizer *localizer){ + return localizer->is_gps_ok(); + } + + bool are_inputs_ok(Localizer *localizer){ + return localizer->are_inputs_ok(); + } + + void observation_timings_invalid_reset(Localizer *localizer){ + localizer->observation_timings_invalid_reset(); + } + } diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 8d9e247655..4325900c0e 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -19,6 +19,9 @@ const double VALID_TIME_SINCE_RESET = 1.0; // s const double VALID_POS_STD = 50.0; // m const double MAX_RESET_TRACKER = 5.0; const double SANE_GPS_UNCERTAINTY = 1500.0; // m +const double INPUT_INVALID_THRESHOLD = 5.0; // same as reset tracker +const double DECAY = 0.99995; // same as reset tracker +const double MAX_FILTER_REWIND_TIME = 0.8; // s // TODO: GPS sensor time offsets are empirically calculated // They should be replaced with synced time from a real clock @@ -200,6 +203,14 @@ VectorXd Localizer::get_stdev() { return this->kf->get_P().diagonal().array().sqrt(); } +bool Localizer::are_inputs_ok() { + return this->critical_services_valid(this->observation_values_invalid) && !this->observation_timings_invalid; +} + +void Localizer::observation_timings_invalid_reset(){ + this->observation_timings_invalid = false; +} + void Localizer::handle_sensor(double current_time, const cereal::SensorEventData::Reader& log) { // TODO does not yet account for double sensor readings in the log @@ -209,10 +220,15 @@ void Localizer::handle_sensor(double current_time, const cereal::SensorEventData } double sensor_time = 1e-9 * log.getTimestamp(); - + // sensor time and log time should be close if (std::abs(current_time - sensor_time) > 0.1) { LOGE("Sensor reading ignored, sensor timestamp more than 100ms off from log time"); + this->observation_timings_invalid = true; + return; + } + else if (!this->is_timestamp_valid(sensor_time)) { + this->observation_timings_invalid = true; return; } @@ -227,6 +243,10 @@ void Localizer::handle_sensor(double current_time, const cereal::SensorEventData auto meas = Vector3d(-v[2], -v[1], -v[0]); if (meas.norm() < ROTATION_SANITY_CHECK) { this->kf->predict_and_observe(sensor_time, OBSERVATION_PHONE_GYRO, { meas }); + this->observation_values_invalid["gyroscope"] *= DECAY; + } + else{ + this->observation_values_invalid["gyroscope"] += 1.0; } } @@ -242,6 +262,10 @@ void Localizer::handle_sensor(double current_time, const cereal::SensorEventData auto meas = Vector3d(-v[2], -v[1], -v[0]); if (meas.norm() < ACCEL_SANITY_CHECK) { this->kf->predict_and_observe(sensor_time, OBSERVATION_PHONE_ACCEL, { meas }); + this->observation_values_invalid["accelerometer"] *= DECAY; + } + else{ + this->observation_values_invalid["accelerometer"] += 1.0; } } } @@ -335,8 +359,14 @@ void Localizer::handle_car_state(double current_time, const cereal::CarState::Re void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log) { VectorXd rot_device = this->device_from_calib * floatlist2vector(log.getRot()); VectorXd trans_device = this->device_from_calib * floatlist2vector(log.getTrans()); + + if (!this->is_timestamp_valid(current_time)) { + this->observation_timings_invalid = true; + return; + } if ((rot_device.norm() > ROTATION_SANITY_CHECK) || (trans_device.norm() > TRANS_SANITY_CHECK)) { + this->observation_values_invalid["cameraOdometry"] += 1.0; return; } @@ -344,10 +374,12 @@ void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry VectorXd trans_calib_std = floatlist2vector(log.getTransStd()); if ((rot_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK) || (trans_calib_std.minCoeff() <= MIN_STD_SANITY_CHECK)) { + this->observation_values_invalid["cameraOdometry"] += 1.0; return; } if ((rot_calib_std.norm() > 10 * ROTATION_SANITY_CHECK) || (trans_calib_std.norm() > 10 * TRANS_SANITY_CHECK)) { + this->observation_values_invalid["cameraOdometry"] += 1.0; return; } @@ -363,12 +395,19 @@ void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry { rot_device }, { rot_device_cov }); this->kf->predict_and_observe(current_time, OBSERVATION_CAMERA_ODO_TRANSLATION, { trans_device }, { trans_device_cov }); + this->observation_values_invalid["cameraOdometry"] *= DECAY; } void Localizer::handle_live_calib(double current_time, const cereal::LiveCalibrationData::Reader& log) { + if (!this->is_timestamp_valid(current_time)) { + this->observation_timings_invalid = true; + return; + } + if (log.getRpyCalib().size() > 0) { auto live_calib = floatlist2vector(log.getRpyCalib()); if ((live_calib.minCoeff() < -CALIB_RPY_SANITY_CHECK) || (live_calib.maxCoeff() > CALIB_RPY_SANITY_CHECK)) { + this->observation_values_invalid["liveCalibration"] += 1.0; return; } @@ -376,6 +415,7 @@ void Localizer::handle_live_calib(double current_time, const cereal::LiveCalibra this->device_from_calib = euler2rot(this->calib); this->calib_from_device = this->device_from_calib.transpose(); this->calibrated = log.getCalStatus() == 1; + this->observation_values_invalid["liveCalibration"] *= DECAY; } } @@ -407,8 +447,8 @@ void Localizer::time_check(double current_time) { void Localizer::update_reset_tracker() { // reset tracker is tuned to trigger when over 1reset/10s over 2min period - if (this->isGpsOK()) { - this->reset_tracker *= .99995; + if (this->is_gps_ok()) { + this->reset_tracker *= DECAY; } else { this->reset_tracker = 0.0; } @@ -483,10 +523,28 @@ kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_build return msg_builder.toBytes(); } -bool Localizer::isGpsOK() { +bool Localizer::is_gps_ok() { return this->gps_valid; } +bool Localizer::critical_services_valid(std::map critical_services) { + for (auto &kv : critical_services){ + if (kv.second >= INPUT_INVALID_THRESHOLD){ + return false; + } + } + return true; +} + +bool Localizer::is_timestamp_valid(double current_time) { + double filter_time = this->kf->get_filter_time(); + if (!std::isnan(filter_time) && ((filter_time - current_time) > MAX_FILTER_REWIND_TIME)) { + LOGE("Observation timestamp is older than the max rewind threshold of the filter"); + return false; + } + return true; +} + void Localizer::determine_gps_mode(double current_time) { // 1. If the pos_std is greater than what's not acceptable and localizer is in gps-mode, reset to no-gps-mode // 2. If the pos_std is greater than what's not acceptable and localizer is in no-gps-mode, fake obs @@ -521,10 +579,15 @@ int Localizer::locationd_thread() { uint64_t cnt = 0; bool filterInitialized = false; + const std::vector critical_input_services = {"cameraOdometry", "liveCalibration", "accelerometer", "gyroscope"}; + for (std::string service : critical_input_services) { + this->observation_values_invalid.insert({service, 0.0}); + } while (!do_exit) { sm.update(); if (filterInitialized){ + this->observation_timings_invalid_reset(); for (const char* service : service_list) { if (sm.updated(service) && sm.valid(service)){ const cereal::Event::Reader log = sm[service]; @@ -538,8 +601,8 @@ int Localizer::locationd_thread() { // 100Hz publish for notcars, 20Hz for cars const char* trigger_msg = sm["carParams"].getCarParams().getNotCar() ? "accelerometer" : "cameraOdometry"; if (sm.updated(trigger_msg)) { - bool inputsOK = sm.allAliveAndValid(); - bool gpsOK = this->isGpsOK(); + bool inputsOK = sm.allAliveAndValid() && this->are_inputs_ok(); + bool gpsOK = this->is_gps_ok(); bool sensorsOK = sm.allAliveAndValid({"accelerometer", "gyroscope"}); MessageBuilder msg_builder; diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index d6bb5347c5..f0872d9f56 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "cereal/messaging/messaging.h" @@ -32,8 +33,12 @@ public: void finite_check(double current_time = NAN); void time_check(double current_time = NAN); void update_reset_tracker(); - bool isGpsOK(); + bool is_gps_ok(); + bool critical_services_valid(std::map critical_services); + bool is_timestamp_valid(double current_time); void determine_gps_mode(double current_time); + bool are_inputs_ok(); + void observation_timings_invalid_reset(); kj::ArrayPtr get_message_bytes(MessageBuilder& msg_builder, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid); @@ -73,4 +78,6 @@ private: bool gps_mode = false; bool gps_valid = false; bool ublox_available = true; + bool observation_timings_invalid = false; + std::map observation_values_invalid; }; From 8e91ce1eb4f91c976570056fd8979a4afcf43a53 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 15 Nov 2022 11:09:19 +0800 Subject: [PATCH 0290/1179] Cabana: Move history logs to a tabbed widget (#26481) * tabwidget * cleanup * update state before show * cleanup * remove spacing * fix right panel stretch issue * fix missing } --- tools/cabana/detailwidget.cc | 55 +++++++++++++++++++++++------------- tools/cabana/detailwidget.h | 6 ++-- tools/cabana/historylog.cc | 4 +-- tools/cabana/mainwin.cc | 7 +++-- tools/cabana/signaledit.cc | 15 ---------- tools/cabana/signaledit.h | 6 ++-- 6 files changed, 47 insertions(+), 46 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 260c9dfec7..192d1fd66c 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -64,31 +64,35 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart frame_layout->addWidget(warning_widget); main_layout->addWidget(title_frame); - QWidget *container = new QWidget(this); - QVBoxLayout *container_layout = new QVBoxLayout(container); - container_layout->setSpacing(0); - container_layout->setContentsMargins(0, 0, 0, 0); - - scroll = new QScrollArea(this); - scroll->setWidget(container); - scroll->setWidgetResizable(true); - scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - main_layout->addWidget(scroll); - + // msg widget + QWidget *msg_widget = new QWidget(this); + QVBoxLayout *msg_layout = new QVBoxLayout(msg_widget); + msg_layout->setContentsMargins(0, 0, 0, 0); // binary view binary_view = new BinaryView(this); - container_layout->addWidget(binary_view); - + msg_layout->addWidget(binary_view); // signals signals_layout = new QVBoxLayout(); - container_layout->addLayout(signals_layout); + signals_layout->setSpacing(0); + msg_layout->addLayout(signals_layout); + msg_layout->addStretch(0); - // history log + scroll = new QScrollArea(this); + scroll->setFrameShape(QFrame::NoFrame); + scroll->setWidget(msg_widget); + scroll->setWidgetResizable(true); + scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + tab_widget = new QTabWidget(this); + tab_widget->setTabPosition(QTabWidget::South); + tab_widget->addTab(scroll, "Msg"); history_log = new HistoryLog(this); - container_layout->addWidget(history_log); + tab_widget->addTab(history_log, "Logs"); + main_layout->addWidget(tab_widget); 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(); }); QObject::connect(can, &CANMessages::msgsReceived, this, &DetailWidget::updateState); QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { dbcMsgChanged(); }); QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); @@ -151,6 +155,7 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { form = new SignalEdit(i); QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); + QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showFormClicked); QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); QObject::connect(form, &SignalEdit::showChart, charts, &ChartsWidget::showChart); @@ -176,16 +181,26 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { warning_label->setText(warnings.join('\n')); warning_widget->setVisible(!warnings.isEmpty()); - QTimer::singleShot(1, [this]() { setUpdatesEnabled(true); }); + setUpdatesEnabled(true); } void DetailWidget::updateState(const QHash * msgs) { time_label->setText(QString::number(can->currentSec(), 'f', 3)); - if (!msgs->contains(msg_id)) + if (msg_id.isEmpty() || (msgs && !msgs->contains(msg_id))) return; - binary_view->updateState(); - history_log->updateState(); + if (tab_widget->currentIndex() == 0) + binary_view->updateState(); + else + history_log->updateState(); +} + +void DetailWidget::showFormClicked() { + auto s = qobject_cast(sender()); + setUpdatesEnabled(false); + for (auto f : signal_list) + f->updateForm(f == s && !f->isFormVisible()); + setUpdatesEnabled(true); } void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool opened) { diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 5fc6d122fe..4346d1c5d5 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -28,6 +28,7 @@ public: QUndoStack *undo_stack = nullptr; private: + void showFormClicked(); void updateChartState(const QString &id, const Signal *sig, bool opened); void showTabBarContextMenu(const QPoint &pt); void addSignal(int start_bit, int size, bool little_endian); @@ -36,13 +37,14 @@ private: void removeSignal(const Signal *sig); void editMsg(); void removeMsg(); - void updateState(const QHash * msgs); + void updateState(const QHash * msgs = nullptr); QString msg_id; QLabel *name_label, *time_label, *warning_label; QWidget *warning_widget; QVBoxLayout *signals_layout; QTabBar *tabbar; + QTabWidget *tab_widget; QToolBar *toolbar; QAction *remove_msg_act; HistoryLog *history_log; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 28e344a46e..1b0898afbd 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -86,10 +86,8 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); verticalHeader()->setVisible(false); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); setFrameShape(QFrame::NoFrame); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 97d62cb4f4..f0419a2fb3 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -72,7 +72,7 @@ MainWindow::MainWindow() : QMainWindow() { video_widget = new VideoWidget(this); r_layout->addWidget(video_widget, 0, Qt::AlignTop); - r_layout->addWidget(charts_widget); + r_layout->addWidget(charts_widget, 1); main_layout->addWidget(right_container); setCentralWidget(central_widget); @@ -192,9 +192,10 @@ void MainWindow::saveDBCToFile() { if (!file_name.isEmpty()) { settings.last_dir = QFileInfo(file_name).absolutePath(); QFile file(file_name); - if (file.open(QIODevice::WriteOnly)) + if (file.open(QIODevice::WriteOnly)) { file.write(dbc()->generateDBC().toUtf8()); detail_widget->undo_stack->clear(); + } } } @@ -216,7 +217,7 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); - r_layout->addWidget(charts_widget); + r_layout->addWidget(charts_widget, 1); floating_window->deleteLater(); floating_window = nullptr; } else if (!dock && !floating_window) { diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 8737154c16..eb22b78d5a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -189,26 +188,12 @@ void SignalEdit::updateForm(bool visible) { icon->setText(visible ? "▼ " : "> "); } -void SignalEdit::showFormClicked() { - parentWidget()->setUpdatesEnabled(false); - for (auto &edit : parentWidget()->findChildren()) - edit->updateForm(edit == this && !form->isVisible()); - QTimer::singleShot(1, [this]() { parentWidget()->setUpdatesEnabled(true); }); -} - 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())); } -void SignalEdit::hideEvent(QHideEvent *event) { - msg_id = ""; - sig = nullptr; - updateForm(false); - QWidget::hideEvent(event); -} - void SignalEdit::enterEvent(QEvent *event) { emit highlight(sig); QWidget::enterEvent(event); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 335e49a869..da0b9758c7 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -34,6 +34,8 @@ public: void setSignal(const QString &msg_id, const Signal *sig); void setChartOpened(bool opened); void signalHovered(const Signal *sig); + void updateForm(bool show); + inline bool isFormVisible() const { return form->isVisible(); } const Signal *sig = nullptr; QString msg_id; @@ -42,14 +44,12 @@ signals: void showChart(const QString &name, const Signal *sig, bool show); void remove(const Signal *sig); void save(const Signal *sig, const Signal &new_sig); + void showFormClicked(); protected: - void hideEvent(QHideEvent *event) override; void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void saveSignal(); - void updateForm(bool show); - void showFormClicked(); SignalForm *form = nullptr; ElidedLabel *title; From 2d766fee14e94011e261c8c557098a7223c87014 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 14 Nov 2022 22:46:29 -0500 Subject: [PATCH 0291/1179] HKG: Car Port for 2022 Kia Stinger (#26397) * HKG: Car Port for 2022 Kia Stinger * Substitute KIA STINGER GT2 2018 torque params * bump panda * Add test route * Update CARS.md * Not this checksum * Update test route * Update CARS.md * Harness C -> Harness K Co-authored-by: Adeeb Shihadeh --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/car/hyundai/hyundaican.py | 3 ++- selfdrive/car/hyundai/interface.py | 2 +- selfdrive/car/hyundai/values.py | 22 +++++++++++++++++++++- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index bf89b667fa..d00ece4b73 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -30,6 +30,7 @@ Version 0.8.17 (2022-11-21) * Hyundai Santa Cruz 2021-22 support thanks to sunnyhaibin! * Kia Sportage 2023 support thanks to sunnyhaibin! * Kia Sportage Hybrid 2023 support thanks to sunnyhaibin! +* Kia Stinger 2022 support thanks to sunnyhaibin! Version 0.8.16 (2022-08-26) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index b8a313386d..ca3a224586 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 214 Supported Cars +# 215 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -107,6 +107,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Sportage 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 2f944edc0f..1ab90878b8 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -175,7 +175,7 @@ class CarController: if self.frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV, CAR.KONA_EV_2022, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022, - CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022): + CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022): can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled)) # 5 Hz ACC options diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index dcb8430976..c2ffffbf22 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -20,7 +20,8 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, if car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.SANTA_FE, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, - CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022): + CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, + CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022): values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsOpt_USM"] = 2 diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 0306f7e104..0b5fd3bb39 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -158,7 +158,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.5 if candidate == CAR.KIA_OPTIMA_G4: ret.minSteerSpeed = 32 * CV.MPH_TO_MS - elif candidate == CAR.KIA_STINGER: + elif candidate in (CAR.KIA_STINGER, CAR.KIA_STINGER_2022): ret.mass = 1825. + STD_CARGO_KG ret.wheelbase = 2.78 ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1dba3a5442..ecba7b7494 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -95,6 +95,7 @@ class CAR: KIA_SORENTO = "KIA SORENTO GT LINE 2018" KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN" KIA_STINGER = "KIA STINGER GT2 2018" + KIA_STINGER_2022 = "KIA STINGER 2022" KIA_CEED = "KIA CEED INTRO ED 2019" KIA_EV6 = "KIA EV6 2022" @@ -181,6 +182,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { ], CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), + CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness=Harness.hyundai_k), CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e), CAR.KIA_EV6: [ HyundaiCarInfo("Kia EV6 (without HDA II) 2022", "Highway Driving Assist", harness=Harness.hyundai_l), @@ -790,6 +792,23 @@ FW_VERSIONS = { b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', ], }, + CAR.KIA_STINGER_2022: { + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00CK__ SCC F-CUP 1.00 1.00 99110-J5500 ', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81640R0051\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7d4, None): [ + b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5380 4C2VR503', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00CK MFC AT AUS RHD 1.00 1.00 99211-J5500 210622', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x87VCNLF11383972DK1vffV\x99\x99\x89\x98\x86eUU\x88wg\x89vfff\x97fff\x99\x87o\xff"\xc1\xf1\x81E30\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E30\x00\x00\x00\x00\x00\x00\x00SCK0T33GH0\xbe`\xfb\xc6', + ], + }, CAR.PALISADE: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00LX2_ SCC F-CUP 1.00 1.04 99110-S8100 ', @@ -1451,7 +1470,7 @@ FEATURES = { "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022}, # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022}, + "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN} @@ -1496,6 +1515,7 @@ DBC = { CAR.KIA_SELTOS: dbc_dict('hyundai_kia_generic', None), CAR.KIA_SORENTO: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format CAR.KIA_STINGER: dbc_dict('hyundai_kia_generic', None), + CAR.KIA_STINGER_2022: dbc_dict('hyundai_kia_generic', None), CAR.KONA: dbc_dict('hyundai_kia_generic', None), CAR.KONA_EV: dbc_dict('hyundai_kia_generic', None), CAR.KONA_EV_2022: dbc_dict('hyundai_kia_generic', None), diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index d0051454a6..cd61528439 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -111,6 +111,7 @@ routes = [ CarTestRoute("ff973b941a69366f|2022-07-28--22-01-19", HYUNDAI.KONA_EV_2022, segment=11), CarTestRoute("49f3c13141b6bc87|2021-07-28--08-05-13", HYUNDAI.KONA_HEV), CarTestRoute("5dddcbca6eb66c62|2020-07-26--13-24-19", HYUNDAI.KIA_STINGER), + CarTestRoute("5b50b883a4259afb|2022-11-09--15-00-42", HYUNDAI.KIA_STINGER_2022), CarTestRoute("d624b3d19adce635|2020-08-01--14-59-12", HYUNDAI.VELOSTER), CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2 CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1 diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index c043c9d455..77236e393e 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -37,6 +37,7 @@ HYUNDAI ELANTRA 2017: HYUNDAI SONATA 2019 HYUNDAI ELANTRA HYBRID 2021: HYUNDAI SONATA 2020 HYUNDAI TUCSON 2019: HYUNDAI SANTA FE 2019 HYUNDAI SANTA FE 2022: HYUNDAI SANTA FE HYBRID 2022 +KIA STINGER 2022: KIA STINGER GT2 2018 GENESIS G90 2017: GENESIS G70 2018 GENESIS G80 2017: GENESIS G70 2018 GENESIS G70 2020: HYUNDAI SONATA 2020 From 7fcafa402239c30d8344c46608ade6a8fd4831f4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 14 Nov 2022 23:28:43 -0800 Subject: [PATCH 0292/1179] ui: stretch abstract control title (#26499) stretch toggle title so it's easier to expand --- selfdrive/ui/qt/widgets/controls.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index d3b77935df..619fd3cb4c 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -38,7 +38,7 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons title_label = new QPushButton(title); title_label->setFixedHeight(120); title_label->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left"); - hlayout->addWidget(title_label); + hlayout->addWidget(title_label, 1); // value next to control button value = new ElidedLabel(); From ffa32df062fe3cf241e887e7afbc582118bd1e36 Mon Sep 17 00:00:00 2001 From: ambientocclusion <1399123+ambientocclusion@users.noreply.github.com> Date: Tue, 15 Nov 2022 00:04:20 -0800 Subject: [PATCH 0293/1179] Multilang: add missing Japanese translations (#26482) Add new Japanese translations --- selfdrive/ui/translations/main_ja.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 87c60516fc..339826796b 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -60,11 +60,11 @@ Cellular Metered - + 従量制通信設定 Prevent large data uploads when on a metered connection - + 大量のデータのアップロードを防止します。 @@ -240,11 +240,11 @@ Reset - + リセット Review - + 確認 @@ -864,7 +864,7 @@ location set Uninstall - + アンインストール @@ -1004,19 +1004,19 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - + openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。 <br> <h4>🌮 エンドツーエンドアクセル制御 🌮</h4> エンジンとブレーキの制御を全てopenpilotの運転モデルに委ねます。openpilotは人間が運転するのと同じように考え、赤信号や停止サインで車を停止します。openpilotが運転速度も決めるので、あなたが設定する速度は上限速度になります。 openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - + openpilotは、この車に搭載されているアクセル制御(ACC)を標準で利用します。openpilotによるアクセル制御を利用したい場合は、この設定を有効にしてください。 WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - + 警告: この車種でのopenpilotによるアクセル制御は実験段階であり、衝突被害軽減ブレーキ(AEB)を無効化します。 @@ -1074,7 +1074,7 @@ location set Forget - + 削除 From d7f943e27524744f20b008a55ad3358fc9272034 Mon Sep 17 00:00:00 2001 From: Oxygen Date: Tue, 15 Nov 2022 16:23:37 +0800 Subject: [PATCH 0294/1179] Update missing items in main_zh-CHS.ts (#26492) Update missing iterms in main_zh-CHS.ts Co-authored-by: Shane Smiskol --- selfdrive/ui/translations/main_zh-CHS.ts | 50 ++++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 558a6cec4f..64b32c80d5 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -60,11 +60,11 @@ Cellular Metered - + 按流量计费的手机移动网络 Prevent large data uploads when on a metered connection - + 当使用按流量计费的连接时,避免上传大流量数据 @@ -140,7 +140,7 @@ Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - 打开并预览驾驶员摄像头,以确保驾驶员监控具有良好视野。仅熄火时可用。 + 打开并预览驾驶员摄像头,以确保驾驶员监控具有良好视野。(仅熄火时可用) Reset Calibration @@ -204,7 +204,7 @@ Your device is pointed %1° %2 and %3° %4. - 您的设备校准为%1° %2、%3° %4。 + 您的设备校准为%1° %2、%3° %4。 down @@ -240,11 +240,11 @@ Reset - + 重置 Review - + 预览 @@ -814,35 +814,35 @@ location set SoftwarePanel Updates are only downloaded while the car is off. - + 车辆熄火时才能下载升级文件。 Current Version - + 当前版本 Download - + 下载 Install Update - + 安装更新 INSTALL - + 安装 Target Branch - + 目标分支 SELECT - + 选择 Select a branch - + 选择分支 UNINSTALL @@ -862,7 +862,7 @@ location set Uninstall - + 卸载 @@ -966,15 +966,15 @@ location set Experimental openpilot Longitudinal Control - + 试验性的openpilot纵向控制 openpilot longitudinal control is not currently available for this car. - + 目前此车辆无法使用openpilot纵向控制功能。 Enable experimental longitudinal control to enable this. - + 启用试验性的纵向控制功能。 Disengage on Accelerator Pedal @@ -1002,19 +1002,19 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - + openpilot 默认 <b>轻松模式</b>驾驶车辆。 试验模式启用一些轻松模式之外的 <b>试验性功能</b>。 试验性功能包括: <br> <h4>🌮 端到端(End-to-End) 纵向控制 🌮</h4> 允许智能驾驶模型控制加速和制动。 openpilot 将模仿人类驾驶行为, 包括在遇到红灯和停车让行标识时停车。 鉴于智能驾驶模型判断实际行驶车速,设定速度仅为车速上限。 openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - + openpilot默认使用此车辆自带ACC,而非openpilot纵向控制功能。启用此按钮将切换到openpilot纵向控制功能。 WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). - + 警告: 此车辆的openpilot纵向控制是试验性功能,且将禁用AEB自动刹车功能。 @@ -1064,15 +1064,15 @@ location set FORGET - 忘记 + 忽略 Forget Wi-Fi Network "%1"? - 忘记WiFi网络 "%1"? + 忽略WiFi网络 "%1"? Forget - + 忽略 From e58f6fbc11424e8059d6a86a4f0990f604c3a22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 15 Nov 2022 00:46:47 -0800 Subject: [PATCH 0295/1179] Rate limit honda steer (#26500) * Rate limit honda steer * Update ref_commit --- selfdrive/car/honda/carcontroller.py | 14 +++++++++++++- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 5fa475fe08..ba1f13fb4e 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -99,6 +99,12 @@ HUDData = namedtuple("HUDData", "lanes_visible", "fcw", "acc_alert", "steer_required"]) +def rate_limit_steer(new_steer, last_steer): + # TODO just hardcoded ramp to min/max in 0.2s for all Honda + MAX_DELTA = 5 * DT_CTRL + return clip(new_steer, last_steer - MAX_DELTA, last_steer + MAX_DELTA) + + class CarController: def __init__(self, dbc_name, CP, VM): self.CP = CP @@ -116,6 +122,7 @@ class CarController: self.speed = 0.0 self.gas = 0.0 self.brake = 0.0 + self.last_steer = 0.0 def update(self, CC, CS): actuators = CC.actuators @@ -130,6 +137,10 @@ class CarController: accel = 0.0 gas, brake = 0.0, 0.0 + # *** rate limit steer *** + limited_steer = rate_limit_steer(actuators.steer, self.last_steer) + self.last_steer = limited_steer + # *** apply brake hysteresis *** pre_limit_brake, self.braking, self.brake_steady = actuator_hysteresis(brake, self.braking, self.brake_steady, CS.out.vEgo, self.CP.carFingerprint) @@ -143,7 +154,7 @@ class CarController: # **** process the car messages **** # steer torque is converted back to CAN reference (positive when steering right) - apply_steer = int(interp(-actuators.steer * self.params.STEER_MAX, + apply_steer = int(interp(-limited_steer * self.params.STEER_MAX, self.params.STEER_LOOKUP_BP, self.params.STEER_LOOKUP_V)) # Send CAN commands @@ -250,6 +261,7 @@ class CarController: new_actuators.accel = self.accel new_actuators.gas = self.gas new_actuators.brake = self.brake + new_actuators.steer = self.last_steer self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index f35e23d45f..a8053936d7 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -aa2d370836588fd80b648dbed8d156765ec804d5 +324408a87f49413da864616cb409537ce7d8beb2 From 844f7692d48c5b2b2b6f8bc90070d9fc83ef7171 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 15 Nov 2022 19:44:25 +0100 Subject: [PATCH 0296/1179] loggerd: add missing utility include (#26502) --- selfdrive/loggerd/loggerd.h | 1 + selfdrive/loggerd/tests/test_logger.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/selfdrive/loggerd/loggerd.h b/selfdrive/loggerd/loggerd.h index 6eafbe08d0..1fa6349828 100644 --- a/selfdrive/loggerd/loggerd.h +++ b/selfdrive/loggerd/loggerd.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "cereal/messaging/messaging.h" #include "cereal/services.h" diff --git a/selfdrive/loggerd/tests/test_logger.cc b/selfdrive/loggerd/tests/test_logger.cc index 18a0e57df7..ba7835d632 100644 --- a/selfdrive/loggerd/tests/test_logger.cc +++ b/selfdrive/loggerd/tests/test_logger.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include "catch2/catch.hpp" #include "cereal/messaging/messaging.h" From bdc432d21824cc83627bb5d1abd5e99b4bc62fc3 Mon Sep 17 00:00:00 2001 From: Tim Wilson Date: Tue, 15 Nov 2022 11:55:43 -0700 Subject: [PATCH 0297/1179] Add video link for Volt (#26504) --- 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 eace6b6aca..03392ba0f9 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -90,7 +90,7 @@ class GMCarInfo(CarInfo): CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.HOLDEN_ASTRA: GMCarInfo("Holden Astra 2017"), - CAR.VOLT: GMCarInfo("Chevrolet Volt 2017-18", min_enable_speed=0), + CAR.VOLT: GMCarInfo("Chevrolet Volt 2017-18", min_enable_speed=0, video_link="https://youtu.be/QeMCN_4TFfQ"), CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"), CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), From a662af57c7de750df4f1650ee4079c56665b817e Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Tue, 15 Nov 2022 13:07:46 -0800 Subject: [PATCH 0298/1179] CI: use github.head_ref to group PR action runs (#26505) * CI: use github.head_ref to group PR action runs for push triggers, github.ref is set to the "branch or tag ref that was pushed" for pull_request triggers, it is set to the "pull request merge branch" (master?) github.head_ref is only set when the trigger is pull_request https://docs.github.com/en/actions/learn-github-actions/contexts#github-context * only check github.ref for push event --- .github/workflows/selfdrive_tests.yaml | 2 +- .github/workflows/tools_tests.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 598f2c592b..f2cc51285d 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -7,7 +7,7 @@ on: pull_request: concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} + group: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }} cancel-in-progress: true env: diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 549a2f4195..94cc3c2580 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -7,7 +7,7 @@ on: pull_request: concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/master' && github.ref || github.run_id }}-${{ github.event_name }} + group: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }} cancel-in-progress: true env: From fbf3ef0895182ffab90ddda83fa485b02d5a76d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 15 Nov 2022 14:21:00 -0800 Subject: [PATCH 0299/1179] More Honda rate limit (#26509) * More Honda rate limit * Update ref_commit --- selfdrive/car/honda/carcontroller.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index ba1f13fb4e..790dce1810 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -100,8 +100,8 @@ HUDData = namedtuple("HUDData", def rate_limit_steer(new_steer, last_steer): - # TODO just hardcoded ramp to min/max in 0.2s for all Honda - MAX_DELTA = 5 * DT_CTRL + # TODO just hardcoded ramp to min/max in 0.33s for all Honda + MAX_DELTA = 3 * DT_CTRL return clip(new_steer, last_steer - MAX_DELTA, last_steer + MAX_DELTA) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a8053936d7..4aa9d60ab5 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -324408a87f49413da864616cb409537ce7d8beb2 +959e63af52d9efdb62156cab4b773f88b154fd75 From 9c5df76a6c8784af3bec64827a2dbab464d8ce39 Mon Sep 17 00:00:00 2001 From: hoomoose <94947902+hoomoose@users.noreply.github.com> Date: Tue, 15 Nov 2022 17:19:30 -0700 Subject: [PATCH 0300/1179] Hyundai: longitudinal support for all CAN-FD EV and Hybrids (#26345) * Update values.py * Update interface.py * Update interface.py * Update carcontroller.py * Update interface.py * Update interface.py * Update values.py * Update values.py * Update interface.py * Update values.py * Update interface.py * Update carcontroller.py * cleanup * update docs * bump panda Co-authored-by: Adeeb Shihadeh --- docs/CARS.md | 12 ++++++------ panda | 2 +- selfdrive/car/hyundai/carcontroller.py | 5 +++-- selfdrive/car/hyundai/interface.py | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index ca3a224586..59b8145556 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -60,8 +60,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Ioniq 5 (with HDA II) 2022-23|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| -|Hyundai|Ioniq 5 (without HDA II) 2022-23|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| +|Hyundai|Ioniq 5 (with HDA II) 2022-23|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| +|Hyundai|Ioniq 5 (without HDA II) 2022-23|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| @@ -83,13 +83,13 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Tucson Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Hyundai|Tucson Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Kia|EV6 (with HDA II) 2022|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| -|Kia|EV6 (without HDA II) 2022|Highway Driving Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Kia|EV6 (with HDA II) 2022|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| +|Kia|EV6 (without HDA II) 2022|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| |Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| @@ -105,7 +105,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Kia|Sportage 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| diff --git a/panda b/panda index c0632cd32b..5dc5cd8e20 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c0632cd32b78279dfbb3ce28c7a10ded8090d40f +Subproject commit 5dc5cd8e20668dfb15d35b175fccbfd3f7b63b09 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 1ab90878b8..e5fdbfd57a 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -85,7 +85,7 @@ class CarController: # *** common hyundai stuff *** # tester present - w/ no response (keeps relevant ECU disabled) - if self.frame % 100 == 0 and self.CP.openpilotLongitudinalControl: + if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl: addr, bus = 0x7d0, 0 if self.CP.flags & HyundaiFlags.CANFD_HDA2.value: addr, bus = 0x730, 5 @@ -122,7 +122,8 @@ class CarController: can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CP, CC.enabled)) if self.CP.openpilotLongitudinalControl: - can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.frame)) + if hda2: + can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.frame)) if self.frame % 2 == 0: can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CP, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override, set_speed_in_units)) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 0b5fd3bb39..8738aabd17 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -219,7 +219,7 @@ class CarInterface(CarInterfaceBase): if candidate in CANFD_CAR: ret.longitudinalTuning.kpV = [0.1] ret.longitudinalTuning.kiV = [0.0] - ret.experimentalLongitudinalAvailable = bool(ret.flags & HyundaiFlags.CANFD_HDA2) + ret.experimentalLongitudinalAvailable = candidate in (HYBRID_CAR | EV_CAR) and candidate not in CANFD_RADAR_SCC_CAR else: ret.longitudinalTuning.kpV = [0.5] ret.longitudinalTuning.kiV = [0.0] @@ -283,7 +283,7 @@ class CarInterface(CarInterfaceBase): @staticmethod def init(CP, logcan, sendcan): - if CP.openpilotLongitudinalControl: + if CP.openpilotLongitudinalControl and not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value): addr, bus = 0x7d0, 0 if CP.flags & HyundaiFlags.CANFD_HDA2.value: addr, bus = 0x730, 5 From 4eda53cef2adb949709166c2e5d204565376ce2e Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 15 Nov 2022 16:41:27 -0800 Subject: [PATCH 0301/1179] add laikad comment --- selfdrive/locationd/laikad.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2769f394c5..6936d88acc 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -187,6 +187,7 @@ class Laikad: "gpsTimeOfWeek": tow, "positionECEF": measurement_msg(value=ecef_pos.tolist(), std=pos_std.tolist(), valid=kf_valid), "velocityECEF": measurement_msg(value=ecef_vel.tolist(), std=vel_std.tolist(), valid=kf_valid), + # TODO std is incorrectly the dimension of the measurements and not 3D "positionFixECEF": measurement_msg(value=self.last_pos_fix, std=self.last_pos_residual, valid=self.last_pos_fix_t == t), "ubloxMonoTime": gnss_mono_time, "correctedMeasurements": meas_msgs From 2ad9a4f95a82bf922c86b373026c0e96f9971a80 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 16:44:03 -0800 Subject: [PATCH 0302/1179] offroad ui: support storing confirmation of a toggle (#26510) * show confirmation toggle on first toggle of experimental mode * don't store confirmation if users toggle off *after* this PR * refactor * cleaner * not true * try here --- common/params.cc | 1 + selfdrive/ui/qt/offroad/settings.cc | 20 ++++++++------------ selfdrive/ui/qt/widgets/controls.h | 10 ++++++++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/common/params.cc b/common/params.cc index e17d1f1b13..9e3e32d584 100644 --- a/common/params.cc +++ b/common/params.cc @@ -103,6 +103,7 @@ std::unordered_map keys = { {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisablePowerDown", PERSISTENT}, {"ExperimentalMode", PERSISTENT}, + {"ExperimentalModeConfirmed", PERSISTENT}, {"ExperimentalLongitudinalEnabled", PERSISTENT}, // WARNING: THIS MAY DISABLE AEB {"DisableUpdates", PERSISTENT}, {"DisengageOnAccelerator", PERSISTENT}, diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index a03cf02010..ced0744692 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -28,20 +28,18 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { // param, title, desc, icon, confirm - std::vector> toggle_defs{ + std::vector> toggle_defs{ { "OpenpilotEnabledToggle", tr("Enable openpilot"), tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."), "../assets/offroad/icon_openpilot.png", - false, }, { "ExperimentalMode", tr("Experimental Mode"), "", "../assets/offroad/icon_road.png", - false, }, { "ExperimentalLongitudinalEnabled", @@ -50,35 +48,30 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB).")) .arg(tr("openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control.")), "../assets/offroad/icon_speed_limit.png", - true, }, { "IsLdwEnabled", tr("Enable Lane Departure Warnings"), tr("Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h)."), "../assets/offroad/icon_warning.png", - false, }, { "IsMetric", tr("Use Metric System"), tr("Display speed in km/h instead of mph."), "../assets/offroad/icon_metric.png", - false, }, { "RecordFront", tr("Record and Upload Driver Camera"), tr("Upload data from the driver facing camera and help improve the driver monitoring algorithm."), "../assets/offroad/icon_monitoring.png", - false, }, { "DisengageOnAccelerator", tr("Disengage on Accelerator Pedal"), tr("When enabled, pressing the accelerator pedal will disengage openpilot."), "../assets/offroad/icon_disengage_on_accelerator.svg", - false, }, #ifdef ENABLE_MAPS { @@ -86,20 +79,18 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { tr("Show ETA in 24h Format"), tr("Use 24h format instead of am/pm"), "../assets/offroad/icon_metric.png", - false, }, { "NavSettingLeftSide", tr("Show Map on Left Side of UI"), tr("Show map on left side when in split screen view."), "../assets/offroad/icon_road.png", - false, }, #endif }; - for (auto &[param, title, desc, icon, confirm] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, confirm, this); + for (auto &[param, title, desc, icon] : toggle_defs) { + auto toggle = new ParamControl(param, title, desc, icon, false, this); bool locked = params.getBool((param + "Lock").toStdString()); toggle->setEnabled(!locked); @@ -108,6 +99,11 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { toggles[param.toStdString()] = toggle; } + // Toggles with confirmation dialogs + toggles["ExperimentalMode"]->confirm = true; + toggles["ExperimentalMode"]->store_confirm = true; + toggles["ExperimentalLongitudinalEnabled"]->confirm = true; + connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() { updateToggles(); }); diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index b67224b33d..c639b7f481 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -139,13 +139,16 @@ class ParamControl : public ToggleControl { Q_OBJECT public: - ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const bool confirm, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { + ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const bool _confirm, QWidget *parent = nullptr) : confirm(_confirm), ToggleControl(title, desc, icon, false, parent) { key = param.toStdString(); QObject::connect(this, &ParamControl::toggleFlipped, [=](bool state) { QString content("

" + title + "


" "

" + getDescription() + "

"); ConfirmationDialog dialog(content, tr("Enable"), tr("Cancel"), true, this); - if (!confirm || !state || dialog.exec()) { + + bool confirmed = store_confirm && params.getBool(key + "Confirmed"); + if (!confirm || confirmed || !state || dialog.exec()) { + if (store_confirm && state) params.putBool(key + "Confirmed", true); params.putBool(key, state); } else { toggle.togglePosition(); @@ -153,6 +156,9 @@ public: }); } + bool confirm = false; + bool store_confirm = false; + void refresh() { if (params.getBool(key) != toggle.on) { toggle.togglePosition(); From 9c96b21367af3dda9b193a821fe2e175a63f4176 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 15 Nov 2022 17:18:13 -0800 Subject: [PATCH 0303/1179] publish experimental mode state (#26512) * publish experimental mode state * remove that --- cereal | 2 +- selfdrive/controls/controlsd.py | 1 + selfdrive/ui/qt/onroad.cc | 8 +++++--- selfdrive/ui/ui.cc | 1 - selfdrive/ui/ui.h | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cereal b/cereal index afafa0a2a5..3bae09cf65 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit afafa0a2a537d775842ab2e1bf20cb9a33b34f9a +Subproject commit 3bae09cf6527674d7eda3a9956242aad94a8f3d2 diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index f69e9e7fd1..a18bec83a8 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -777,6 +777,7 @@ class Controls: controlsState.startMonoTime = int(start_time * 1e9) controlsState.forceDecel = bool(force_decel) controlsState.canErrorCounter = self.can_rcv_timeout_counter + controlsState.experimentalMode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl lat_tuning = self.CP.lateralTuning.which() if self.joystick_mode: diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 23986726c8..fcf29181e7 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -446,6 +446,8 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { painter.save(); const UIScene &scene = s->scene; + SubMaster &sm = *(s->sm); + // lanelines for (int i = 0; i < std::size(scene.lane_line_vertices); ++i) { painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp(scene.lane_line_probs[i], 0.0, 0.7))); @@ -461,8 +463,8 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { // paint path QLinearGradient bg(0, height(), 0, height() / 4); float start_hue, end_hue; - if (scene.experimental_mode) { - const auto &acceleration = (*s->sm)["modelV2"].getModelV2().getAcceleration(); + if (sm["controlsState"].getControlsState().getExperimentalMode()) { + const auto &acceleration = sm["modelV2"].getModelV2().getAcceleration(); float acceleration_future = 0; if (acceleration.getZ().size() > 16) { acceleration_future = acceleration.getX()[16]; // 2.5 seconds @@ -555,7 +557,7 @@ void AnnotatedCameraWidget::paintGL() { } else if (v_ego > 15) { wide_cam_requested = false; } - wide_cam_requested = wide_cam_requested && s->scene.experimental_mode; + wide_cam_requested = wide_cam_requested && sm["controlsState"].getControlsState().getExperimentalMode(); // TODO: also detect when ecam vision stream isn't available // for replay of old routes, never go to widecam wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 970448359e..2d4533afe1 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -174,7 +174,6 @@ void ui_update_params(UIState *s) { auto params = Params(); s->scene.is_metric = params.getBool("IsMetric"); s->scene.map_on_left = params.getBool("NavSettingLeftSide"); - s->scene.experimental_mode = params.getBool("ExperimentalMode"); } void UIState::updateStatus() { diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 38e2ffe3ce..d6f5c3e2e0 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -104,7 +104,7 @@ typedef struct UIScene { QPointF lead_vertices[2]; float light_sensor; - bool started, ignition, is_metric, map_on_left, longitudinal_control, experimental_mode; + bool started, ignition, is_metric, map_on_left, longitudinal_control; uint64_t started_frame; } UIScene; From d4fd0c3c8798317e4af87642af30ddbcd39fc4d6 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 15 Nov 2022 18:41:43 -0800 Subject: [PATCH 0304/1179] [torqued] Make torqued work on Hyundai Tucson (#26511) * changes to get offline values * set tucon values * move to params.yaml --- selfdrive/car/torque_data/override.yaml | 1 - selfdrive/car/torque_data/params.yaml | 1 + selfdrive/locationd/torqued.py | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 2ef5a1cd0f..c0b8592ee0 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -30,7 +30,6 @@ CHEVROLET SILVERADO 1500 2020: [1.9, 1.9, 0.112] CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05] VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1] VOLKSWAGEN SHARAN 2ND GEN: [2.5, 2.5, 0.1] -HYUNDAI TUCSON HYBRID 4TH GEN: [2.5, 2.5, 0.0] HYUNDAI SANTA CRUZ 1ST GEN: [2.7, 2.7, 0.0] KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.0] KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.0] diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index c2ebadfc7a..a9023b4edc 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -38,6 +38,7 @@ HYUNDAI SANTA FE PlUG-IN HYBRID 2022: [1.6953050513611045, 1.5837614296206861, 0 HYUNDAI SONATA 2019: [2.2200457811703953, 1.2967330275895228, 0.14039920986586393] HYUNDAI SONATA 2020: [2.9638737459977467, 2.1259108157250735, 0.07813665616927593] HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488717382] +HYUNDAI TUCSON HYBRID 4TH GEN: [2.035545, 2.035545, 0.110272] JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185] JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003] KIA EV6 2022: [3.2, 3.0, 0.05] diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 42dff60087..588bca1578 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -16,9 +16,9 @@ from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY HISTORY = 5 # secs POINTS_PER_BUCKET = 1500 MIN_POINTS_TOTAL = 4000 -MIN_POINTS_TOTAL_QLOG = 800 +MIN_POINTS_TOTAL_QLOG = 600 FIT_POINTS_TOTAL = 2000 -FIT_POINTS_TOTAL_QLOG = 800 +FIT_POINTS_TOTAL_QLOG = 600 MIN_VEL = 15 # m/s FRICTION_FACTOR = 1.5 # ~85% of data coverage FACTOR_SANITY = 0.3 From f3efc8998cee2750e65a99f96a6e9c787c17a19f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 15 Nov 2022 18:25:16 -0800 Subject: [PATCH 0305/1179] taco time --- RELEASES.md | 17 ++++++++--------- common/version.h | 2 +- selfdrive/ui/qt/offroad/settings.cc | 11 ++++++++--- selfdrive/ui/translations/main_ja.ts | 16 ++++++++-------- selfdrive/ui/translations/main_ko.ts | 16 ++++++++-------- selfdrive/ui/translations/main_pt-BR.ts | 16 ++++++++-------- selfdrive/ui/translations/main_zh-CHS.ts | 16 ++++++++-------- selfdrive/ui/translations/main_zh-CHT.ts | 16 ++++++++-------- 8 files changed, 57 insertions(+), 53 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index d00ece4b73..e15286c5f0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,29 +1,28 @@ -Version 0.8.17 (2022-11-21) +Version 0.9.0 (2022-11-21) ======================== * New driving model - * Internal feature space information content increased tenfold during training (to ~700 bits), which makes the model dramatically more accurate + * Internal feature space information content increased tenfold during training to ~700 bits, which makes the model dramatically more accurate * Less reliance on previous frames makes model more reactive and snappy * Trained in new reprojective simulator - * Trained in 36hrs from scratch, compared to one week for previous releases + * Trained in 36 hours from scratch, compared to one week for previous releases * Training now simulates both lateral and longitudinal behavior, which allows openpilot to slow down for turns, stop at traffic lights, and more in experimental mode -* Driver monitoring updates - * New bigger model with added end-to-end distracted trigger - * Reduced false positives during driver calibration * Experimental driving mode * End-to-end longitudinal control * Stops for traffic lights and stop signs * Slows down for turns - * openpilot defaults to chill mode, enable experimental in settings + * openpilot defaults to chill mode, enable experimental mode in settings +* Driver monitoring updates + * New bigger model with added end-to-end distracted trigger + * Reduced false positives during driver calibration * Self-tuning torque controller: learns parameters live for each car * Torque controller used on all Toyota, Lexus, Hyundai, Kia, and Genesis models * UI updates - * Multi-language in navigation * Matched speeds shown on car's dash + * Multi-language in navigation * Improved update experience * Border turns grey while overriding steering * Bookmark events while driving; view them in comma connect * New onroad visualization for experimental mode -* AGNOS 6 * tools: new and improved cabana thanks to deanlee! * Experimental longitudinal support for Volkswagen, CAN-FD Hyundai, and new GM models * Genesis GV70 2022-23 support thanks to zunichky and sunnyhaibin! diff --git a/common/version.h b/common/version.h index 0a109c1faa..74a56a7c1b 100644 --- a/common/version.h +++ b/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.8.17" +#define COMMA_VERSION "0.9.0" diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index ced0744692..cf6f589b65 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -46,7 +46,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { tr("Experimental openpilot Longitudinal Control"), QString("%1
%2") .arg(tr("WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB).")) - .arg(tr("openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control.")), + .arg(tr("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.")), "../assets/offroad/icon_speed_limit.png", }, { @@ -119,10 +119,15 @@ void TogglesPanel::updateToggles() { const QString e2e_description = tr("\ openpilot defaults to driving in chill mode.\ Experimental mode enables alpha-level features that aren't ready for chill mode. \ - Experimental features are listed below:\ + Experimental features are listed below: \
\

🌮 End-to-End Longitudinal Control 🌮

\ - 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 which speed to drive, the set speed will only act as an upper bound."); + 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. \ +
\ +

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.\ + "); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 339826796b..f7329811a6 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1006,18 +1006,18 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。 <br> <h4>🌮 エンドツーエンドアクセル制御 🌮</h4> エンジンとブレーキの制御を全てopenpilotの運転モデルに委ねます。openpilotは人間が運転するのと同じように考え、赤信号や停止サインで車を停止します。openpilotが運転速度も決めるので、あなたが設定する速度は上限速度になります。 - - - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilotは、この車に搭載されているアクセル制御(ACC)を標準で利用します。openpilotによるアクセル制御を利用したい場合は、この設定を有効にしてください。 - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). 警告: この車種でのopenpilotによるアクセル制御は実験段階であり、衝突被害軽減ブレーキ(AEB)を無効化します。 + + 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 31c910a910..56d7dfd965 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1006,18 +1006,18 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 <br> <h4>🌮 E2E 롱컨트롤 🌮</h4> 주행모델이 가속과 감속을 제어하도록 합니다. openpilot은 신호등과 정지표지판을 보고 멈추는 것을 포함하여 운전자가 생각하는것처럼 주행합니다. 주행 모델이 주행할 속도를 결정하므로 설정된 속도는 상한선으로만 작용합니다. - - - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilot은 차량의 내장 ACC로 기본 설정됩니다. 롱컨트롤으로 전환하려면 이 옵션을 활성화하세요. - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). 경고: openpilot 롱컨트롤은 실험적인 기능으로 차량의 자동긴급제동(AEB)를 비활성화합니다. + + 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 6a1d32f87a..f68400a3c7 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1010,18 +1010,18 @@ trabalho definido Experimental Mode Modo Experimental - - 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: <br> <h4>🌮 Controle Longitudinal de Ponta a Ponta 🌮</h4> Deixe o modelo de condução controlar o acelerador e os freios. Uma vez que o modelo de condução decide qual velocidade dirigir, a velocidade definida só funcionará como um limite superior. - - - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - O padrão do openpilot é o ACC integrado do carro em vez do controle longitudinal do openpilot neste carro. Habilite isto para alternar para controle longitudinal do openpilot. - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). ATENÇÃO: o controle longitudinal do openpilot é experimental para este carro e desativará a Frenagem Automática de Emergência (AEB). + + 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 64b32c80d5..174f40696b 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1004,18 +1004,18 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - openpilot 默认 <b>轻松模式</b>驾驶车辆。 试验模式启用一些轻松模式之外的 <b>试验性功能</b>。 试验性功能包括: <br> <h4>🌮 端到端(End-to-End) 纵向控制 🌮</h4> 允许智能驾驶模型控制加速和制动。 openpilot 将模仿人类驾驶行为, 包括在遇到红灯和停车让行标识时停车。 鉴于智能驾驶模型判断实际行驶车速,设定速度仅为车速上限。 - - - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilot默认使用此车辆自带ACC,而非openpilot纵向控制功能。启用此按钮将切换到openpilot纵向控制功能。 - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). 警告: 此车辆的openpilot纵向控制是试验性功能,且将禁用AEB自动刹车功能。 + + 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index c9810597b5..d1683a9562 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1006,18 +1006,18 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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 which speed to drive, the set speed will only act as an upper bound. - openpilot 默認以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。 實驗功能如下: <br> <h4>🌮端到端縱向控制🌮</h4> 讓駕駛模型控制油門和剎車。 openpilot 將像人類一樣駕駛,包括紅燈和停車標誌時停車,因為是由駕駛模型來決定車速,所以定速的設定值只會作為上限。 - - - openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control on this car. Enable this to switch to openpilot longitudinal control. - openpilot 默認使用汽車內置的主動巡航控制 (ACC),而不是使用 openpilot 縱向控制。啟用此選項可切換到 openpilot 縱向控制。 - WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). 警告:openpilot 縱向控制在這輛車上仍屬實驗性質,啟用後會喪失自動緊急煞車 (AEB) 功能。 + + 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Updater From 97a205c94df412d40db1a94bbc4bb735b5afea27 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 16 Nov 2022 11:07:50 +0800 Subject: [PATCH 0306/1179] UI: fix CameraView crash on deleting. (#26390) * fix crash on delete * TODO? * after makeCurrent --- selfdrive/ui/qt/offroad/driverview.cc | 1 + selfdrive/ui/qt/widgets/cameraview.cc | 10 ++++++++++ selfdrive/ui/qt/widgets/cameraview.h | 1 + 3 files changed, 12 insertions(+) diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index 0ff786fb91..1377bb3b23 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -35,6 +35,7 @@ void DriverViewScene::showEvent(QShowEvent* event) { } void DriverViewScene::hideEvent(QHideEvent* event) { + // TODO: stop vipc thread ? params.putBool("IsDriverViewEnabled", false); } diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index a606d6893e..347cdb1dca 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -102,6 +102,7 @@ CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool CameraWidget::~CameraWidget() { makeCurrent(); + stopVipcThread(); if (isValid()) { glDeleteVertexArrays(1, &frame_vao); glDeleteBuffers(1, &frame_vbo); @@ -171,6 +172,15 @@ void CameraWidget::showEvent(QShowEvent *event) { } } +void CameraWidget::stopVipcThread() { + if (vipc_thread) { + vipc_thread->requestInterruption(); + vipc_thread->quit(); + vipc_thread->wait(); + vipc_thread = nullptr; + } +} + void CameraWidget::updateFrameMat() { int w = width(), h = height(); diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 0698d1fb9a..7cc3847f99 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -51,6 +51,7 @@ protected: void updateCalibration(const mat3 &calib); void vipcThread(); void clearFrames(); + void stopVipcThread(); bool zoomed_view; GLuint frame_vao, frame_vbo, frame_ibo; From c6e3d566e9b23b2046f933f3dd9e189708230a56 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 15 Nov 2022 19:24:12 -0800 Subject: [PATCH 0307/1179] update experimental mode disabled description --- selfdrive/ui/qt/offroad/settings.cc | 4 ++-- selfdrive/ui/translations/main_ja.ts | 16 ++++++++-------- selfdrive/ui/translations/main_ko.ts | 16 ++++++++-------- selfdrive/ui/translations/main_pt-BR.ts | 16 ++++++++-------- selfdrive/ui/translations/main_zh-CHS.ts | 16 ++++++++-------- selfdrive/ui/translations/main_zh-CHT.ts | 16 ++++++++-------- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index cf6f589b65..997e344221 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -151,8 +151,8 @@ void TogglesPanel::updateToggles() { e2e_toggle->setEnabled(false); params.remove("ExperimentalMode"); - const QString no_long = tr("openpilot longitudinal control is not currently available for this car."); - const QString exp_long = tr("Enable experimental longitudinal control to enable this."); + const QString no_long = tr("Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control."); + const QString exp_long = tr("Enable experimental longitudinal control to allow experimental mode."); e2e_toggle->setDescription("" + (CP.getExperimentalLongitudinalAvailable() ? exp_long : no_long) + "

" + e2e_description); } diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index f7329811a6..21fdc48fef 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -970,14 +970,6 @@ location set Experimental openpilot Longitudinal Control 実験段階のopenpilotによるアクセル制御 - - openpilot longitudinal control is not currently available for this car. - openpilotによるアクセル制御は、この車では現在利用できません。 - - - Enable experimental longitudinal control to enable this. - ここ機能を使う為には、「実験段階のopenpilotによるアクセル制御」を先に有効化してください。 - Disengage on Accelerator Pedal アクセルを踏むと openpilot を中断 @@ -1018,6 +1010,14 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. + + + + Enable experimental longitudinal control to allow experimental mode. + +
Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 56d7dfd965..57c688ffe6 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -970,14 +970,6 @@ location set Experimental openpilot Longitudinal Control openpilot 롱컨트롤 (실험적) - - openpilot longitudinal control is not currently available for this car. - 현재 이 차량에는 openpilot 롱컨트롤을 사용할 수 없습니다. - - - Enable experimental longitudinal control to enable this. - openpilot 롱컨트롤을 활성화합니다. (실험적) - Disengage on Accelerator Pedal 가속페달 조작시 해제 @@ -1018,6 +1010,14 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. + + + + Enable experimental longitudinal control to allow experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index f68400a3c7..2d7195e0d2 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -974,14 +974,6 @@ trabalho definido Experimental openpilot Longitudinal Control Controle longitudinal experimental openpilot - - openpilot longitudinal control is not currently available for this car. - controle longitudinal openpilot não está disponível para este carro. - - - Enable experimental longitudinal control to enable this. - Habilite o controle longitudinal experimental para habilitar isso. - Disengage on Accelerator Pedal Desacionar Com Pedal Do Acelerador @@ -1022,6 +1014,14 @@ trabalho definido 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. + + + + Enable experimental longitudinal control to allow experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 174f40696b..fb9b6dd6f5 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -968,14 +968,6 @@ location set Experimental openpilot Longitudinal Control 试验性的openpilot纵向控制 - - openpilot longitudinal control is not currently available for this car. - 目前此车辆无法使用openpilot纵向控制功能。 - - - Enable experimental longitudinal control to enable this. - 启用试验性的纵向控制功能。 - Disengage on Accelerator Pedal 踩油门时取消控制 @@ -1016,6 +1008,14 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. + + + + Enable experimental longitudinal control to allow experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index d1683a9562..86d5482355 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -970,14 +970,6 @@ location set Experimental openpilot Longitudinal Control 使用 openpilot 縱向控制(實驗) - - openpilot longitudinal control is not currently available for this car. - openpilot 縱向控制目前不適用於這輛車。 - - - Enable experimental longitudinal control to enable this. - 打開縱向控制(實驗)以啟用此功能。 - Disengage on Accelerator Pedal 油門取消控車 @@ -1018,6 +1010,14 @@ location set 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. + + Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. + + + + Enable experimental longitudinal control to allow experimental mode. + + Updater From 3b71a9780dab0eed22dc277ce26a4d95c97f07df Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 15 Nov 2022 19:45:15 -0800 Subject: [PATCH 0308/1179] [torqued] Non-zero offline friction (#26513) add non zero friction values --- selfdrive/car/torque_data/override.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index c0b8592ee0..6ec782444c 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -30,10 +30,10 @@ CHEVROLET SILVERADO 1500 2020: [1.9, 1.9, 0.112] CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05] VOLKSWAGEN PASSAT NMS: [2.5, 2.5, 0.1] VOLKSWAGEN SHARAN 2ND GEN: [2.5, 2.5, 0.1] -HYUNDAI SANTA CRUZ 1ST GEN: [2.7, 2.7, 0.0] -KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.0] -KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.0] -GENESIS GV70 1ST GEN: [2.42, 2.42, 0.01] +HYUNDAI SANTA CRUZ 1ST GEN: [2.7, 2.7, 0.1] +KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.1] +KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.1] +GENESIS GV70 1ST GEN: [2.42, 2.42, 0.1] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From f2d97da9b46d81454ec227152e280f1261ae9883 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 15 Nov 2022 20:14:35 -0800 Subject: [PATCH 0309/1179] jenkins: use tici-needs-can to build release --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 696446c65f..c34d253585 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -59,7 +59,7 @@ pipeline { branch 'devel-staging' } steps { - phone_steps("tici", [ + phone_steps("tici-needs-can", [ ["build release3-staging & dashcam3-staging", "PUSH=1 $SOURCE_DIR/release/build_release.sh"], ]) } From b3f75b0c5b151cbcb048a31bb33c8f49b2a818b1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 20:46:42 -0800 Subject: [PATCH 0310/1179] ui: function for setting toggle confirmation settings (#26516) function for setting confirmation settings --- selfdrive/ui/qt/offroad/settings.cc | 7 +++---- selfdrive/ui/qt/widgets/controls.h | 10 +++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 997e344221..85b09dc183 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -90,7 +90,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { }; for (auto &[param, title, desc, icon] : toggle_defs) { - auto toggle = new ParamControl(param, title, desc, icon, false, this); + auto toggle = new ParamControl(param, title, desc, icon, this); bool locked = params.getBool((param + "Lock").toStdString()); toggle->setEnabled(!locked); @@ -100,9 +100,8 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { } // Toggles with confirmation dialogs - toggles["ExperimentalMode"]->confirm = true; - toggles["ExperimentalMode"]->store_confirm = true; - toggles["ExperimentalLongitudinalEnabled"]->confirm = true; + toggles["ExperimentalMode"]->setConfirmation(true, true); + toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false); connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() { updateToggles(); diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index c639b7f481..e2fd9d1b9d 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -139,7 +139,7 @@ class ParamControl : public ToggleControl { Q_OBJECT public: - ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const bool _confirm, QWidget *parent = nullptr) : confirm(_confirm), ToggleControl(title, desc, icon, false, parent) { + ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) : ToggleControl(title, desc, icon, false, parent) { key = param.toStdString(); QObject::connect(this, &ParamControl::toggleFlipped, [=](bool state) { QString content("

" + title + "


" @@ -156,8 +156,10 @@ public: }); } - bool confirm = false; - bool store_confirm = false; + void setConfirmation(bool _confirm, bool _store_confirm) { + confirm = _confirm; + store_confirm = _store_confirm; + }; void refresh() { if (params.getBool(key) != toggle.on) { @@ -172,6 +174,8 @@ public: private: std::string key; Params params; + bool confirm = false; + bool store_confirm = false; }; class ListWidget : public QWidget { From 62024176c6e0386401374873e73512ab76f4204a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 20:52:31 -0800 Subject: [PATCH 0311/1179] ui: toggle control supports active icons (#26514) * support active icons * function * fix crash if not setting icon but active icon * revert * clean up --- selfdrive/ui/qt/widgets/controls.cc | 6 +++--- selfdrive/ui/qt/widgets/controls.h | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index 619fd3cb4c..456cf748f4 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -26,10 +26,10 @@ AbstractControl::AbstractControl(const QString &title, const QString &desc, cons hlayout->setSpacing(20); // left icon + icon_label = new QLabel(); if (!icon.isEmpty()) { - QPixmap pix(icon); - QLabel *icon_label = new QLabel(); - icon_label->setPixmap(pix.scaledToWidth(80, Qt::SmoothTransformation)); + icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); + icon_label->setPixmap(icon_pixmap); icon_label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); hlayout->addWidget(icon_label); } diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index e2fd9d1b9d..0540088a78 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -54,6 +54,9 @@ public: return description->text(); } + QLabel *icon_label; + QPixmap icon_pixmap; + public slots: void showDescription() { description->setVisible(true); @@ -153,6 +156,12 @@ public: } else { toggle.togglePosition(); } + + if (state && !active_icon_pixmap.isNull()) { + icon_label->setPixmap(active_icon_pixmap); + } else if (!icon_pixmap.isNull()) { + icon_label->setPixmap(icon_pixmap); + } }); } @@ -161,6 +170,10 @@ public: store_confirm = _store_confirm; }; + void setActiveIcon(const QString &icon) { + active_icon_pixmap = QPixmap(icon).scaledToWidth(80, Qt::SmoothTransformation); + } + void refresh() { if (params.getBool(key) != toggle.on) { toggle.togglePosition(); @@ -174,6 +187,7 @@ public: private: std::string key; Params params; + QPixmap active_icon_pixmap; bool confirm = false; bool store_confirm = false; }; From 797c626984080e1ff17206b99e67a11bba87992f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 21:07:11 -0800 Subject: [PATCH 0312/1179] ui: handle two dynamic toggle icon cases (#26517) handles two cases --- selfdrive/ui/qt/widgets/controls.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 0540088a78..770b9b92dd 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -153,15 +153,10 @@ public: if (!confirm || confirmed || !state || dialog.exec()) { if (store_confirm && state) params.putBool(key + "Confirmed", true); params.putBool(key, state); + setIcon(state); } else { toggle.togglePosition(); } - - if (state && !active_icon_pixmap.isNull()) { - icon_label->setPixmap(active_icon_pixmap); - } else if (!icon_pixmap.isNull()) { - icon_label->setPixmap(icon_pixmap); - } }); } @@ -175,8 +170,10 @@ public: } void refresh() { - if (params.getBool(key) != toggle.on) { + bool state = params.getBool(key); + if (state != toggle.on) { toggle.togglePosition(); + setIcon(state); } }; @@ -185,6 +182,14 @@ public: }; private: + void setIcon(bool state) { + if (state && !active_icon_pixmap.isNull()) { + icon_label->setPixmap(active_icon_pixmap); + } else if (!icon_pixmap.isNull()) { + icon_label->setPixmap(icon_pixmap); + } + }; + std::string key; Params params; QPixmap active_icon_pixmap; From 73ec91f3bc20409e672480428f125dd6c8b9f2a1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 16 Nov 2022 13:10:05 +0800 Subject: [PATCH 0313/1179] Cabana: fix right panel layout after undocking charts (#26497) * fix stretch * set window title --- tools/cabana/mainwin.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index f0419a2fb3..7781ab3b75 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -73,6 +73,7 @@ MainWindow::MainWindow() : QMainWindow() { video_widget = new VideoWidget(this); r_layout->addWidget(video_widget, 0, Qt::AlignTop); r_layout->addWidget(charts_widget, 1); + r_layout->addStretch(0); main_layout->addWidget(right_container); setCentralWidget(central_widget); @@ -217,11 +218,12 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); - r_layout->addWidget(charts_widget, 1); + r_layout->insertWidget(2, charts_widget, 1); floating_window->deleteLater(); floating_window = nullptr; } else if (!dock && !floating_window) { floating_window = new QWidget(nullptr); + floating_window->setWindowTitle("Charts - Cabana"); floating_window->setLayout(new QVBoxLayout()); floating_window->layout()->addWidget(charts_widget); floating_window->installEventFilter(charts_widget); From 58b84fb401a804967aa0dd5ee66fafa90194fd30 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 22:18:26 -0800 Subject: [PATCH 0314/1179] ui: offroad experimental mode button (#26498) * draft * draft * before qpushbutton * icon, clean up button, clicked goes to toggles * fix icon * add imgs * img * make square * works with layouts! * fix gradient * this looks good * clean up * clean up * remove padding around couch * use scene's experimental_model, new onroad design * rename widget * def want 3 * update translations * add img * add 25px of padding! * make 300px (no change) * clean up old images * 5 px smaller * add white img * fix from merge * no style sheets * see how this looks on device * aliased vertical line (clean up) * clean up * imgs * couch * delete * bye bye * expand toggle support * clean up * fix dynamic icon * make exp icon dynamic * order * move to offroad --- .../assets/fonts/JetBrainsMono-Medium.ttf | Bin 0 -> 204140 bytes selfdrive/assets/img_couch.svg | 3 + selfdrive/assets/img_experimental.svg | 10 +++ selfdrive/assets/img_experimental_grey.svg | 4 + selfdrive/assets/img_experimental_white.svg | 4 + selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/home.cc | 19 ++++- selfdrive/ui/qt/home.h | 5 +- selfdrive/ui/qt/offroad/experimental_mode.cc | 75 ++++++++++++++++++ selfdrive/ui/qt/offroad/experimental_mode.h | 31 ++++++++ selfdrive/ui/qt/offroad/settings.cc | 23 +++++- selfdrive/ui/qt/offroad/settings.h | 5 ++ selfdrive/ui/qt/onroad.cc | 6 +- selfdrive/ui/qt/onroad.h | 1 + selfdrive/ui/qt/sidebar.h | 2 +- selfdrive/ui/qt/window.cc | 4 +- selfdrive/ui/qt/window.h | 2 +- selfdrive/ui/translations/main_ja.ts | 11 +++ selfdrive/ui/translations/main_ko.ts | 11 +++ selfdrive/ui/translations/main_pt-BR.ts | 11 +++ selfdrive/ui/translations/main_zh-CHS.ts | 11 +++ selfdrive/ui/translations/main_zh-CHT.ts | 11 +++ 22 files changed, 238 insertions(+), 13 deletions(-) create mode 100644 selfdrive/assets/fonts/JetBrainsMono-Medium.ttf create mode 100644 selfdrive/assets/img_couch.svg create mode 100644 selfdrive/assets/img_experimental.svg create mode 100644 selfdrive/assets/img_experimental_grey.svg create mode 100644 selfdrive/assets/img_experimental_white.svg create mode 100644 selfdrive/ui/qt/offroad/experimental_mode.cc create mode 100644 selfdrive/ui/qt/offroad/experimental_mode.h diff --git a/selfdrive/assets/fonts/JetBrainsMono-Medium.ttf b/selfdrive/assets/fonts/JetBrainsMono-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a6ba5529af2486ea7d2b92b7b8bd598bbee46e29 GIT binary patch literal 204140 zcmd443w+M?|Ns9wUDpm~cHV4rxehzA17>Dp=CY&nIc}(Fm*aKJsIil$?f=3N#hCDBEHrD(__ET5!B1Rfth760zAML; zPMhH0Iiw%bqfE>?u5|41$8*q#_(_w0?f=VMm+26R7or!oRX=CWsGJ30|9-pjiCiK6$O? zAZ{-DE35WJ@u88EzGnP3^`aP4FTRD1V~godu}EHGPb03x-;YULRicPrWG3WMDNs7r zO)DS5Qn?ecjQQvcS1M5(#QwU97}Scft~vO%gR$CLT?ToLCs`T)`}g1At~gPJt5#-4 zo&!P3|3e~?H&G1w-+>~;`vQ-aBK&_P$DPL@=$)QR@l-B)HtF#HAhr&eC;tn-4Y7#x z)Z;(tt#;~&`~F|yK;8t|t?rW9hKUjk{j;eX@P|C4*jo=tB9#V7wapt9e}dc_>e1E> z*=8u9GEh7{m&!zSqcF7@>WIxJ-u2Eg+o}PfNk^Si!m78p81)jDdB~a$tC+hJ! z!qWlN$eZr*l#zUl%1O_lc5wo_M$e-B$*!LAlJ*5uk8nU`p)f(Vqde#y@*A=*h3iAt zJQf}+A|b~ zwOwN{4dHjdBtY#<{^+@P9KwqM+2uKRyyqI_y$swBo^nHdin+tof2q6_M>Zrq0X_uL zZk~k_zJP3VK@`=biK44Vz$*w37Dd;uA-wvA)-*zVC$I^??`mL&n*E~a8p7AcA`Dy9 zpe<|m;q`7nX$|`n@Yx;s z8R<}uzp`#zzY2R^KZp1ikWWMCN@y@Zd9VI~XQLk1&`#G+qTUaKa)2~OJCN_+3(#&x zTa!(10;_L&O?|izXb$qg01yP|S~Q^cOafMr1CU>BE%bT!Yw9~!L6lp`@2D+NF2i4- zjLJtoLViy9!Y0P}K=&mA()z&O#=RkkFK~zHIrMzW&!ZIX=Z5n3gekrWZ~`jJa6q=9 zH1*SY(o;Ih6VEb~`mN3V+_nf4^n8NKPfBr-fb2y!Bzx4a1BH{_z&DNc$V$9UuLqR{ z_B85*^47w~*hFx}t(3=5H}qUezX?!T;R6O#SBfJgs9aQcO5Xv%4-8x4HR-Jw{RZV@ z34oNKa?@+5Q6?%s%2pq;r*X}#M!uAWot*<@T>Xh>FK)&e-lj1dv ztH#)h*PgKFHKp~$-6?FOrSTPb(t6bJt6SoYxNbUq{d?+%jXWE>(~xhH|KIWq&+Gd4 z)en2ha66?k7|(F4Cymh`>3Q|y>xYeds9f$eM!7uUdiC^NugkYyexA5HX?;6;(s=6X zdF@dnzFyw-%UVC5`gXY~4VAqO7zlD;lS@$a9iv}&gwl8%4;p|9&>W-zy4D$Z#vAlK zdS2b!=^2-3+{M^xjK4HSP@f?CMSw>@y8AW7-O6K#qvzksqlhEuekv2qCDiAs3{L}3 z-cXO7NEzlY+1)=b|x}y2^b2 zSN0NPH8xNQ^1)M}4c30cpg8w5XbCL_t=v4w*!9y0PenSMl^XXBg5u1yW)c{J>&Wl= z9)v^j3~GOxGyVon0`ec&!(bkC1E8`HupQg%&g(Yi`Y+2wWu+q&>9bvA3du+&GFhp@-5e>pA7`}f>iXK!%*hIy>=r}K!O+@ zZaB?2v!&OP`7(yrs$qW|1XpmzyjTVEW-VAIdxW>*kMIS2Az#K{;x4|A@8<{jL4JrI z=2iR%|B?T~|KPPEO0*VjMX}f_wuyg=PsLGjLHsF|^plNbkc^TJnIJRd19GOUluyY8 z@+JA2bjeTU7xEkBry`X@wNtsOml~{ws^`=)^|IQa-c|3bZ`IGfr!8|VD=dFmxwU~c zz#3wWv|6loYm7C{+R~b4ZD;LhEwE0oK4_h8eZu;Nb-nci>xZ^rTbM1Bd#pXto@vjr=i2k_UF_ZL z{q1+#huMeQC)ualXV~Z2=i8sPzhHmSzRbSL{)&BzeYbs|eZT!Thsn{v5#fk+jB-qN zyy>WkvBkv1E{gqo>`Sq)$Nn>RPwd{MwiHm^BrZcZ$!URC{eO>OPslaIrpw7_f!Sz*`SMx$vRo%O$UX9F#g)H`QZcH% z%2R#R5Vb%pRjbr`wOMUdht*GLfeN(1N_PtcTO+K|R;#-OQmvWRY-=7`U@}^u!uon$ z3xw8dflAu~cMH5?w7{3PAMFe+;B9YU_eTpvxLY9Jp6+geLU#)cwU^t+87(l&Xo2V4 zEwH+-1_(#n_Qf7V3;gJAft7VFFb*wnD*g|& zz~k-~SXu45(E`G3v;%(eezg;IxHhr2TkW*k8MRYur_?^+xlUU1Ma@F=z2>5mXo@?Q z@)szU|HM!6WBeQRnNRtI+JQ(n4cuKb0KYK`>YwXlFuu+9yt-Nc9M9PCpBX!G_{0|{ z9yl>UUpJAUt~{;>L0XwT}(YDaafPI3I6niGN4FjQ z$IFvSB0qv6{(-#`3=tvP(dmLV~CaFlto|B>6BF&?=a~&_Z5tQDuu%ITV<#mRiFkV zg!Wa-)kgJ++N1WX1L~lvQb*J=RgHM!C%T7zObbnmO-tS3C3wBmv|PWc|Jwu$dwxuF zP4hfqkD4%>nC6=nnBX%eNXw3dED*J(v)wP~HnRrhMW>451l z-r6%PhM~M2UGXaMT)$bp@UEj*@0;U1uhfHTj+(1RtNYYg)g9w<5A~FqAdafX)GSq| zMyOG0q#CZKs(EURDpB{U$JIDBUfr)M)RW>nF;pxRqr?fBp?Znu#QkET7%s!aAn~Xe zDDD%3#XYi#jFi!$RQ1GrhmkCb*;p*gz?|b`xvUrK!}_seHjtID>1+mjm_5p#VDquM zSjAptYcaz=AjXI(GDgfbDfSNA$G%`+vv1iM_A9%{{^Ta^%^UC_9?T@@GPFk zyYNyzjF04_`2Av%DiV{WLzRmoqC`}SAH{L;vnp17OhWbLQ^eEKE@r8ICO>tTw2B_0 zr^zH+s@|f^)KGNiQ^kC7w-|uEEuQINlWwV-d{4Qdt~phS{?#%VPzsklEQ# zb{{KcWo#O|S4OZYY!Q2gJ=Nt5{$M@1V%@o5 z`Roeo!6oa=F0~0>wig+L!#6#FUJe&>YVLX%#;Sp>y zZ^4G~Xf}zbum^b>o5?d-1#ge_L_0Q%cVKh4lg;KG*<(DLJ;e*zle~ac@_fv7CG2nf z9=3pYV}IvE*>XOZt-w3TtMUH%IzF1c&NlLiY!jc%-sY2dE}O^F*;t;y7V`mkcliUB z#m=(_IL(@8S!4D&o61w!T;7R2%{#NV_;~fR`qAWLk|tl1zo~)Atj?%k)p>PM{h@wW zzo^sdlDeSIs^3hhrZmCCH-ZZxq%aAyh!tMKTO^7kkt`e{LBxo7(G2fSHy1vlg=i^K zFkY?UGx!SrH@*^UrBzrlE$1)uxmZ2Dz^CyC`E>pepNZAfqkI;BjL+tC__LVR7xCx# z^L#OX5%a|o{&&8bzk+qv2ELKM%{TLR`FngTf1hvTA7J*_!}s#fumae}zr-qRKjxGp z{3zdo*<}-Em#?uV`xdLRudqJ*j&J9m@Gtno{2l%(|DLbq)%-PnoUh|2`0M-!{suqE z-{k+|>oGUI#eZaL_z3ngFJrIp;Vh7S%!1iJvHJLsHDn(#f3}k~V*g-%c#mGOEqL#L zEAwLSV}-a4@AkjPTCsnz*6c^tmYrtJ*)f*Hs#!8S&QjP3mdL(m-8g4mSS=gPW7!xU z&&qjIHiFyONN#7NxPuMnRyK||V-t8HyC0vMn8=gac;1{n$NRD8`CaSp{j22_XU1Ee7 zDN@xvs!}~6hs&X|RF=t+a+Dk)OXM(FF7Fn<$`;}pR;>QAuWTs(l1bv6OqSuYoA^bh z$d0muxG1hlUunaNHd{uCD>6_vl@_dR8_8f9AeFc-`^f$>M21SI>?9k=9Q85JylRgL7&DnOoA4P=!( zDF3B=^Ho$|0}I zi^?pkm6tp&cVk8Rz1%N9mdCI=*rn1{y!=$PQE~DU%+#6kbJa;@$i4EY+$aB`(p0Sc zr*f*c@-xL`EmpEZnUqpeHN=`AP`I=H^W@`lu6$a)D3{7*a*ljUzAfLEA7Y=fNp6!nBvjQDdRB0tE^)HF}+a8VdE+s2eT7gOV)O*HC$D6Qpys(@leO{gcKR*m=$YSRd^iCrVGqQcB)AgKIU@e$$# zG*%-spm7@23mUHx&p{JFGo+_7G}j2KZ=yz0U6V8d=M)(248)^QtSJdG5ZXc`?t``j znTSt^(weM2!dP`;#xjsp?+zMCw#n8=*ab7RfhdJKHCQz<%+?wX%>lW9?#**!gXX)T zdKZ8~Ky~lz#tH4>hVJj`hHTQ!O&@4?H~paGbM$=Ly-+%$1kg&7m=5TkzF-ERdx%E? zb_NDdK<{!hA4JK=z8`XI#!c?be;6a3`tked8 zQ+^L=1m#EV0TkKzVU3`?XKJJa`iMr6JyvSO5h%3{5GBx68c_{>StEXguGWa-&{s6# zXXqM@^0X`3R*{da)tChIHH{*_S*PJtzt=V5Y3LgoX@|b45woD{HH!S~Esee8sY zpyWe9TA>@k+o%iq@+OUm+U^~VYzf`0QRLI_Y6SVp7LBPP^gWH}4&AEZXb-H93tXV9&&`htW)dQlBIifhsr8K)(azr_X|;Zpf#OxuJgWy$1U( z#;V*K#&h&k7+<_AM7&? zsGni~X+UcW8c&Te^;4)>Lu&=>M-9mDXq+|1+NMw+4fz^&s|L&pZJ;5)!w%Mf)*2jr zm>{3Uj@E$I4%p!ukPl*)Yd~uV>~;;vA88yn#_}|1u!hpKw~xJFXUT>e|3UV-2nL%_TL7yCcr*ULv7ex zLu&`@?KITpNg7(4V6SID{)Mvw16p6;{6Ir~LG}W)W+A^cd=q|(a|HuhbI{yrKz;%L zGkmZwv@OU0Vq51<_zu^2sLw-@Hq4f>UEi~jiUEG91(GQKjI0V|w4fzq- z8qj)y`lkWelG+B)dWZLNLw-cI1GLuQecVtxknMo6p6G`#LG~uw0a`C$Z>}M`lI;Mi zfRbGZvMbpF(3%2!cn#TppoYzYl3fV0H`N)iIZ(0-;RIAqz-B{-x}kO`(Xhv$rEapJ zR8PR3f|j`$w1)i+dY>CA>lh7N03GXw z+Gm`G{T({q4b@|UhAoHQ?}ltJQNvb1sci_d0ktcjbryfX4b^FihSp8A{xG02PSemD zia)5KwGW@}hMx0~hSouRh8ud$!x~yA@tJO@9FMpmzkWu8lQ?Fa*Q4GzlVg0LM*Iu9 z%uPcm*%8oMn7`yE0s58(e_O)1%MJXAf3Bgw9pU>lw1(pQH8dCT18$l?54xd#aL7$x z=wUbH`&DjwLyx#2-#?|HJsHl#3~0XPr!~f!`xk_Xmf)g>_H+CX4b9d3nuhkf{JMtL zO}s{9tk-K1CQ`8mjnJ^UP~1b%I3gl7^j9__N<-s;pnCwVb4645<(g8%x|zsNbO|AE8h$>8(*{ABpl2 z>Jk)XA{3q}Q4T_(U8J8z{RVBMQ7DTH(x}T&*qKm&K^+=(1sV(Br|K#+9b_Pk_LJx* z68%t}grbiSWG^{eV?sO0IT}+Mbgl+fW%6;2_y#%;RN`LPLO!JtsJ|o|J%e}?bb&@t zS)K*df6zwqW$+rpROWTyb)+Xdy#dxEoCt-l5Q6ID(g@T?ZUCPmo@};9BVwSRX+%79 zuSPV3!jB0N2i>O;&7ogt1lmA;4bb;Q3ns9+oZJQTK2us44Znxx@NpvfBk zcPQBcw&AOxEkSF9(IyK1q1qt4844d$?GSzs+8*R0{2??C!?#0+X!s}4p&I@Lbb*HEA4PTt{2k~*4Sy9%b_e`> z=u!<|3tgt+)zDQM{u-401MuU}^%}ko`j&>DfKnR({yKDnhW`Mi_5l11=(`$z61r8x z--N!e;s1hC{Q;-ve5;|kg~n5Y<~kaS37ThoPitt*wxDkiYz-8?NYL8EGD|~eEtbbL zw63wt*3emtWsZi{HI@|`_BeE@$`-T%LFW?|*qxv=W(#ah&{>5A_9f`N*#esqbZ%jR9SJ(8w!n4-+X02W2&SO0 z5kY4y7PJY$%uuuoL1!(NjT+_!eOp84E*AJGL1*L^_zgj4Fc!2SLFelhv?D?1Hx_yZ zz&lyYLazbs?=AEUfOof;h4KZox3^GU0PlD)%Lf|T(_7%v1f3aM$Xcm9M;fztL0k_w?eBlY#j7E4ec*2M>KS9YQY+Vp#7zVYz^oP z)k1awwAZv$YuH36*%#2h(?T`{bQWv*K|_01%SjD;4oZFiX#Zn5rD4xQf7H+($nukh zy#W1LL;D}gX$^Z3`iqA4K$bHawiNoShW102vl_MxdQL<8BFlLVTLS$}LwhRA?;7?d z^n!-=9F~h3IxDsOp`m?=<&uWZN-ckCXkTKvtf8|~%U>GWmssIL1g-n54K%dovj%9y z9B42IL7K;)5uh=`PeLO#;&Es+XoC1Bpcajo2SpnbG*4J<8k!%h@D)P9->fkjaW6DZ zBZfd*YGfuf6|_b^1E6Ud@hp_CwL?D7K(jRhK5y-)5wMjtPb1Kd)_hQa^zdgZ)gOp% z(8=IIgnL1!Yb5fuRshsVbb`JPU~d6GvckTEfL~ZKJ`e)FWBpJg;FmVoji9;F7OJ5& zy)8_m?tw;XXpL`!JqVh6ZLkR;+CWn@G?&_(8rct8sZpe84?>}=wgnnF910r|awv46 zMwUXK)5tRDBJe!YpfB4NYb5MrgRc{^1PZ?-n;ZKX!u2Yp#1;ghyk zz^k|yZDE5S6B2E0`&1**2DUH3LB!t=MZdGbuC(TcISeHFnw@LJuTY_pEuc~(u0c&2 z83*;&2=oKHk4E}K8)#%-sGmkQgwi!2{(?5r$RuchMx28NYGg7rNF&3cXkUW%Kz8&I zLUw~T)`(xAXlp{EJ?$2ajD;TQsh>OrnjkpTU z(#Y=6T#Yyl&DV&t&_WIEqwJkE5`EO(MMHZjJJkV5^gBEJk`QO0)E+=~g~GQ8iT-DY zuMo7qvX^Sa6)60MkYqpj4I!IChifF+W1NQeYWDFO+QZr5AA}5s!aoQ}Z8A|qdr12v zjkpe-u95AbGc=OyF-s%+Kp)dcs?%&R2YH4-=Yq!(c0%WAXm4qsuc3XZ{aKCd1w}uy zFGBhrQ1l@}4uPT{*d{D(DNEu1f_d`xWw@1oEioDIna*?g?4hlri7dd#r=eO z1d2XIh=-u)Q-pXJ3Lhc_?CpTP2r&~Hp-~S&V>N0rbd*NrL+ROwQ}9y<>_f;j=yLEk zgj1m_G_o!9?_ee3+dyB^NGdz*>3A9O91439vNQA*um<4*=&KqeXO6WRQ44)dBWj@Q zGy*nrysnW{&NnnN5BjD?Qkk!UYbZbb&H?{(AP)tb#NZhOeGViBWr~5V)f^}u9-|N* z4K-=#b09Hh4ejA#;AaHwnPOmXg7$JTus5OL`!TRLp{77#Z$do<_0y;c(1sdS3ia2h z$Drs}gqj5n(9q{YVgfbv`H&d&Lqd&$25ZzvXoyA)hlXnC^C2-|8Z{3Zu2Ey4@Bu=V zKpSi5^C2;j8ud6d3PdB#IA{}%x*uxMs0wIPjd~Jl)u`D}n?{vGVQ@lCtNR#;ab6G$ z`xEjM6zxDLlqD8zLC6bGrBSGJEZT*TXP{^og3c6T(I$la6^b??=SOp=c9= z&LLvaCWJf>;-&^V214vp8yub>GU)gIbR zBfo`GI-puYsSZH?0j2T*MQug40P-?4MWd)5Ej02QDBTa_mr$|`P*e{pH;`AMWM3eE zfTn5aoGG@AM*am&*C?`0TaBXUWN7GIDK=B1$TsaX@*0%t2IM&?*%2sepAH&%1xhvo zitJ780Tf+#YUu1Lwv$F4g63!xJttQqYoK`=IuDD@*T_Gi1sX+dUZ{~rpq({}?AJx3 zs6D%Ct9!!A$aOnLSWr9xBDBKV`NuwlmvPLz8KA=${&?y=f z2%V}?-q2|p`6Ki}jXVpTu93e$AJWJZ&>0%#4}DmpLZLG?@+asc8u=TvLPKZsv5$gz z=sT3h6B;^qkFC_mC!ucWTt1er0ZD0}*3g-K?0gNK<;Omwp)>y21sX|dp9Rn1-WQ>Z zG;$8~dGL3{Qywe9O9-!lt^=ETFMJZx=!hU+yMPRBk4KYHIm}!c|d*yrM!To^3rP{sVqA+lI|lP z1(M=+X(W~FV~wP;>;~{t`7(5mM!o{wtC3`IW#E5r@200X`NQtWlkzp&B|{j}O<-`FcFY2!hVp zHx4LelB zex?E_{HYp#XF}a;YBk~*KIU^>qaMXu038gNXa((Rz(kshC0SkUuA=;6tF_w}=HI8A z%iM2Zkt;3Al~7zV!diJ(kxRsuzUR%nSy`E5Sd`7?V#O|&>&V;4ILj@`Np|rhm$hU> zvP&d6Yz|wpOD0*%-_Us+u(>3T~_xubWH71pRMwYq$J7nLB!O4ocTlun`alBkm6;^HV+%jK6_ z=3;$|T&x=QXZqgY{sG8Ehum|J44EU~%*VYXyfP*S)4MH^IkUU7`8;c&;a zWLI!fw?0MP`sv6h8{&hF_>iOxEGYM`q76Yoxh`Is;|ffqE(h1j+0cl71>l#9hoLQG zZ118C)DK~+AOxQ9xW-F2gm@>q zo=l9g!@a{$$I!%NS9sC}P8tDwlQvG;AW0*WHYn1lqzxw0=%fv1(k4k8yhtrc8@x%I zCT;K`O-zC{wEbP?5?I<{O>yyisJA4$lImRytGjr=zL;F^VqD$DiTa{7iMbjj-m#vj z)H}MWRL}bLv!Q-gl*^9#kvdR6(iqf_G#2$EjYIuN<554-1k{hT8R|#c9Q7kjNwQ`c z9jQfS^K){^or0I9IFY8%#VjzX*dOwPNdf=DAavv?OaAqvUOno6aZy--ii|KDR9`#j`N1 zk?@n3?a0`W#zU#D>97YXaNB!I&{;||l3i_+Qo^&6T^avXQaE-Ql4qicSXitz#ac*1 z0!-Vbva--oh#{y56CXxh%t#rWhlaqy?J#zQxx$f5VK|L7l5Ox~Ij#n|iNh;X99C;q zCGu>4b24j+&d+6b!L$}K5J=fk9m!A|9tMj>2MjPc>tdrDC>jQ@^;(u^nvo=|{#LX4*%zuPY92Dzmq$gz}WD=LJ4BavxcQ@G5rc+~}$>eep05&zxuN*wOi z!pNWO>gaizVSRUVmCyp`)+&3N*opBYg{)ZM3ePR-9fdj7npK>#p(PJNzwLC>)xJ@^ zZ@QXu(^b#C_4B*+j@%?yyTtklJU4kBn3v>gpI8a^BOj|oPrp;y(4Z-B8GN*#E|h$=)=MWjQjUZ1w!b zR_rckAqL=fi5{zT#;f*;Hfl4ni@P>;Cg=hagz9dO)d_ldaEdD(y}auk;=3U`9un+o zi!|MnT$zv_WW{`#+ggB0*ki4pN#xM39x!vSB<#Kl5a^8nr$C>ijogUoi+~Z+kJ1$4 zQh!QAfx9RT1qM(W3f!H9l|IWws0bmR?J|gzlkqMra77 zGeSe@nfXXoLeHc?DLs<{!|0h5D5Er;5h$lL6c|ovC@_N3P++7{t~`WB8ReqTy+*kx zG}Mps8ReqTc-T0rt^p?)uUt-CxL*f5AvlqYPRU$3cr^)g zErOJ0vJO(32aGgyfznLD%^m7;ooc)??wF>7bjO1_NXe%opAI_9hjfq<%+Ntf@G#P5 z*X1|UcxB}Ghz?Tn3LT{6kK)d3o!=}Sqy&%YASIZMv>og6n`68(@|&xJl>BiWq~!B( zXGfji6FNu}v*-WfCy>R;V#8+~pd&hZ4c$s|NQGG>Mk!?;fH#HeiemUEN zcLeTexWi|M*~v_-0g?sgY-i58|0wP~CNZaPh~e}4V7D-@h+dcHZAhTkTfCW$V0pz+ z8{#Qyt9J$C$~mvBzmXCb=*Q{TTXYr~<^*%3$>iUB3$LByQcq(d&wJZcZf1FTv~c(z z{FJdW{N=#iq6$0lIP9Lgi<9^Ux0bb+YrEshjcZl)uAUSr|LMAH;J&{LKI@aia(MgN zg*?A@9$p!*Wj23acIHo_l&Neqo5E(X`D_JS$2PN_Y#*y)r`RPfxIexvBaWx?Y<$1O z0DNb_CcXpTg5Za5>{un%i>)#Tf73otF2rAopTgg555_luOjZ^6`|~Agt=gn^sJ-~M zpp*DMg=;2nQ;2D>X_RTQX@%*u>5^HP{mqf)ICH9buz9(8t@(iYnEAB%l9%xE_loq2 z^Gfx~_L}82-)pzm0dL{$@15kG;oa4HfcGfxCEis&em)UCF+MGQCi=|u+2OO-=djO7 zpYy)V*UvY?H^#T6ZTdz z*>HQqJq-^vJmH_^-`T&v|5^Vljm(YuHd@taSEEY-BA|0X|A5&63j&r0tPR){up?k^ zz~R8iz_`HF!0f=Tfdc}E1&#~c9=Ip)P>=}f88k3xM9{>bnL*ov&IDZ!R>1+m(ZLD9 zX~E9m?!nW7X9q6`ULFz_Vh>3PX&2HpWI)KUkZ~c?L*|Ao3|SSjK4fdi?vMi^$3jkr zTnZJTt3zF(+rlP>%?vvgo)X?JydZpk_>u6RB6>$`ZJgHF6{#WvBBLV{BGV$Bk-Z}a zM~;e|99a?hROFJ#)se2qZBcPisZkYC8>3^QTSjL^caH8KT@pPedQJ5D=pE5}qkoUC zY2w=?tckrzN|Sa?x;7cmWLT4NO@3-}(ZVcAmJG{i%M{B@%R0+u%f+VVra?_(nhtKd z)hew1n5dJi8P-MCmDXzO8S7=6vIW?pZArEaTb`}AZLn>WZL+PxcGh;qZpOE0S?ta6 z-Ay_6RSvTw$YF78kBN&}5OX;;FSd8=;Mh^IJMcYNhvO#3&5WyzI~K3vv*Ih__aww5 zv`i>T7?Ut9VRpiTgyjhv6Fx~emT<8dYv$K1qS=UM6PwL!R@rQEvsKO3H{06W+&rkc zrFqxpOPa54?rOfR`6r3y#Pr0R#GZ)*6GtRYOq`imnYcJ{XX3uZs>D-?XOqSxxstXd zT}--`9G#qyJS2HV@|xt0$(K?Fr_4`TnzAZoeai1CS6YY`zAchkq_xOuk=J5ki&8@Gbbxxa-=1Mz} zcDhYmoANf3+w4jYN{>vRn7%XpMEcpbF>TA+j%hos?dA+iM(>Ql8I>7}GpaJJnVmCx zXHLwVo;fRXb>=+Z}2j)V_23S?zaaywT9CCo>ulDQ4(1L) z9R_yToo&t@oL!l{Bl~>z<&J3`CwH9PaZ$$;9Zz@sz2g;Uk~7Vj<;-&~axQnScJ6f^ zbROvx*2&T-u2V{In%HT2r&*nL_% z_vXdr&ClDPADurse{ueb{JjO1g1CYi1+xqG7e*HjD_mcAr0`_t=AGMhp3-@5=fj;( zc0S+vS{LswAziFplDe$vva!qduHIb(x=!r6w(C#b26U_H9@2e6_odyddNl7bu*asJ z=AL;yH}z7zdiN^nHKA8UuLZqU_Hy;w(QALN>R#u2r}iG)dqp4CC#6qCpFMrO`%dh; zt?%J}z58wMU((;z|6u=XceT4~)?J4N_z&njVB_8CcNg3}=I#UdV(p}&nMHGp))eh1 zI#L`_TvR-&cv|uD;_U;&296%MVBqF~hX!6Aqy_~HN*&aH(3C+-25ld-XV9rZX9xQZ zjvJgZxaZ&jgXa(4I{4J!OZS-XX?M@Kdlufa>7HHpoE_pnBz?%}AxnqsAF77-A3AI3 zu9D^@3rcpD94yT)?OHmpbWG{A(#q1srE5!fmhKyNsH}6@z_KxA)5;F zS~cnH>s5AT}UedfVOf*zS!;aAbKV%wtukB)eB z<)dpK-8Cy{R`#qJvzE@2sc%vu)1Vxsh}G z&Yd^+V@ve`Ldwj~{vmT#6FK*sXPXs*C^@+umta3r+lFI5Q2dqw7Jz@2{)f-puU48Kt_Db_t`o1#bmG!Uee&x_BKfQ8gjde}NnxZum*UVZo zf6baT8`tbvb7algSH-JwuV%eE@YM;gZhZBpwU)JA*H*6GzV`RmB3_&D+UD1;tczRM zd)@SPE7$E@clPyw*Rx(9^ZLTqH@#l{hIk|8jUjI=dSk~MXWk5XGyBb=H)p=N^39!Z z9((i3dh7Zj>({K`x&Go?DQ|UtYusB4-rD%q!MD!3qFs5eF|L)ay{^j}nr|4ep<;t; z!^w>S8?!c!+PHY*-i>G8_Io?+?ICYZdwa#(JKjF=cFm^9P0md-H|^eZ;+>FpdcHI2 zoyvDy?;LpN;%5KN*_%gfp1*nL=CkiczT5rXY45Ij_rMnOmeehSx6IwLdCQUayx(j7 z-hlU}y|?zgeeYe_8ojmi*3ny6Y~8c<()+3Jm%qQ{{oU`M-4?d3VB5HDi?<#A!1sf! z5Ar@(_`&KA&TkLep0GV{d&%}0+gEJg{9(a|`#!AMG4G?0kCuFNZKreRke!t~SMA)l z^U6Q^{$u{G=v~uyE#I|$*P&gPKaTu3>*FCGSA4wc<6R#g`M74cb$8D0^4)WHuh_kL z_rBey{u%VoynkN#BDEur?uprxwP(|wy?ajXx%QdmGv{Z+ zKAZj7qR&=;w(YZnpB>qo@p;(ir@!$1V$Byv_DAfWv48#kt@~@fO!@MuFOMBaIWY0S z_OIAiGrrn=(0*|A!NXsde|_NVnnM|f79BeOP4{n>eslP+-{Jm;M;xAZc;(^Wzg6Gn zeY@b>mERt!@~d)IO{;QM?W{WdUDxmS92s_G^^uE5`yO3$EaBL;@15UQet)LgQe9HL z@p#zr>Bn~-|NVH)iR=@VCzk#&_=ig;H~(wVzxJGpI5qRfik~8XTJiJZpQ}zso*sRA z?&+~m+rqz`DM{B8-J<(<=Pqhna*dXpV|Iv3cUw8a^?QGoH zQD^6!-Ff!Xxv+ET=LVcBIXC*;yIB2){~z7|sQlyNrTLe3T)O;c(Vu58r(7O)`S4%a ze@*yn?G^7Ui?1BM+VbkstDCP@UA=P6LjPfTJ`g*~8mx^aKJD+rS~*jEu%!^ZJC?2j zUyC#npWx#7z$d;eX{bVo_rk~gz04-0mw_g8cw*~7TVO257k~y1ZOqCFGzxq5tWR~7SO0W8VctRYwQH?xWfe0|U;JSd}w36JENyeDHm-bm&Z z7#L{wX`I+PxOK22-r*J8IzBEg-fZ?t`QWi_!&45Whz-8Md4;N7>n^w(ItDVt)1neL^TeAv-XY$3hxkr6#os7z*d5~OyLdh29WSrdJs00Md`o$al%DH%EN`yoKGZp> zUVeG?;+xlt$M+c5J-@kp+mpWu-|u|m`GWRQ+U{0QJhgwl_6QPa=sLT9U6(%Uru5I( z#Ya*+`B81ED1;w{Gb_t~U?<(%atZWZ}Zvq)ForeKT_%&2IHK5t$Sm8l98gEV^xz z4{q;!C+o^i-?M$At~YGf*j=YcR4fa1YJ|5|Iy$qc2HrxB#GA8bpooc)rm#5jXk@dUr9(6^?TGd#vrvVbJaWrIEMq#I#B%8@CUNe z+80b6QE`8U)7f_7)D8s&9j1z^;YIEH`Ueax95RltY2P}n{q=*LGTPx|0i5;6{=I=X z$)Z?$X9k8Tj2@;6luMe_Od6?5aW_oIPCt3rR|;0 z_BHQiIh|RghEZ-Cj=XJrn79Ymsr;!%`IFf~r>_t9GR1N3CAxQWh4wCT zwq{b9l{8l{vq_mvGa1KtNPnL0gYVq%E<>$EDH8(qGnu?fnU_~bubxrPwAb8+T{>IJ_)^n)A!Tu;`4|5#8^;#aP39qB7%i zGxlYMHw=n&HX76a-%S@OLSv#Ft!`((P_k2YUA+W*5Rd@OWSM^BS=xtgSN*&hCYOevz}0XaX@5jbU_7In{^@TE4D_L?EYQ)$=nMZ=2I{ayJ$v3;tNa=6Dcv{VCQB=e#%I?xvC`LC3} zR`VW@sX4+i_7{IU;ICrx4I^*E2C;?>g2fcWXKsxT7h`T4A9jcM(0cKY8FQb`KgSb~ zHGyy4bK^}`ibosNzb~WSeYu|dU<+rx_`G`YzV+hsZ;Ge+LO(y?rg-WTIzG@7PvtV^ zUL9|g>o#@@a<7H7ooMdW>7zXPP@74bdv$yy#Zy~i%))AmMYDF!wsmc3W?p8mvRj(e z$J;YUA$2rOyYxe2OZ{eb+&Tr&FkiwUlqBa;b zFwXwlbTt3B+s#LJ6|WyQv2NU?^<*Z>d1L*1W1iCSp7rmo@t*bPt?{1qXaCv&n!oDu zw~N8IjMqBI*(BU!<}LjnVawzG zQC0IfZ+$(E_o%^}V0ujMi9Ca`KEW!0HV_TWh^A557h4ox?~w}MCY;g3&qsK9WqP4$ z!?6NE`e15aIy%@-if;>2>KB39Y;IN430Kfy9Krm9sd0DeE###4-|0& z2VSqj?hMZ|@-&{6dsBPf8t-Y(TjM?LrsJt^=zKiub{$V+ijFthjh8p8}_|n7ri#;tXb_PqkMrZ)!Bm4w*_-ifz<~75J)M^`9iQ#lc!(% zH}q@ZjfEQv;D1VOXC{$ocLE-uqg^GoY~#Ck&=ykyUZNgsKLa+lYEi?FSZT=0Uhk8G2rzY z{ASOZ7y0n6Ylhe0V|ysW0F*(Z41p}hY4ekCL*89K8kO}tI*iFGojk~Bi_9L#T%i*wd{s4hR3vL078qfp z*;j8wj1psDbk~5E@4q`+x4(q4-=pi%W{7jspmwR^E?s)m=*OrY{bG2#>us}&jQxc! zGxcv>7th|C<~M~kL__Q^(6erA9Ze`7E2SYDd&frpoP~w>M>UGV-mxKX=;_?3lqALjAEWRCW2&dKIfBV{C!CpC4naKlOc{Ga<@Pp9$%B&zX>ZKAk=3 zc+Z)Tjwc)Ic+cEoJl|L==y=Z@qSMnFMaO&Q5FJl*h>kbr5cDpJkCe@^<8#nz%Lk)i z0LO*`ClXxD!FcRmY?-kKs~eTW!#J}4gJt~p*-}ajemH08(Lm@8C$a3HDaIi zus*G#Zf(do@5bGFb%<=0bEo!l|uRD{|^&&gy^g#ljZ*aFu zq$E4&_$c?8nNCl3*71$&#fR0kvzIA^+PTiZXztba^qi&983g&h6{n@JC-$_8#xb0i zNLEJsT7AfX*+yHoBkyUqVM>g*rPx!NHVJIx>&>j(>RG*FI7838aiW4=;Z?W5mpAv1 zsTsL37U65w-6T1|+O%qXl*|raS`y~8$fom=l#CgP>Eu%h1tPO% zKcAWGtP!YiRL%TYqb-fP8f`oUWxIJ@ujGxs=NaGPYyT8Zv~d%b$nD)+;V^=41DxSE z=J+T6xV6ayeQU}9XOT8Kht5txg(vU;RF>2X$`!E+0074e1$O{;x8Y_oEe^^ z%*V%*(ilPYP3*=kJsNOt@0;$A#Qo_v-H(L@PPC--9H-p*ZXA%g%V<3K-*5C9ibJtX z_d~HCpfQ|2R@Ahqg|oOAOJdW+2-*tJ0cs=vh8P!`@Fsp(v4z*UZ&-M1T8`6(0N^Oq zU)(%A>?rKpx6qLiDNVfLTZFbav&sq$ZqyLT{NgYx z8Y`_-<0#dPGt|06)S_PtMr34+%&)9$mzUSBQdFgv=H`^9*L=$#DQwri5YM~2Ze0{c zGckPKq&Rk|coznvD9$VKNE$nh^Q*9s0G!{lhOsuRBkAl4dn5f+haYxtyjNQn6I;5v(l<%Ny_HBELP)ZeLK)zGi3pe0LkfpbhAZyS1~W4;M5B!XkK2 zfzI~aErD&l`*hoVvh5!jj*b<+QC3Rc(ek zyN(X6`3G-R^96q*FC#M#V>3o*5o7e{hi~f7x5j(cShP+@c`=q7>Fd^5d6*kRVCQDW zdAKrhG;Ia^2`)4f)sUs=Sm<4}rl~s*ZxTf(;yzv`#hUSE?rAX&XWzyVcv@UM-f_bl zBlS+lL&CzbfW>KqnYSn$-L9-#c2+@B+{hkxO(`#%Qszu=o0FU{x=a7e5x%K|vePsyP@%n6&BYmn-$M)_s zbD4J2nYjrcc{5>~fI}F8?}WVN%-n2NrSLmrgz>6(W`4W7>YbV2?lyg9-k!CKwg)BJ zLvC|s{@*g8!*hbZSD&Ew9&%@U7Kocq(?|9CkJfb`tl!4Qp0#2g{0RO6KQe4z=SMU~ zG(~@~Qg4m)_QFn=)&%%BUL;IgH!{JIcqy#y?i5IFwa3^JV)T|XEj=A?tLe9UFh+Ua zO>nenYrMsBcY2BQ$5p+Cv@OfQ+c~+p?NVNzmEKYKcDyI8mK=)yo6*CYyU(%ez3b;g@A?_< zEO^e39D!Ho&!@cS&*zT5yurYMHGlN2IclsQjB*-%?g>28^S%L|jlMP4{0TWo zfP{7sM^FFXH}l>WSx$0yPFB*+dvD&%H#6US-|s7vm*pq};9yR)^QI7trCEm}gYW0P zO(|$C>+^^Da|-;8d7|s3!U)98MC(KwF*nf`%uU|L$lMfjK+|~%B+~E~O-W-?Y6>4> zpf3g;QEk)=deD4SCw4Jga(!)ya+1YFJ-QyW4SE>#V7)vd|F5n`*Mmek$^W7rp$9?t$6A4TBAgPU`pzb(G*La{&ef6+VXf3SXK9oIuli6Xo``wn0{a4*EE?39TkQ6uxPjLD}{!9-IqMNv1Uwf9EjX~1jJd&B4$(grRiGp~5RW+|9 zll#SI4(>~|8Vs3<`}aTd;swVOGx4|OIL=I5d@<8wv3N3HRPR-xs|4qoX4 zkK{3#)IsqCzIQ z9EIK@Z*ERjW?E{p#bl7|%x=-NSBNr=LaZ^lI%SgGAse`i9H8`(u#=VjkBRVN=o9Tt zwOyvUgtndSvj^vxX{xeg^xmq*4ohfgB-B*rD|giOmxZ^e*Y0lW7!K48)|FQ`V61qb zl?>405u#nf?@4c5qx?_grx7VXso!sCj+B>S{PcRf*b8w#>O0qS{>XEnx$>DveJye2 zpNy2Z#+B>uF(tfpj`BBS$}d+w5UHmvQoeS3W1p*wd9FS3+~4GSCEBizm~vV9ROCH@ zxbh^uJmGhda=c%ziBX2OhjSr2y2 z^AAo4F-s##^Zp2J{~SwmB{fq17fy3Ua)Eyk%^Rf-oU`+pparQ=5^5pz$M}H}y$(rc zAgSg<7RFMT(aelXNnnP;WYRsHmJH*zG@qENa}-~M%6QCZHl2K5&xL~C&H$5oy8|0K zH?+0*nyMOz8(n?2Ra727(V?(aWN|$=7vUJH=)K=)g z^u~JNwC4Qg`x@Vx=ktCNV_?D_lO;K&^B%P*ILlOL;)R&V&@eRcq#IB%hmGN3AUL;U z)ph85t=df*#1aYuWMoodfz6riOiSTT(^)J_1I)cHZtXWULR$u#h7?W!qo$IQ3Od#~ zW@7VUSvHRaHZSZt;_vG6`#L)Hb5F?z{PTtS*0x{6~2E8+iNwFMg5e-~YxhGVZbW_KQ3heRNdk zhnipHWKL&T)|%5?=h5dh z0JGI|TDuPI=-uYD2A)UfG^Q_2=A1?^cg)b`4gs^!oHlP>SlHY#YLVseJhP1EV?O&Z zuPvC$Gv^1IF1vTxv!}UZTTjO=9X;J0w+6bgH}$Oi9e&8KK%T9VhJphCEeW@WyiEI% zvJqGGZ)FW_vtH54q$&ja=)Ig0Z<`5rQR zBwG@44Y_!|0=My;O6F@cF(B;kHGIoEEb7gJq0nH)$*ETiP*7^!ELozRNL=OTNx6-EALh?e1>9mvRvmI&Bu6i`jB9lZRWC=GZia;_H zh?5KfAS`hSU}MW!5=8kq?psrCAW_-vDn$J1Dq|1CWs(~VaUBLy1t^63e?{cwn0Y%s zJF_`30#}mz?+;H+&C8}?yRW0e=WlDX9GIP-IUjv)8Q!{ec=@@d<^bmJL_6m11fRde z>rCLudDvrsuHg_KY%>bH)g`Pk%=(NBDackF%&o|RGUmxso zxz>-f#e#ya-rfj5F>zk~lE$mCM{0Z~w){_;U77bQ=KiSWNT4hM@+ei%hsYi5LZt8QuOb4=O}+YQjT_UnOoe? z+qDKg-q7stf*vGui~BL#qx9o4wcj60T+byK}K^kH>rX&x10P%vYLrC%_mD^ z1MT23$W>(09B%3DH71gwEPPab`1nFv*x2B)mDpjGSO4&42mS%gYHUt8GJEUHks~wn z^;fR13|cdVODKSbB=v z;Fc=vHL>`;%V~1O%TE#Xe&|>@HEcON5k7Jx+|l+%8_@f?hAY;s8$U90D~Im$^8ww1 z-Lzpa^1zoe$pZ+UbpTJXaZr4VW{QqN-I)?V1_!LJI@FCtN45@^)5clH&+ff<+s6Cu z3;g02?6#@xJtLu(=_z#|AL}9bzmi;5E}j2qmQf~zUGTmVbeZ-pwggTf&k^*4L55G% z3~gfYi7E(UL(p$gl=fkMpO_0Vw}pbXLb&LaI_>3!<#e$UtM??FD|AFIp%ByU}_{H=48zZqA40p^yd|L<|-w5~<@ z>r@Vkk_}bHxZ1?H!d|2~0BVqLcdVNpTsd4;x9+BA)1`89)8hg#oF|!V8tNLK4|g;* zcgm+vE%`h4OsY4tT`gU`9qI#kCHjhg^iJ7GCvUB+to(((E2q#l`~_dfH`zMXZq*5NEGbK;}^l@HNf5QPK z!-_a6_&RZeuIAC~T6bG}_d9In_^wma!8Z2UspYrl4&!!=73!5ch#zS0ds7zgqd1H@ ztjlDwUxCNP_%h=`NW8M#9vc;KmOrzf{F$LXPltDZy1hR{x>C^4448 z-P5ok;vIOm83iU`LqwazyFFN+-#|HZbF_v0n^VZ{q4yn4fF#D{?^X&N1jY&*C^>$T zUD1JI6rIlo=VvDdrygg;?vj6=9ALkkT7J&qrS-<^C5)LR(fbj9+{oW2>^Hv#PXeZ$ zfmlR@EDGObZ1YHLjPApKS2wGJDcQ0)_-~EsCU7)?t^%8#Qu6})#0RRE3hul1Kb9^_ zPDw~ix>zns7~9fwsDIOz-sLZ|?T(hTv=)c@ARiBE6ZgBOHl4%ox)5~Z{?(%0pxZwF zY$Be$6m&v=-oUf)yMCLk_Pf?;$@^v_$7`9;!?RI)P!~Q%4sV7v0o#+`=SPf-gZ!>Z zoTbeaLd(KYQ1zo91zjH+occ{@=&w`iTf0KLUIck32R_Vc*@`w5V^4KT+X%TKPX)1~ zW*a$F!>w2C!)B8~;V&!*=Hod`E$+|=B17bkTnq)%anUI`T~?>nU5bD`GOI%&(9}aA zWYBg%n3uLK*fLtT8jTI5j=Cg+vC&=MHPvD-8YwPlkv)B`%8F7~likJ#zBLJ2ay%ZRO6x_#^|k#g8}k_Dm^1INo0X%&-(ERN z8yM#L>SuL~oqUxzX06q!`-4w`FMtDJjm$if!OhpA?{=&|WsXcb=qr5Ki31tnu4FI- z3}D42=szw%N+w4hh)An%2?bN}M4@Ca&9J)RomHT7Ds2a+*czQUZvUFdCEc~ozs_roTl zl}Gh9DyMx*^e?Knk$zSaDUa%B@%@PEXH*W^L92)BXOIzyeiUDlBe|u6k7Tka1nhvf zB90B9{RpUvw)oxB|=lnVL7_%G@k=GjSZSJ z##&%7pAG99&93nhyJOXyu)79F9ks~~{qa+S<}B|Up95vu+`ww(`o&_a~Q(#{!k z{~L0jc0XvuX(#UgTSVuja#|Cj{4X)(*)enP4-s7$V?c76HU_J8;bO$110#Xz!Trvl zhsF4!3%rsK1C(D!36sh^CDo4VB71r&P`#K)N^;qV)qPjHqQ{`@hgy1zJSMa7M6azV zwEUQ#Sc#oiLHJs(xYI+u$n!kx<@K9X~}KP!iO zm)pp_+}Gq)vYn%aM-~QsRWn;0M;1n#%NpdTi>lkYFKO#mo+~ao*su;Tv!m;1+sHYYaUWRnb&%Dgd2ho37W=*N5C9SS-s%9#{s zZ}HdHmN!>4J0K?K=i0I|(y+M7SXl~WwVVk4ah83GkPzKI6>oU)>(;7My(1&NWexd= zlE`Z;ebCt{WRT!xXU6ySF%Nw={JJhxfckOal6z6ws z6yL`x+{>jE6{XAW3U!430C~ZCLf8w<92ap)dmhb*w?7dQB18e=IUN4!;vU+N$SGKX z3k7iuC;lD;D`eZSBXau_i3yNvc(6irBjj@lHag%(amJ?*q4R<9h4AK%F@W_){GFZt z=FZMj^65oi$N4iKn>|0^yX@mk62>P&>qURItZd`{R%B1x_h=^kM!7w$9y5X3%k60~ zd^Enj)TeWGM>t|Dz_M5O$sOsFuC(i&%J9eaX-im9Okj9MU;~XY z9<5;?lV!_j$L6^?vZ%26pXx}>$1n2*&Y%6*%=sO@MMMuuG1e54J(n=?3NYua(o~%6 znNM*5n1Lr_Wl&5!1jQEwiy{|SiK5~LA&J6ce+^00=Hl$uma#;zdDqt63xW2-T)H~2 zqpYO8=W_Lve2?Mn;=HE?6e2n1*qY^UX*!7m@+JBKo+R#nN7L!HU_VcRJoawB@LYTp zzVMLE5F$pt@YX~M-YsWky5}GHaZ{oY?h8*Gm<+X)DTX`JXuj|+mOpX+E`L=;6Py$V zA6(es*|uj_eTAo{ZhUZR%dQ3U*t%jzxzp(}C*@x~G&bCoSLAlKr6i{gZy27Sy_mO` z_q#*uw~*gfmvcD{<43qL_3!`U2ao<^F_0g8kH{VK{`}zM9*g+FS2Sd{HJr;2{=Mm^ zTTFjK7So2D!R_xt%oGdvAQo9=I!z;8=O(RP%Pzy`&}v%hvMuE?04*_x1nqSlWdds? z2ma<|l_X?a-G4CtjRxx@X#JwboY(oCG#kg0S z&55%J^=eHdAgVwr$jt@>Fa9MXfrB5WyNLOYaQGM;Ve=*Y^`HA38gN(t<~KHdh??-B zO7GVgblVulo#BlQO%?;5150mmDzM&_*qb~OymKnDpl01;q?nY9Swl0h{) ziwBT#QY7RUa-s%RNNS1zisI>UG_-SmK1vgL-$y^Xd|Nza_*h_#(^$Br!Qcj@eKHj> z21hL9%}BUf0;UCrz>^YEUBK-zOspX6&3&KvSQFL~+KjaX8iIenBj1MK z!e3nmzQ|+M$w?h_)D>g+K)w&Z{mQu`;ef9hfn4z0XWP{WJG#3&=r_-GLbfG=T@3K| z>iX~Ma$WyjU9RiDtIKsBA<9Yr6!q)+rzroMR_=wb9&{^UB=r7Qf$=Ns;a7Ex|6KRd zyWj7!^x2B z?3nfvjt!^qAQ>D2;|nX=92jL60XGG-DkwgCjjN$xqRX1;asj=vS5o!`Ohs(Ch@%s_ zu#1dTPS3V*dy}tY%(bbu;mGXlq3^OC>H`#r!*)RRt?{eBojWA#8Pw(-d@se)<}w5T zH_T0ny+E7M7g7GUyhSUIzyA$+Fs7XPF7E%EENoVye$smLEa|@Fe6u+}`9Ae8>Tf=uR0y~`>GODZHFO;s&lJfSEH+^bf!;%^z>=l`MSL!L zjHqA{l91z%2}xiNkNw-elXycyn(4wl>KmtiA{*4NBmX24cd&I7WkR&$^>f za-DXfoMv#3Y+&EVyHeTs6vJ|pd<`7X-!`A%{n z1AW$tN#NVsd&MM7uv&y<->H6|bNQP*aFA`A9^HLi&3Zn(~brni1_a%j6RQ5K!k!M8AH)P1*5d7 zAQ<)CHW=aN4e8_T$Ke01JqGavPlbX7g?5Unvbzi26j`N(D{EJI|Kkt*EPb%5N_zcNXPU zX6I7hA7$TU_scJHTppH2^bhXm$`Vj{Tn$CQc>us?Ve?w+&W+9cy1RY!A^fM%>15w* zuN$gs=Rc}k_945|i61U8=f!%aF~LGYyQc7i@~TqYKebEGr>aTs`Q)CfK;TrA0tM?$ z3;s_+7DDaOMzP|Qj^69C6Jvu*sbh59# zoy0NB>5zCY+Cdl|7a-wZpyzgqyqy+0Pc;HLm~uOrDB}R$nQ@YRPJImZE}sq zh7?G^N_qG)vPBVD;Nheg3p zW918ThcBDkS2@b6_OT0DSp7O%$3GuauV>rThv*9RfJJ{gkB334pF`* zBiYTM=duKavLA4Opjb%j6oOPj(t1fzL4Iy_W_nr*cgU(@Rf#6^ahA^_Q_U>*8wsZ{y4pb|A3*XIJb*=)q}t5FBxj59Z5zfSBD-x_LN%`7Vqve+QrASAl*ekp&#( zkcxP|G;ldS?)*ECDZ_WZ7HF?$l6B<_&#j&&4G%s{Y!@mb@~A^T#xh48bKJ;_<;KP2 z$Q87nE{hlsX97^q6nw?h&43Sv(WGU@qIrvCg$jUdYgUC@HnS7qubJd66Nc@Blk8=r z^E#kL3WRI_J{P%q)lG7A9CF%V0)VCj(i_`}lfwZ)MgKb~-pe;3c7tcS=K16L7 z;|RT^VdXX1gTTuiNOfMRHy9*ua(Mzv6Z;?h{+7&15EtQ{XOfmc24vsHWy5GLHW&mW zmE(td8wl4NpmmY@ z#qQ1=@w^be)YX>~W`)MY$Cyq1{hZmzc8fUSDezlA-jyUFw6(~JlOlzY# z)DumGvF)XH+t_c_&D+l3cwk!tZ}l6+o1vo8tHh1mY(_~5O;|8v>S+!y{u_!F01h7MjKU%u?QOp_sEa|glV zMj2JnZ}1g3uFjHp!bfX|IIU=G+nL3i3Vm&g+m-G%jZ)|_Ah&qs%ovC~rC?c}s%WOl+lv^cQQ zi}aKvG?COq)6q>Z1Fb_>V9GnSv}c+rQ|hHK1U5H#sr$PpeUrP0nQdulXliId6IR|{ zIU}z}J8~q4v{!KR5)6e&l1&t?pi3NRlrl$x2#Ie6Fo3Ro3uW{ufHjYNT*&F!X#khc zl;HNCPlpv`XSi{q28k#p+Df^IqBUP*`OzL2t$9UoKX5f|oSxoz!*K%}4zjtX(#p!x zCd1awW;t8^>BNSE0~7KMYTJ%|TdPVha95&L@JQqRvBGBtvJ<8y+5uzq5@9%?tI3ow zn`nfImWxh>1=%8XE;2$Pm9vRbeQ5th+m+#ukhO8!2e&m1g+fC&eDK#z?urU`6Uh2A zR;K=J8&0g+#^%*~$0|IB&=T5@wERWjX;<*IOSnlQHn~qFfL?(Zp^B;3?6m6uOG@_0FLn#U(l#NnNXc=Q;+NdQD;)piprx2iM z>Qau5GSR-SU;Ltrw{HOsLcm0+Sr<(miRPxEG#y0OU09%$zt<@BM!$3U6yLdg3dsfc zX?bpO-zcX)e#nKG>)8_W^4b8Ez>JHfNCzzN>7h+_7(euFC0ojNS_y16^Qpm;(b)VX z_;GJJIO>}+_U~uwkELzgx?v)`x!GTV)js*B^if2aKgT>r+pASFM95Mr=-L3fQl7`d z!Zpl+A;;++NRCF)Py}`7YmxD=o=Xzs(t==lE@GCeh7 z$3SvOix6cIqzZus(_7O3L3;8L(0#$7m0mp*LQ1)j$>FgbJI2Z@E6d9&DlEGv?pD8y zY5tvSCwA?cP;Z>ry}7x89Ve!uUf0l!zCq^Udo}SsnjZiSY%_L*vWymS-iA%PAe9LW&6#WX&BKRMZ4f6Bd`rR75GX@kkL3 zv$Yi5i8f1G@#GbW@deSKM7i`~C%K22`x@J6u)~qD*Zu6Qe8{7d;3e*82U{#A0qLbF zYsX{c!(ql~Ea0h!AP%A__@_@gO*=+p?aBFh(pT@fhxJad;M8v>)Nf$T4nZauMBVAM zkDwmmdu&uFhm=Crm9Sub@Lko#j&vy2yoWzHHrerD zG_CS~zIqcSRtB~3&MkN+^(RfL3s&R%yS^=66p64{dKt*O1qsO;COY+0=$GR)NJozK zTLPLR&k*!3S5Ohgv=~%RA#0k; zcj@J^=|)bR2tPR-pK)aP$tQVV1L!McdaPZ{?z3f4;@k;_u#kYF!^o9g5=vS{U|Ki1N;Cx>Km+pahK_?|D7R9a;S)&Yj{}{*BA@0)7&*eP-y?@uaZC&nn8i7A zi0ORd-ExSPFC1f=f_{H6d~9Li*s%qF@DD*S>wh~!Vbic!%&A|UKQ!6XcF{#`J(zv8 z=h1$W!n2&=bR+N!sE4upT-5h4u4NP?2&X4FsGGHRMKcpCx;K-R1RfC`wd>%)T}Wzn z`i+jZwhkm9eIsBwgv8z9g9iZ}%pYc-JrL;b4yc_yffFYJJ+wb)xlS;@9>F+MTm|jV zlrPLnXBMS#r%8Q-0N2p>2WTC_%Ys;RK4F3R-U4q{W-_o29@MDQk@O{uGwDd0k1iy& zc)u)Gv+G#!*!ayi4^7LaOn*VL5%)9p2ljWtMoGZbv-gr#9)pnnVN_QI~E zo~-nED!~&@f~aX|pUATg1x~c(U9h+hsXvxI(<(L;8Xx{V$B(~^0#x3;AQ#{CO2*tE%TjA!x#^}?*u~!(nnhPZ11-)LbM&R?ck&yKjrRmi;OH+?hO&3T z;_UB<#UVW`yvg-Q6mVx#`mqB$cGi#8&QI?@IumXfYY4M^mi!j}ssFA1zccuUcXzJ* z1O6t}z~9D$qnLRDc{5|&DyR@Vb7@Un`aOAR7#VR$yg+p+( zBS$ef7Zw!<*GUwMPFt3;^#aRcLTjb3wyB~11D93Sglfv04U3ljTWY3uceVGgJFvqv z)RSLSUFxpcT;}XAvGIr0f>z>zwisbahh#E27|-&d4Cw(dyqyBO{&k>8~fpOrO zweUP#(Zs0thv#9^yK=KCOEK#&3x731**t05-n*5xf+*kr^<}VgqaDC}u-ADcyM!|c zvaM&IL0}i*BLX$U89X_31_2-+bUx+`0$)?7OotE@DK=aG75zy_5SO0RONeNK9G=?+ z;a-tF|LW*WPw#a8X!-O+<@rYz-8lbbg9Cd-EsRaEbKtDAUE)R{7Tw?@z$4&Xw#o3X z!r@=Zo?rfQ`SkC9FV->nh}WR|!cL*ju{bP}Pq1@ik(2DxR4I{6ZNhkJezvF+3{&G3 z$ddwI@k8E+X3*0GddBDPj4(mm6N`6pDL3QHGwk=zupdlLstvqOVN0agGT0394qq0TTw|1xGDCeYC&B1a04_Q7B%GK^$pNs`N1 zXwNFhDu7onTrFWBuyM%I;M3fkIpD}44x6$HZe(os!1*)VW)B>g-Q3dIc^y72r%vtP zdCQJ{r%vtLam&vAr+^&Z(A{=RdrwdMElAkF`@nHi*jbHGy=bfvqQ?FKI$24sOka&P z0+FHSN3lkCupVCKbYb)B?jXGE3jaUZ%Q@n9(+XWjh;CQ1)tzuS^>@mir)S2;XF}DL71bCTyo-L&yH?vrF&_wP z#0%rF#wft4*++pjp7qY_uYY4dy>$ORdg(s)LMZmFI>t!-Bh7pj#)vn@VT?(LpCp7c zDK!ZIj_9n0G3qZS#f<}W0%5ES?b#Dr0l-+<(AwGn$AxESHjVEj{xs55Qv=6K>bC-X zaUJ?i_~J(gANFE*DM4`@zKFR5DIf-46gVWod8_V2mHKT2kLiCCBw4n`-MB*_l6Wo( zNUn`YiU44oG^zutP)*4Q6-6W!YhG~z%WD}3g*JTffWn4**tQmDdAYO2FxAn>=AYiW zzNT+0`?31R>HS;Eoz>2AG^rg#p#HCkM`8@#2Of!h7GmrP<|TzWibuAGt{rWq_FRAM zPg|W{uM_S?&ph+Y*8a+MTUmzs$FXupm7{|Aw&p($o(HQ0zK=oIp%{&R_U|NlJRt=^ zBdh?u{C(knnhY1gD9?%iaS4vAYVd01_+P{`0{CAA5^sf-&gRyhFMqkG)z^hD$L4lj zbdhCoTb(c1Ub?lQy}P+~+inCa@tnq+LDOiQy_Q=5eOg_v$LpUfMjRc6$>cPUV(6vV zk&wLtKnV`!QeZ8nBLpDI8sS0$Sb@Tsgu$jzDnvYh8`uKy;-bn7bO@sZKtT`GzyJw^ z6MsyGKl#bn3=3f-Uqe2f5fQHXeOAt+GJh$zP*bE9juFukP+&Hj#XDGCD^T5#b^bp1TUDI@{~F#t)L8Lf6^;A{ z^{b11U=0ukaBh4MTtLGI(^BEoke-^ImW@Y%g?TtWNbbGl?M$I zF@uqrJm90yVB#FSkQ0lzYc~9i`Dj!8EjcY{nF1nX9Pv1g&H${_x4rG%JPvniD*V6$ z$mvhPxX354y{nCx^-+(R3vciQ156^Bt%%cV&Acu4bK-#!!sW_cP{dKH$KgQHSGMr3a zHBA5hF4!R7@E~*I_Bd=1;SNfa(8HxGFFQI5C- zGmi0wTP;%@BENUdH?DeIeR-al=aVxN44GsoWv{FI*)4S;q!kx!n!`I{eWT!UP5GSB z#xLn@jQXJ9HJT3!=vyG{5>f&Tl0d8@hQ1mQ7-Bzi0!UJ=G-9`tC8m#0|dJ3G)gTis1ftQA z0}vo14ACGX`6SoZ8Ii#QWZZROdS+(&g`9-H>)o-VN3{w12_2v67d|_hzZ1Ss;Rc2L zEQr4N%LF|p5Nv}Xn$AO07Gc&92qK1)j*KV!a=Br|Y{u-A%t>Zgyb??ah~43Xn~1@+ zf*&&NGr}HM=h;bo9+xklo>rg50TN%I1|k9)#Q6!~J6b~i513as^6NyCh|dpb0(}vj zhx|nlQ-oQCd?28S44-0|qM;+LqzIM-*qzGB;}Lf!WoBd<%rJHNtO~JetKzV2eB~AP zbM+(t@7HY4B%F}aCnnXus;}UUXa}@eU%v?6| z?wJlWPc{dp;pFoWe0tbU_5O}N_`f*&I_PhB_GmtN^lmS3f3Gw%_;3kH{n&C1aNaqD zjg}j@Ylg`xrOaZt;Uq$!EWgE&fQ5aIdqhGLujI91OZJv&?QQhYF_0n)5%-28dCW%* z*EVVB=C+0p=li`EFD_o}_2=L6Z=Sk!t*z_oJRyVPTIXY_^T&?OtAFzKLF5me?DH`z zdGD#e_w}6wofY&2d<9${4TgQWaRrn{9xRLs=LH_}UZQgKvwAr{7uYLGFn+;EIqcR_ zw4B?oS3V25kIt;4a#)LT|17`%V*HKq=H(yd<)7x|cni@MTz^G-FP=g>cVXWCS@|;V zPbZlk_3-+o5~?Sz9QB|tlh{N1P=5~LH759mk~tiQ)hfo5xN1_6cepm`w}! zAX9}c3rv+C!37T*Iy8~u`!tp+_ALUxNw(C|%8RK(zS`!^GqdA3F;AXHsP9ODo*|P5 zBU942(?|-6 z5s$kp_XiN?-gQd;4gxQ0wzPC^OHZ5GfXK^JELp@}`g}O(jM^QQqs}_Np^`f+@)nZS z9>EgSGGDCdWIGcpG@UvXFEO1${UTo~on1nCNg$0UBReWIFECHMn=;)lfgD}ELB#NiGf8@%k&hJQL2`!Ez|+R4-xg`)6^Rz8g?N) zwQzpWtcMiJ2yl@SRj;qxxo=~4VExim{pP)vMMGm*ePw-J#o)lYGw#$m=bQVFyF0$dHD;m9m7P+vObb z6iXe^ss4=Y2BSG2t`SXW8*j0nPNV>?PtYd^P1slJkB9dy&fKVehu#0^$mZ6jO9%T- zT~)txbnu_2ub!TJZ1e_SWqnuwHE09z9y(_tOWJ~XefarlxuVFGSenBgDpm3Zfa~ye zL9WD9Mhk}Aqw3?X#^;PeGf8{U(;`Lm@ky-T)j6YAv(kO3HGyCGb0bpl$%!kml8=!Ux%X7mx##+TRs8ew^~LFfI?2 zVHb+a>&8hU^179i9W5rW8=B$3P{rhR`^4b%Gpx*Aat-pjRZgjwI6Rcs4N?$g9Dsa4 zcA==u$9*Jn_x6ttF*|N%k2^tL56l!VLE)iSDb-o4F>X!xTi}R?F9}5R`nGyXUL>D2q zaDI;YO36S%;nrqfAUr20_}bd)(HA8CK-6td529{46Yun$_&DvOB=b@n7NsyIdW^4( z;7o(lh?{Q@wj}Y%ikSlA9(+?ZuK=tYM9_-~f^G%4IuV^%z?X+@eS@Wf% zt#$4iK&vP62dtSk_OAump@UZscDMChxbTf{Hg|P3f9%e#jUzofyNCbfitK_T^BZPT zQ;jP*i+OFm8Lfi9s+jD@w)_~qt2`5~TuYMjE|9JEW$W0p& z>{6UZ6$A_8uE{d!O*c@0Ja`y#u`=K?t77E!xlX{OFd^{{$+;st9-JMQv**g3xrVt- z%&FG1A5KiDr^_m~V;`V=X$sbV238sOsu9@;;8=lX*JE_GbzX~g&KZC;6aJgInZ?#( za`wgclD*JyGm-2C z8#hn(LT3#O$xgJZhmGQdlTZ}04sl_jl9NZA1`X*Z zdK?2n_RSKK37f>AXde6Iye2lq)xIa?-E+-wiDqdJHnum<_0U-i$caN4wXa7;?McPB zuK6T9?cmLGeS3Fr>-F&Hq4hv^Ci3e@CA|W>huAtWo5nf%bpxpNbE1*HXo84>Uflq)N=0~!$GfSNKxs|&)ZII)9PBUH70p{~{gn|AJ- zF}8Nqlsm|L$fng#w)e1~g$5tv7Q~+R$I8iO??zi15m{lP7=@J~;fb{}#E}%Di?D$b z76j~$FQrOh(wisUo?2-#RdbCCvNPJ3!P`jghB0l7C|oYAw%PrmVB1hzFtmR*(y$=e z=Ys9jNVJaL>%%;8Va`_2oGl|Qbf~D%Y=Tb?JTPT`gdPZG5b`pe6-;PBlFRzU-! z<&*N;u$9{obd41x%$c;3ygo5?h=&@Dr`r2Qdh-k0>?I>5_O@dCy0N~F`Yw~H%Q89m z{FVbryA3TBFN~IZo_x|%KKg>U*|*4c<{A0A3ZaubEl%pPAZZzoi#OE1|*28Ja z+vybbXWj16p(Wm(wCu(1L!UoXc>$oYIVfb}sw^1*jbRC;T`dKNXm;Od&tO?GH%V zNg>(6XOlWgHc#qzH3vxG&;fliBRhk3OHwDbz&1L|QCBEQ6Y?vXe@*4gw98r1R2lDP zqq;S{QggNuZPok}z*oMD0$EDMn%Rgp=E7@fAh{4jijgm0ty)KkjHP<+9wQn5D!w!q|nwo&F-L3St0O8Wxkc^pMxq?Y>?1A}rXUTD5k?91vaFjT1jV2d3c^647& z^&0ig8XUDu^uoKem_MFLCrKoAqtV3Nr1Q3sL2Lr!DbK))12h9Iq^S!0KMf8YCL=#p znq0gwt}X?nfhC!_rmi@n$kkW8jg8IPqyDM~c;Ra*{?yYbisc-d%gDs&JLxW+!SKCqUI^^r@*xTPR)9$M)KUm`{F7O4Ks`l6U8FQET zyFV8g8fdRtpW)Bh*&3W_t{(NZ4|LSKgBkw3rS87P)|zp4fBi^SbM}OIW749@06GTdpI)t6cwhYF{#v9SXNY)V@tEA+W{s)#L*9Mh`}M_ z0eU|d{YebuhxQ&nzPNbYztBe^V)U^)9Ck$5TaJeHv)v(_Z5?Q1ooxdHZR(S41HW<6 z4R(sa2ag58=uB%1#Vi7lz{#dui*M0TRoZ#@nfJKEg1B&g%qIXYoCZX?apD*rQBJ) z7z@INilp8kP8rL2}E z3`q-UAAbB1?MotQoY)*4zJP530jYaHel#hbHsrsRnaLBm;LSeP$hcjT-K0LolJ={= zdoBFYJJ~<0edS+Nw^RMXR(D!*NW;O6I0XtvZxSm50jT$In?3=fh=QO%0uW=VKn@t3 z3if==F7RDCH3f{r!EjavHycG9FgQ+Va>38Vp*t+le5}}hBr$9V_&Nd|9qyLoc>}vv z{h6Xz);CWs9JTD+R8bvl?{5#fi`lJHue-_)%=gbzFqSL@FlK}$+0bg}aTcr{P89f9 zChX-z5e%5r0yL3Alpv!!avX@XH%kakiVPJnFu=z-5u}qVE4;Y`!d7qC*WoI8Xy11d zti2T-Qw<&GZ4f6<4O?(jRqgH;R;hkou{&B8diu|6pV-vfGd|wayNQn*zzg_Zora}< z{1JfM9CM(s)?6{W4^c-5a*Uj8UJ%R^m&C-6yCz)6k*o}xC|^`Kla-hadyE;?KZV)P zRwVg~V?Uhc$s80OV~{7m3aqVM@{Cd%A+H3&G$*Yp|+c%&)s$D(G!9$pCtEw0ii$%`&0Fj1w>CFTmK5*lY@MuUk0n_$x;?e+?X}*Z zdUKDjVx2WTBXfOOa}TIScc>u4B%g10@T zrbIFxLbISv2?A`Sa|)#e)kpuSXA-PEV$}OF4@yfuWzYtnjVtyN|3Yv7-j4RY>+5#6 zs6Sx~<6`i~Y15C|Uv1DJ(ZYiK^t5-QKh4nW!koe^>?9O?5;bit0c*!~%wBPw#a_Py*TwU2(O%>FHK_kzSO=bm;J3#0oALY?_;pBX zYh1q;&p*Q7Kep!e5ApU>`>@8u^KtFJ3-y1CKaXKpqyF1gPOzu>b$D$p|C#!)d}aC1 zk^WQrp6B%0qCX$4AM@^Jb|d?)vH_ApTz>j-4i|~Vw0VvE^zWGiXJGT@fq^Ys2E0{O zUVPY%W9x2PH#&+RV?EWL+dNfO_`!WTnRGY1o&7-RJZldgi`j!Wan(lKgOl=LlaB1c zcVBh!TzHY)-pfiS#{1Q~X?v0GK%LaDciDr-qx;MzZi&-XD+0WSRq2p;)Ipo6CGcw#=I*>n&7El|m0d4<9=|V=G!;jgr()cz! z_;4aPCi245ZhUCfW;_<%j6w8*p!*z~cKm&zAjEc35>jE0!)}$&@=ec)4MtE_ih@1}9{`sQvd7>4Y}%z^$r3%s*?ozk=lVWPoX^CyNE@+4+M)})HW>#D<;AY@3Rk6dJ+nNK z-_hE)ncdj!&nv1ZEv+d0bMG~k8#;Ty5M=2?e0_8RD=nmb8JXMT_vNt|3=vJTW-`h! zP-rboNiv(H43?n}1-4}nqfu)GiL^RbX4U-@Ihp5;US_s8xAbh?Kx@NYUCnMB=`QZK z-~WVjAkaP1jg}#1zqA5$y9;CTEzm7?AI@51A0FfJTUa@3?8A|3ar-bWEGxxyLg;_- zGauQ&ydT56c6VL5S>y;(q}xD`r?IXGwP~b%pgJ!TlP+c-Cf1?v!=Q-Q1Ej3c+vq5U z>o<&zMr~?>9s<4Rqax;I{2rXMY7bsNUR&v{9O>yDsqmE7j8Es}+VaXAC7yz+(#rgt z;^OSQN_Jycv!gRJtF@@Uy}iDuB`dSj+1!QGsS^_&S@}i9`I*iiIqbI5#FUgomyMtQ z%X#4K?0NKw#`xTOuV9IrWQ;M-B7rd`1ijQ{O3DRxlHr z->@ymx;GJn>-J!PZx=&5(p}hZfAA+XxHQOuckmo;khK&kFNnP!$T9$*;5JFe2Xej0il%{sYExWipeB-GScjtIs*;e_4O9n2nSES zzZ9#U32i5?zfdk&UN(*qjrJFst=?alV)np8nfi%d8_Y(0i|Mb`3fQH{T2yF9C>?wr zP(2iobNAPV4m+akF1ClWH=u{C?+Yh3Ub{btZvEP%bt{qOE_>E({`}X|x4lSx!APS+ z)R%npr9%1%AH5W@ak!nbC5etrAbGoY)$Wl9?wpu(k`l;}TLg@0DNF*+wuFSqrlbk% zt7enMyhln(GR>qVrz)l-(`W&58L!d^|2Nfyg5|}<1qH~-Sy5b3Ugq_bx*R11MFpT- z{EkFtgVRK@Vv(FW4pG3dNq3*#Qtj`*j8FCmF>h|G%_%I*%_(XN zG_`aa{S|d>>IJkEB2<;70q9j}@(qxZol--vwm3Bj&dN~8v6={6RzUXZ_mKUp`jZytUywHQn7cO^rKtA+6#5Gshxp-eicmZwoP||+Ybmi|t)<#qR$E)0e&n7DjDOFs{ z>ZT1Jk&J+HaCmSEPPMaUB*Z&Pu+W}LUFHhS9dVP_yug6Ox#xNq!txpn}tg@x*V?T>%fep`z3`|?Uk z^7`_N*ZK?11l@j#d~z3oe;8n;#tCvbJ5RV!azI6lS&uvdml-KF$!IlY;zmQJ5gUnH zfoQ0h#9(REVP@MQTVsLCg|+N(75toCdFiFC zKv+|)8R_R72p`;DZOlFGPSHzS*9( z>1JiuPa=dw7Pggb?8kB?=;)B{)A|Ic9)k5DtWSecG3+JR0lxl_M-~Uc!fBT$+$|V< zm`+de(%s-S7mlR?1LoZVuX$~=Vgo0`7TVF(c z(!lMiF(=|`#m0)*K)+aq=@wI2!-$*v z`kL|iGyjRd@E~T-cDY%em+EPy6c^>CCt2Vg&xWeY%U~lIz#S5sh^f7>Fk8XND}FEZ zLcf>JgZERYG|8}J7?fWpi>&bPr{ger&igt1DY694{F!*<8|}Ye=;2 z%rYnB_B%G?`=-K#oK9=ga1*8Tf{ePod7!X0(OJ?|bLRo&b0PIxA@viWu5=6PzM0nzI)Pyb0YiZyK^(`fQ3)P9$azHu zu?%iQF<^zjjfH>M&HuOq^{NL#Y&OKYg^hw32>Ak$H$QAputg|oaQ{ZFdr}i+mTZx6 zGO7d{9G&!@o+2kDwI%_9fiu4y&lKe2RBM80`5XBUoM6!C#~b+viWVtbIJSU3E@(~FugdeF zg(7*lYz9xdReLIK(>GKSb`i=}at41sCkQh*Ox(0RAB%Y?2O>~E zo8P0}i$Qp2%lmr9fM?ie)O+`^dGQc$>l?5g?_2pB?1nw!WLqnw9?+L3+T~dX1B5VS zQYqvh*Z}mxP!OVXauPr8CXJ=isix%FKth`X+z-jnTz3rb2-kR7y0<30WBAmLVNY$X zXP6c-xtu5#VvJLKn=Gj9*4XTSKLRRybM9ZK*Q(LS^T$ zS8x8r!1X)3wl_3v?>b)k!tJN#K7Jr~CT-ItL#GBW+LT80mky(z2eo>VsGb~Or%a9@ z@B}HMij0T5klb^7*UsxV-gkUHZPP`Ar-m-sls1!l;Nx?rZhwL5*od`v2J@vB-5j_`LG^H859mkG!cnxW$#ZY5yb)AxCXlZP0F{CMV)wKsgWA`;w zhiV$`9}R^n%I20vOvYYh~!BJs03 zB?B22O3`FD;%g&^a#9n)SR-xLo2a$fwX-I^VKt4DqUjf2D4ITbfSTtYPE71;q2`4~ z?{BCHRX5x>#@C_FFHKSzAU3pI@Jq6ZVj=KY6IeuXK}+jE#~R0QNaBynMy<~}e-w40 zB5+3Z5*h``+Pp4lbzK^3yoK{b`Rx!EI<-PNfFEQRGe||j0#eeszi14bAbCwOLh&cj z)%xeFuYTw1tJ!(%eDzlKRy=$ zeL@PNY2byoqWno-emq)^cj~k>NTopsUd`NZBmLP?qk&x_=GpJ`uW$`4Kp^APlV1fVdjY zLlp9XAT!)+yKmpL>Gs{BzLAmR8T%gCeQNgu`!e47hWvc#O*>9)zX5Lq%@3lkZ=kMz z`SLiL-^7a8_t}M5QCfvsD4eVWdT{=nk_9C37I zR5w_8?f+ieufh)tA6#f0n5xmT4LMS^;fFj z)YW658OqW+_9HowpABV_DuUiMD_)~krq^0`<;0kJ)0LBB>_=3krf{MksMq>`s5jEu z*m^PkzhW=4$6*amlc#as&EgY!jO!xpj=26U-2V}Uk|9q^Me;$hcghDf`CBH>4q%IB ztmY&MKBN}pzQ*p(gZ)+8W0Dd35UqZpW_lr%Vr=|b?Cd_ zEqn9LKm3V4d>sGJ?;*6t|Fj;CCYf&k&i4*J`)nEY8??7z%ttZi z-h^$^k5MaruYeaz#)NI~>?Awg7tmJP8zuV;nVaQmHi-i}MM+7#hK z|D*X&T!}nLs@cci*~30g?131Ba^~kT^(7G!4`(>OR_QlZvDtu-IygYE(Q^f>VvzLO z8}WuT_KmmG**9h&0rHp7Yb18&ladRu-Up>*v1+;d378P=I_w%Qs7{ceI!h-AjAcNW zqLb(WQ7A5dGx@%Fyr+)*=C#9LH6^}XX889+i+oUhNqy;e7E{Os)QzdzS3b*j$bW$N zfV_IS(9g4oX+jEKByS=CO$eh5={wlw#KjodBQCEV7eDY?Y&LH%&&&6Qx3a?_cHukU zz`K^;(fX45zWU;d>x<}&-W$cFymO^;Sprls-k;Z%#Dq|S1p+3<`pkoo_vDjLS)Mh8 zdrHx)iFRQRzCwONCT4U~8BK#IoR*&k5P>4yvNBwBb}3h&iHK04>D&s^r?tN?`6}9Q zCY10gwBZp@`0=l16&Q{79Qxa(H|I5?_3L>>2?-86|C`#!>A?PmF||m@c?N3+`CP>| zjUr59Bs(%B3%?V$7mWd5GUep3E1p{Jl%IV1$k*zc9(A1wz5RN7_iLi>THTq{_w;1* z8hyvu#`c}k03~H6Wg^YEco+5EAAJ{zaP-cRr{2j^UVHk;SL=O`eDl@c#J!q%nU^;K zb1F^x8GDO84hz*0VFW0Xuo8?oI~nO!6iTmx`2___*9!>J2Brf@o01>XqA|e#@xAWl zp(%MeS=RJaiy7W<$lJ&Y>G(#!lbR06rLmz?A?OD-Lb6|`Dl>CsYO9>$F3$J5D%&d8 zPfWRs3%sQjZ9iKdGCNC)sw#^%^>lU=yNfET$VVM~qZ@k70M`@Bq_N;|4m{FGyD4S> za=Fh7sW=2+L{*##(i>(HO`yC%8g;vwMkb zalr*09@%2pHF?p|syfA@_#1J2ghi>VI{F1jb}<@HdHMY<8xj)-xW>cPbM)mD`Z9#R zP?SCPL=Hlu;b?tCozRzq*{sLcYl;Ow%9o#>gKSA?k$Q??& zsF}4h6rO7ENttsI6UXQ!f<#d#wBEnkE23l+!Xu;Vc znifNA=Pa-V3?5Vj;G%vTkdn%dpM|-Y)!W$MAOSDxGa=|e>JMYkm+zc91$jh$5%^1k zbRYUXwfr__4se)LCAM-r0}q{qk1Hs}!#Ei0fzW#BX2% z%P{Jb?5Li=J=bFIqh~3K+bGZ7OXXA2C*dFYN0cute|qIVfh*_ZDn}7k{!_?F>JO-0 zuupj9?aP1X&u-`KdKP%guSEG7k}&8x)oqfuugu~%wXIvK20pS#*Up>=Pd2)zR`N5G zlD|S8;_2{Tdf1N_eMuI-(WZyBwtA?IR2$DJXLyJ5vOkPIWJx9Pi<`^mT%bnJmU31c097Y9g*8xQ!CQ1}QoZ{@`ms>d6QvG|mBph9$^s zHqE6brYHzp8I~-T$QML+i-vS-^_WkhYpbyN_gPUe@ILFXSQ6(_k!`3)v?~QcLR}`p zvfZ75x>~10lGgPEHg*p9n`%4i+RHtT8fUc*?x$gccdrHR8+>lQJ-K}bn+7V!0pC1e z7l>H=HPy)4I{NzqS6$J+)LJ*u%I;$I-W-cF6M5FZ{Pwfl?j@94Q``tA)ZhU?#d*1ne^l$c0 zRUY_8csx~!p^*ChYVw4EvqUc!-Durn{oIH3<5BD%l^CssPh%B<7mC#));8|BNUSls zinWF8!i^TqY3+LD9enMYc z6L=jYT=GvNyuBU#qyG0^^-lIcc=>I)>p=JbJD`TbvSs=4y`K!-6?*6){P-kVz|K6l z@(iLyeu#1ZijWT~Q(-}oQVt^H8XWQA7O)4Si&Q>n%wiH_7(O@&V5p5PMt!wb&?70= zysszFL8HNV^}9ZSc45|$K7qHvJb<-G%ycdIK8+3_j&xs0WI74x_wv^Ump?AwzI8cU zDcbtZKPjIYni!Plm-lX!Uw`LUTb0A_ga+F$-Et%TyHxvyaY7zA>F0c$=9a&P7lZ$= zOyM_;;Xi?Qj)`lKt!NCl|A6yjDJgSi_zjC&C- zmWUg;`L2HUJSo>_MSrdZVLsQ?Vb}9MC|1g_{^NrEbH=_Qc(WIr5;P@HX-O|BV zMwKncE){Ux0yy5zZOWEk(GCSqbGzhel&SBtIZ6Pwghn=pc&nc7E@`N95_dlb*&E4N z=a}7C2YLN0jdeus6ZBr2SUeb*6C%^y1;u+)Om`RH6KT3zuy_GXcMfN9fIq++k%-J0 z5mbIo+csgyOLJF@R_KPjOD=&SPxaQO;Ul+OaroQwx3z5}L*9~tts6e>^e8%=KXGE} zC%UZ&Z~`B4k7`rS1GFR`a*qIzI`vcCRuM%;jYhU8K2%tsIEJH;dxqRj#h&4TcY@uv z9ULDrHWN2Z#K+-i7s+hlO4is=UsnsS9cfH6NRdC2_98^GurQp#c$Q*R3#XVu!qJvk z*a}vU|M&h|Gqq2alRa%X#m>f?{GYo_8cU`w;iH^uhqbrC_+46j@V!Z%?`QkIRFpKK z@XBwf3Yb8eCs}L53+%LAcZB#phEq{tVy#f2p0(cq_tN z=Jv&V=X7^=#9CXL8Y(LyVXBI#8!Uylswwmzj&j+CiDnjnry6V!f^JxBAVW)=j=ls> zj%=|wwYrmd?cp;1X{UATNOOHnqw2Esc6Ilt$ZuU!KedK`-(FR3|k6+e|FYrFdK_QG>O(n*q)PeM;h}u(mdM;1N{Vd zV4yEEiGffA@Qn0~@f1u1u{smEBjlY0M7nhb?qdQO4{O)Y1cYA5B2%B>yR>i0sq!w< zOnD<2b@=-a(abDUKgHqoKG5?#NK@6|Fec+$$wuvkjT+=@JIe_2bbm(rWTtMchTrct z=Fj3jx8H}5NwQi8bgOl34Q$q|xv?fz8>_~4i-hx|1<@Ig!I0nrQa7C0if!hi#I7^> zIZPc**>*|uw(^S3UQLx@+bN&W|C(m;{;I)ued>_*ZG-KiH3lqjwtWP!u(B{Cuiw`e z-s8og)L#E_IFIiSr=Em$`$Y;sS?8r2jzxZj}kXVhD9Al9D5Ij4r9qGk!%3(}zBIHvr z25Kodmd%5~xj|Z|hK_c|;yvy2JLZuOG3MIbB+jZDY@hPdVxgCyGE?FwXQn+fN5MLf zgO(kND&1*|5{MvJ&*TuIZzo-%o3?>I&FAc1uyA+JF4er8P#WS3u!zV2?XmCxLNP52?ikx#4k-DscKN6aXUWLu$bhPbU}FFVZ4qfP zsAvjK8-Vf_%mk?!)HmcWWBAO3fZ0T8w2;YRX1MIniG#jmqv25VXF+otafp2XFX2D) z04@x`nCL7n0T22CZLuBus1A!RalQ|-g={JNNc<*L=L1A+YP2j8F3PkCn3R{66c>7J zJRiUb_$c!n+m@aN$XE$76$OA^(B}7d_yL=xOBOF$I6SmqaA5vCc^>z4vo6-v+0kwW z+v#CeIRnfLm6!2urUa3gaYV^?q6{Gjbp%7>{n#TZu;fl1n2C#3o03q~{-Gab`h|cm zcZIco@FoIv^3n|KRDjc8I?yHH9dCE*a3^@Lgo%4Sj6UO_6ZgmOK}k6QeTUlISYKOR z84WlD{F@r;YN{&AgAPs$L95_EKnL3fB&Aib(<-#kdSN9Tp-@K%>#%L>mWlDrW1BW^ zIQN|O>qbY`u35cm<%;FYXnnBO)0gP%*QfOi*5^#t$ym3U*2`G8w|Atjn_piU?kihZ zek)$wH^a8jUM(LkzZEaK5Ztl$*W^y&fw1;h-h<=d2i#kty~?{jTXO3UxGzkX({>Oo zBmL;EYVr^9+qAf1fd&5pU4-5MPasq!p8GNG8M%^($ajeUZv4e5Ju8!OO4e#W4%Z; z#wO-?pLSB1Sgkbv;PKs9O#W^Dps`N6OW}7%N56VVn-YpFMaVUUSf2v$R7>NFh!dhj zoy1CIfR#!kc})d~JYJseN!Qi%kb6Z05HT%yawhe>5BtID7xX(tY%^#SG;u`Df7+Sq z0!bnpXil~A_VKmAy4}PYCp{wnuo`?Z@q)^+3&HRIMx76Ra}yhluc_r8zOW3{h=$K@ z26UdIjk*~O45yvJG>5#9n9=bIXPJ>@Tkp{D^&5N7ZQ6D2(Rnk>t>V^=-;@q~E8e^C zo9Ew}Ehh^Z{58m)ZNlzy9_f1Em%IfqxJqg%u7VH_ea0t~_Z&lnFX=UK?^TI=GfAUC z_ui|>ci8egfZ?Ceu3O|rgJ$en;h9SrSBNd%4o$fQyNv=XNsCC%PiBu@IDAsF8B!0b zng`yZSE91@;tu66$N#n+h9m7>COmcJze~>*&#Ix0(CV{OIRb zm`^5)#EUcBl&lP1CexkQs8l9Jtzr0f1lJ@qEnM@X?LMVjTLJ}2snb>J)5SlX&q|q@%y$<{TKcgF1k9brJe402FCDd zi7&?v3tSL*1Kr|z*F&5GaPWAE^8RsU|L)bQ{rKCf(JA!MF99c|U)5>+!_Y`@>Lp9NaH!(!iW47# z?`u7?k$*kBOJPxl6`cTS_$k|%%})-9Ruv%|(CohF`0=gUE4=VR{)x-@$F*9m5o^IF z(0>)+fVh8#*r7DU*(oqc>7GLDTIsy9&u+&8dhDpfj5}?98@00Z3I3njuFEv&-Ozp=+W)&~|4CE(h_S=x58`vO|Dx&@gYi(ffLi4e;tfuq zl*fUbKq<$SZu_N7PNwTir;7bzi_aPlFk*Rj>{70`2WFLyh@skw|$$TXZb4BNti5jou3 z5c(*S0YWxJ9v}>tAvYnox4N1NoSQ`jXf5AcDE5cPS%7h4!0;}jmlU!Rq84%j8X+<$ z=`I35BloXc*FDfPuq58rGd!}mXQ1_h_INzD_YxA2F1hI@<(UtC=tH+;ZdlN>!jryX zXxU`?NAY1(S943()Kh)!oeMB8%Hensa)jT9qdP+TyV!>~KF*4A{jhB)$n5~2!+mEz z2q^x;kP3)TbHIh!Ar#1=R3lc(5e$D!1g&8Fl-P-KQc+r9dr;LARdMgg_U$7*tG1|{ z)%uExdc18}^_iyX>ZY5ncAmffW9!d%UVXJ=%ZjR2yLOqqwQ9u{$JKmI%Nz&4&M~K% z_Mw6p&I^!v?!DwU$9BYvsTLL75c9IqzuA8bdfT;#EQjIS(N+ zMM%S;GPx*_h2e$z+Sz+lV{zi&popZ0sp&&tBa>9E%Op3phu$I|AxftV|WS0%YE*$n|G}zif);IWfiR z5;8zB6^kT74H#mN@zk~0j4A~`L|7z{A21dsia>);yf)70*(E8 zx-IVAxKkN#Z^~Y>YRl@LHCy;N)H{n-?Ob;YG~0Ez)VDO(^P8@A>{wghX@A=u+O=@S zq~n^a9g{1n+wFfz3+-OKa+mXJ<^JlP^k3UrG-mIptB$*2IHM7+Iq@~B6^!+(!e08! z136GFJB>uUbqU)ZEI9}z=FUkEcff=(%3SH(?Q)OX;c3A{g4lKomau-t2VfaPuF*;3 z8Dub&Prz~=k5*R~7I0QwS6x?IQx++xDy))GFH%c|yedd|kOA#6S)Tze=rKagQG_9j z&55X<8M3h3LGrm{#iorio9muEpl?<6mpqy)n9J_ng-Ei5g3qWwNbj z&D^g1uDS7^{GRx;D_7Ey;6pS_Sm-b|#m`0DI0{BspgV_M(UZ0x>kVTgxLMd66j%T~ z4xxLkSn6$c1Fd^=e*Cvm;ZKm=sM+&eF&S3$8XuFAbj|N7oj*1Z z>7L)!dhU6c6V*48`MhCmLWHYLl5)zfNafEkavWF)y|deUME21w`gtWcSg16L~V2O zuNCz%U_lI1#0Nl#L6E%`0|7q;`|&o=XNez+-LT|zI6$PS2r(W(h3@h&k?1rhiU=6+ z0udJb28ka9pb|v+yrua0Eh3kZI_>h`|Nip!zP|R$Ke>AO8a~*3?wsCpo0qTtB>#9{ zd#sQ4f~?g+dHAc?+;}gBL!5ygKW^o8xMP5bHA^Jcv)dgToyHLHR8^K2`OV6`A(t2) zVqsdM02LhLQ&yDXYXCIb>NYUA3$vRdmK{SGg~3ZECN5UC@pwx|Pj)2Z(5*^YTMpm5 z%iA2w$quf`sgISf+O}<7LuY$axUs%)jn`j2*yJI1PmH|=aIFQdirRf>TBHmSIdwr& zGvUie<;vh+N=%qYnIRLtiQ+=yz-VqoS_AQtsYGHydyrnozlNV93jf8|@pDi8^7>79 z9T^$Sg!jkx@Y?7tZOQ~im2%8Qpq8OSKbqQovZ2H+3|U11L49SS5f+yijv=H=3g zVrgkvi>h&8(ZZT*1rYYrE7IEi$RnS5VA~C88Hl9wT(|Xs&wTg0-yOer*@C6~O6`T* zDyOq5mltbSEnTqe;)`iq3Y!aGr;yTvGqs3ax9}b}>Gbh2&X&C>3WI!U@Gb-eLmo(k z)G~N7s5`LJ?Y6b>8n9z^?Ka9I&_s`b@4>FeGu*1~KkY-K@hpj7n<9Ay!J75M@+wffjz7gOSkS#7FB;8j8C=jcBrhHx z9R<(!GcR&nFyhkB4Byr;OfL_=bTOl(swwV za4&%c9;n!5prUwqW>lQ*Y2*hkMzlF&#gSsDil*VF=QOxUlGH5tsnq~SpIy+kAU9f( z+cG%RIV3IyzO!o8Z&$4%`XuvVQ$9q**dk5^5+K>@;qkgwc)p9sU6vZTi}8^7p#KY& z#m5hi#}BPnn~(pDUI>Wc?3nfx-=H1`Co^NbDda6b8aOttJ!P#p3hxVg2Ju9Q@u-5Q zh(Deg$V56&E7fUY`+^+zbBcka#TQYGA=HOfy626z?rI&IyX4{lt9|g2CHyCjvD+s{ zMka3`b8K>qe01Z+kB)#X663+I4WNUwkB6pnY+Pis!43rj51T#eHo=#Z=+#Z^i->!A z6>!q4;ej-Paw8Zr;cE+=f#W$jrr~bTalm9g)x9nlfk6T(B0_y?8CvR&b@(*8#(TSJa^IgJw4|y;sx4^3)ih%$P3=4 ztnzQa8ia4ptMj{e4sRab*)x33;?0ZC8M?K*wWhUuC?{AP%o#$Z*tb}YvRSzra0-FB z?u*ZX%P__!qHvLe6+{4(4b+0-MlDE>0B^wMIY@f~d8!~gk`pm!^l(liWE2W)5H<64 zZ@8i&TpW%5T)bCQ{45-ehKnmI_}?mu@rKu5Pr4wSAUJmc&Uq{bFDXD73NQkytO{X8 z1d4S1#suK_P3c+a_!dA#Qb(do(|}4wKKuhC0U&c%-{hP*lYP8Vd!oE2!oQ^rMS9A4 zJJ4ecTO7qs_mG+cD-Ns&GIsD>x5pF3cXM!7C)Dtk|wK~9xr@fyNaGb$+ ziod`$jC!`cjjYt(OZj%LX~+b?R)N-9l$E$5O+`H31LGSU(1fSDUKq}lDF8<~G6l>Q zWkZAm^p0pAy;kviv}N+ePY9wW=o&T#+or5Ty&vh1YT%*VvFH<40qmz~cqlzfPxdJ# zJT$|TIyU23k<@2@YQI+F6{41kxt^3ueNW`VEC9u=GlqV5mRKc!@yC}UmI0`!( zUU-iWd={Lvz-=mfN%1RAIZzX1v%sN^6bqEVMBR)HtK!(M)CWcBo#i>f5Z}+R`@V;$zQ=bE~^tjQ&6V}va=G(*Al0*)C(Ww`?R5*rr;t&z-ieu_c z8Qd}Troaz6JO2Q^o{N>H#5L0z@iFwvDRdp7J>iH2an0yUm-)QMHo?(qRC`K&6uwg{ z;P9Vl?`+Rvg5}$QrHn^LpJx&meGGBYmL11l(`6r;$J>~P5f{x*9iI(`03z!#?X%ib zmK~$VUc=ZG)_39r_%w;jsN4hf6?ja-Wr>NnhMB@ZTN}1D5O*d_EGug*Lsl(HIuL@U zS8)0>V4`A$CEz~o35kv%-Q7UOSbeoX#-5V)`YJ-kr*}NP;TC5aOl8hnv==jahJty) zoM2Ysg3dvBm2Tz-^m7pB3;6(I`B1EoLZyxTO~@T{rl%jJYcfth^YyH!pUpV*roR(h z1MJVr5`Gtg<8n!Bh6T35NfS|@khDONwjo^+N&t-FO^DSNWqD=>V_AWW+{|2xs4Fe; zQkHhmVv+9`JUCJiMrGPW+S7ro0Kd}S9I0$;tBf?;&&@6>%EpVgR)s6uDl1}@;S%uy zJ{0RbfI*>JE4(I)SbsbYSlNJbnAW#%2 zB1tuX@`aghTMt`jZ`wZIHopDIOE0as^ir^X zuMRI?KCJkrULD)EZS2DLl)nf6X%7)!(*(Ze^Wgr9;O_!G1Rw?#38Wn(*F3lz%mEN1 zY6F%5)Fxc)1=)y}6<3F=b3&O#-XfnJk$yWs}Of9Ka*!WyMU(&1*(J zw0!x8Mn-R1zWk=q;eGSw?HiWAvx|$f@oGwZi5r^|-{PLf#rL=e<1NGZP+Jtc2lNpT z7MmK7q+|yoK9QTVMNkfY5Jw9AEF0$wh% z)s7A(A#IRiGb==nN&>~B!iS42pph7FwYSZ^zW!VPS(z6OXV>Des%ed6&g(B*H{9)U zhrjzwJ?a%a+uk4J8I_fN2oJa<&{)^E04!t3@d;NNNNjoD3ZGCpdu)Y?T?@__Ky1btPf3nI^l6vEfFm|7 z&Vshqk~`Xe{f`dq2yaZ!sOxW@v$S_IzO%N!mbX@fn=k)t`{MHM()nxeSaZjSa@9w( zcMjg%JJJ6B_w&i}xc6gg?tsK*hDSatg?9PoxT^xY6nbf!0gnbCG2?sExWn$a4usYv z&Qt_JS=>NUsvDkEWddrX$*jjC{Ms{rLO`PmDRB#hg)}T+;jJKO$i#4_T`H$fVt>?* zpm%Y?;D`yuBA2xEEP{x-4G{Rim)f77YPXQI>h;#OeWGIlgx0d+rc1g%o_*c`39S3~ zj{q=hm8XB%cF+x3x*Uh ztg%*Pp=iZIsiB}9OB9RRWhDN}>wACn;_Cj52Tm;R?|q^%IwIJx-VJjPjg9SjQ+sWA z$CbbN=Kq8)s1o5SdfybIkp^u;G20pU7UrTfFf85V(V9jKyHr#b3Fu;5tCkC}9+V*o zZ)6<@#|ZOy9u5YAKW%(ku#;|(B`SqhKA3}2NO^)9LNkwvSb=dg5qT>36O-B6b;l2@ z|A%{e`-gV^#{!%Mzb@-9{gW-2CuX(&-lZEhU3Kx;H4i`2x?|(7*YDoVpI3T4a%LPg z4<3fh{99o9Ph{Hm79pLD*5Zx1QCm`h+s;yW z!BNuQX1PDl?opgKVuz-=)2=(y{!SHTXF6SB$q*;1Op!-tNF=uEvbwK4R{J`4*Y($J zzM}Tv4{G1g-l*=cri1f?t8ThUyj^q6bbLeQ9N-(uK~tqdu+|7H)bY*m8$tD|Ao-1i zkVhnjZecvZaz*X_P>cvxR@T0;YhGU7-+$R1v0wdtB(EqO7wa>?bLQ^Y`^W$2-mv8M z$+1hP_+=UA773pJB)r=d_Z8;mP)%c!v@NRVe+Th$s0Noryl88gX(l@28S`1Wb>Y1{ zT-{&Tw{_s|!+kp9buMgpuSC4xj_mmGRqKj3G(EX;Z1ZD;c=wimq}!O9;6o(64@q7e z!GvHP5XMEG4jiTNz?IV`A=M3q6(*BB62d^aQILo27-|%pgVUCOGC?92vXY2h4M>jR zlDPxR!7!}q?eG2cgFB$lIO25nwyoOM5+CS(IJj#m@e23dN4&y){N{-qUMctl|raIbLp?$kBc& zhKe!7*#;#?X@fktc;P+8*ppd+DRjtC%)rEIwJKDgri(Jg=7D3gDr=Kp;|rk+Qmn|E zoDS?WJLJVoGR?8?d}s4R4{i9~=p&Deeh)hA={dKyu&enSiWkq@?zd51KzL}tM+5#D zNEv#2*Nr!J-T2|o4}Gxv#;dz-{9xCOAL{-PKEe4v!J7Erp&5NwbZOJ#vq>GEqLVaK zl%ubBexF=0gtA)8{0*GtWzVk-8ImkYNvYf=^i^ zeIWB;ZU*Cq4F|Qq+J$l&aI)A$P8JCC%GaauOf*WR5#T6-cnAgx!0ZBim!f*iBWj}8O-%V>H15VA;cw^lTF5(#G{-^Ii2OKz z{Kr>~K8tqdvbU5F|0(#4?UYwmdfn#{bEMne4Nc2tUAZQ;!ouhdx;5SC4grhuBCAq^ zEXfs^bzx(t9GjGx7NMy#+SzBaVV*eIzK#iD+>7}t)ckt}cp4S?aPv{I)j0W8Bybd| zZJ|Dp6BpV4kwq&)nUQhm+ZW%v;T!ADb9fYs$GMxYLhhT(js?ox?y|r!YF}kxcDoYe zZv!q=^9wa%T8l$Y*b7AVerTdBP?ouDPMm)M#2ib<|63|DS?pTnZ#%?=#=tS8oQC=IqQqv3l{ZmFI6oC z&1GGQ%iPimuTmJSDJ(DN+4xl`|Gs@;&rr|8@vPcnc@eBDj+a(Cmo-PjLu4JpFYzbM z6}l}3-PSYU-bbq3F^@Gm^}pE5z{+jRDP-s&J9+E2?G%mNs=km$i6q z&!SbWJy3R44u{(vB?WI(H+7H2p6VWJFDv?6?WI+h4?`DLe9o0sS1y9a%jaFqw>PdV z+LN%>3#8trzI6PTWuJ z{#dq({EKPA=T_Iz@j3wKldrLw7*K#wJU0&~Q8xZfCmFnGz$Hv#G=6aE3Xc57I@tSyenLr7*Ka zg?ta>ftp};$m@VymdUpe|8~q*(&vpoa!74nzh3$s$aO)x`J!Fu+!6N!O0Wp56qo{K zA>DvxVQNe81~BEwbi3%r=MB(QLangRfI;Ob3K-)a?Qi_QK`+y^H~9I7*703@7wViN z=dDQQ0h=&ZX%YI%V95POpog6VACW^E0$vqL>MKfZDk78u$3-9jMI%-wtb#G{BcQ$+ z35O}qr+WFW`!_kD;o^4Zts9==KOfPq3Ad)DwT6`j(z+_5t~%A$B$@;bbQ<_a(kv*H zZ4Np*vk%o=Pkt9SuXzhs%8BR6Qq7Z`HV4V_eF0>FSqUu4C><|$`WxTy( zYv(MqD~(InRejV_H>aoaqVe|b?)LVsF4u)ymW=OdZ_01pv?3l*3)`1W^n8EfqLI0C zmh|@F*POZJzdnjJVW|FXQ-W9mg?$3+@EGPnJX=Y;NMf+=m_MCO19w3hXnOHY<;ekO4h&x&1+C;)`@3G=%Ec9t*CpO-F6pNP_n zDO(>6S<=rD}+ z#ba#-6bI(Thx&%PJKK6=y^Zx%6@X`JLF>uz44ej@Nmz%ZVNUQC#PlR#OG;!3{ma_t z&TWs)o%=AqrAOO21jK!tikH zc!LG!2_zs{rh{%Lqd9761^iyb`yl5UY&@;RZ#AbY(5#2}LFd>VliUAo%(=`aSwKRP4!85>$II&L z%gP!Ww9nudT^KK(uYbeWBKaEKL`m4hyLOv#WxQjlEYfdC%@a0Z#1XTD3-2j~=A?^~ z@`;)|#3Klo89l$B4SD?#0Z5sykg3P+Ky(puT2VPU*T!`2a=M`C?be^R?Z;}K?c>OB zRa#nHjOEh z>s#i`X+h=2tSrAj82q(#Xi~y!3qqlSuI{FWj>v^z8;ErX+`M}AZ}c4GdYvqstLFe- zupi=AmvRt(gE^EdmSzWT6rwEzS2#(S%drqXSeK&iEz8QuLVBR2ub{)QO$(l#6m>!t zfkT@>OZUKJCvM(Rskao@4`btVNlCYEes4wZ{B=KE4;N63rvSfV`gl6x zZAp0RJ_aVup)nq~7>My;4gs*1BtO7?S!YN{HD{>hXfOr5AwD=5Cu`39$u6klv?mnz z5A{LlLy}|RC+=Yjm9Ow;Wv;3K!pK=oIM+`ZNO^TJ42uX)6D;SoE~j0!+N@+P#do7b zo@|?OAGfW*q#9Xc)Eo7MQ2f|OZU#`GHHRqn1z}ytDQv!kP8-Ap;X=X;mAG7X+ig3p zxE_`odyZ%Ajw`Z_t6Oi~vDTIA^i+7WuQ0BzzhdFx!?&x7)0UID%XmM0c(*49E}-h| z#yjy7d*QDm_ySs7yPqV4P&l*NGlrs~KrP7@`J1-lFu*~kI z)5)8;YNo31PhJz7H!nsn*!c7CdRTWh{7by0B~GtcSX3p;4{OKd&Q#bT_9VZPKPtxE z7_T$N3?E(qXB2O65W(>P2a%Hs(a6oGGenXVm)`Egh_}p}*V5YG-x{f{jo|g9{HtYN zh4>R6VZC&H4){vQ;^?^(T^1@i05;BC@|~hI;}A-OiyH?kCC4P2=IF9%k_M5dC+&HRL5f_o=Tl2U$vuB^W@6g&dS+tU zB3F)pPYK%xnz;`2raE2$cB$Z~I z=J!i-5_$ZdL>%{}5=OLN!VI5ds+V;JzMly63YU5VVKV&)QV8J;giyE&nF(SEZ-nhy z8{*$8?JkEOWn+A@7sl=RYZGq9Bc0=LJf3LBycHHp$jM&v|MI3gfEzZFmZ2|{Ds(75 zNlwNavX=|h4|Z*4h9?b6OTw}YBlgo)3HxEvDWfd){@Br@5SS0)_abeeZ)&RV_@O3# z3qR0Qr)}1D*3}^&?Ps*D0`>)feN4cf^bCp9n2fLZ-lS)chXD!aGam*g9R&MQ4*|fP zCN1d_?E^4|DGr=M1Wlz$B0QS>5g|7mFnEAz zug{1ZaoAjT$6h~o+np}=UY4Gg=}F%k;9gHgrgw(8Cg!r+TtZw+vpaV{b(HBz%bZ01 zjSSBy^LR2gvkXrL98=Dtekj~YbR=R-(38#K+Aq4YyPf-~ue9{c{h~88upbl0)-Xp= zomp?lVA9@BF)8gU+gC1IvT$f%K7ug2@?-h2mZo|HxFU422w*^FDLWa-^120cq8)UVz5Wb8b_WCsep@nO0M7XHR7 zKMEEmzI$GLi5k0fSGKsF&;;?eOsRr?!VVhu?0m}9Ys!;In~Icav_ z94Set4M+-04^me(t5IkYaPG$|u zPXe#r^|%Q$-%f7MhUcjHTFKP|CA7ck0RY+?;vyP7Wds261q3MUC!7U{k5NWUXTgYm z7SNmm%4TIhbYn#jzHoZ?&gp2VuEJrxcxXY`0{;e5E9+jAa4|rlMo8Y`kfa)uYz*dF z9FpWi**_OCo8@QgLy1C(fdAQ4Oq|uzGJ8o_FQwRC+>w%xwF7_4e5@slOY~BTfm!`A z%iHRao7Ik*g2B>!ZE_2`6H-- zhJp7%u!I7Cq8WToi-qrLv5-&B8g3xzvqEAGkIz26UrBj1bxPK+>3a_UW85&dr`-#>SEJ!nwQFR21{jjS(tUHa)d9#?2D8wy&SMUaIeGq zEJ1vDka%2j1cF?^7h%Apn>Cqaf-IO9Ad^fpbhNPu%z&+B)}SbsigoawfI8h(`)wZK z;eXG{Lwybv*?em~8PU&A{^PC5&-?Rjp4u#tuwC@INT~)+WRZ=;2SAbi2fD49tgvvP zRf%_ra-v2g5F+skA{oUW_W50WEWHqEGi!1lj%R7SVZYmEct=3G)r<7<5R?jbFafqu_Hg7k9TXgd5R%5vl_u5I|9uS-3y|F%}6A!hggKdogKf z8IcPI3MCj+6n2ulANJuEMK*Y6ifWHjciR3`l}@omitR zQLlk^6SON@o`ozV3PA?Rg!yb-Gr< zOLV#>as6Nt*Y}-F=WaBRKdC#bW$$?)MuB7E6|QAaYD9d2NTgIK+HkrHv_%alh!GGau$4*SMq0L5 zR0I;HD-k;|c@b&SathNf_7{b#3Ja^kMgDzhMLBDC(C2Q?l9I~&ykIadzp`YB$GsK` zwq3p4s-(CX#?C`yfO?nu*v? zLM>{VK~fhQwhIL)A2LRq)O%{*GOIh2YEBv(d=MFY5Ib2e)#l4cPjd@8?=kNYn2v#S z5O+5U^A8<3xhxmyorJv|b|iV~)3G0e12FI>LdSk{aN@JrA(n!yjX(a;CVB9Gb_GuZ z{@V+D%O>x-YjU}-fX;sH@3dmc{g6vJRmi6#m~IC@9ylW~VMqif;mR8&y=QWrO;8Fh zTfv{70YoJW`OPOQf+3GhocIgiQx17-7wB)fNggXV{6$Mt!0Q~$i}*4u6afKI#x{nuu75cWDZLzFFr43Kuz!G>{ytDv_=SxfSs6S2Zx z;0!dQKprpO_2y%Lcakb*9zK4Fdc(tguO0`GOy`n^?R+53itSIQFw1`NBD6b`L^kKY@B>lEQ9r}SAOZqys$i0YtVNM-0MpXaE@x1Se$^{ZbU{2{+v zyU^qFdH9F;p!Uj-f2@u2F9QvLU%v-mdJA&pP~XrYQQtrXq}S!c9t>>=5Sy-QCiUV{ zZ&q1Y9P_PUIfQ3KxRqOD(I9v=zF0dXdRv6vUVZE_?bCdlOCON-;$3&$6+c2a2%Z8w zF<%4BwcQUgi5k!-Ayy{1U9fWn;BntRN?DZx$knj~IRfGJ7q86s+M#&WS!axmVzm>R zSd2_v+EH53Bz(%q%L`O13K=#=VQWas3HL>kXk#&wZc54nl?6Y`&JXR%$P0u@g3mr1 z3`37+cb=D3ko~iQNs2`UuEQJf71S#o8b?qWxH>1TPtY~{R+JHe#lZn#(AfF zuE8)&<8#0K#Lu@~N0b9>?h9J6w^~%k-6O>&)Zvc;XiPzORDFK)n4=JArEqcF2(v?*Ss6DlaUgC0Vyyd+Li{6u2y&V}*Ebwp=4#7^{>Km?I&z z(B9MgVvn84Gp}i0(=#0Dk5Ai=a?8|C(=&?a44zRtj{nH~%zbC_%=5=fOwW)#>a=6C zTz%{c^E0Q)zhuBInSY7#?aByj#i#2Bw$+GiAx=@}a6 zY1Wcs-|(8`j5sxL+GlVEdW==k_Zk{G-M$gSF>pqX?Uc_X$0jk2SkCQdv_2`gsn5sC z3gYn7m5Le?r=^EB7&}A1*%JZZh0Jo9!I#0}rASm$lC(33#a*J{cWm)62R;OKK z^Vq5NcL)cuh&o`Wz9M=C3M7D`(`n$fT%XzJVqPC(CMZF}x=&>4b0Keo3~*W@NTISC zm{H%xT-(K5Yveq3KD&@z!rsf?$F61{U>{^3VIOCoWS?cXu`jSMv#+vmu>0A!*mu|? zI7xoQe#)L;|H*#Io&^w*axjdS@J!U-kq__x6Q3#h-BT}h8$bV-m+JS7Uc0+5{Xf0L zfw?;c$N%qe>9_1f_A>i3dyV~#{evB2ClF6%M`Di*?uV*4j~Brh5#`mq9zN4C-o<-) zKOf`^`BJ`;ujT9cMn2BB@$>lk{6c;Se=mO@znXu5e~^EKf1H1kf0p0IzrerDzskSC z@8{o=mh)v&OqIKI3m{)A)?qG+ss@bf0nWOrIIgn&(EJ8Dphq>3Syk&Gf9f z52Fo&i_wlTZ|urL`aixsdHDh^wR6PZugeSZ*QMRO#`xyaZtW>?13tpFycr+i{-?0X z4$*FZ-MAU|XvN+9PWqd^6*p1G_~Lc^jmNv?wfI`}B08W4pQ8U5o%l+$i$Bo%A$ssB zbS`ceZCz?~h`(q$`mhqWP(v>mpNeN`5V$zhZKe`v`2P<-#Lq)4*3bPO*2m^UeXtlF z6|31OJC}_iUH>H8#V%kMv-hwo*!y9Rx`BO&eH3vvpJtz9cd#$AyV%#*z3iLp+w5WX zAM6M0$Lwe97wo^-ui0-H^R^~ZcDDixPx(qc^?;{d6%W`=FRSUAJ~#i3IHL%?=rejZ zo-^*D&w%{m^Xc~*e;eOVf7bY$zBk&V&rXdZIB639fr}^o0kp^W_^o|PyvdvCPWg@T zuHTVp>*SW?SJ*#^UVzZ2{5kq7%SHMPw2A2FUws#{A^aJPTxRf_1Y4||N;z^PQg$+R z1{;2gojxVo80k_I?G=%p4J|^~^{#n#q;zdgewH$fl%!`VV=7?C8wh_Hg!2n02R%p* zY^^eiz)iR|km*vo8HM0ml39Rag#r+X46oDuPQqRUt-|LMKDpBpvuVdgUbd5l#w{`_ z8y3I}ub{|T0DUv6QtyX>j9oK5wH;@aFvfCC_`^OYh_(*kn#-s(*YXR-_y~K+I!ViCE>hWm`5_)R=>jMb+y13l&s9cpI4?m zro@`+7{;zHADrLUTMES`vQd&o&`yc0U}$NJg>3e+SQb98w&0q8M%OajHwI|it>W7< zai=|o%(+c;87XSlUd?Jnx~&u4(A|)?$(^)%9@Dgay3}+)8JB?MZbF!J=(JgU+46EFVV24EIWB`*+O)J&?joDvOwKj;DB@nI%k9Sf+D~42y8t3@N&k(d zh3kk+AON3EQFE%9YEGd*Q?wcO*;uQv9a0*BAe>76bnm@4+^%bRDOM`~!E6PX{vH-yNXj*5t*nP0Ei=~FMBn^^6NH|>b zP9sm39erF7t5)IHE>sBbAsltMBA57SZFlKBb z3S*9P#Fk^f;jXFA15cQK#w*y9*d|Q?2v;^YDLb{F;5%c_-h%dA5H#67FQx1+<6+u| z%1-bb;+{s}JN0SoYs_F|>hsFxMo705D?)qP7?+jovNU1xCo?S0!kP#Khy4x%B~Aqc zEeoq+tO!;4;frFxP5cpjpB%Fl^udb54fFxyww9G)R!8{vw78hSi!Z*Y_f32e&B4lu zGlIHIL?V!VknyEHMD8Mo3g+b3r=|VmMXeLhXc^R>pj&c&)F0RlL649P#cP$*Y(j?w zR54I=Dd75~vKjl&1XruF8Jpt(z9w5OL(MmQKd63d+TJjpOPQP1nA?Z7z0}B>HEX7~ z^KDZ*`u<0*(An@H=Jy{saNtSaM(Ye~6w!;vxyG+kzw`ZW#^U&gA5q<;TNsbUJ%@>= zz`pz)Ea?%$zKq!4BhtQ%dv20+hkro*4yp7Q`yT$`$B9fh4=T49c4$d!#Q4q-A28r( za};C#%iU|luq*DP?Wm6%S0;GHyjGkQ2Qaxe?z_(b7u_qyFYcWk57e+d76FI}%6A{; zZO@2)^m*z1=r~ZT*jw%VQ98jY?t4-Ujr@xLg2?rqn48L+&|c1u&vn_6PzD(Y0Z{A= zWU2spq7WQnQ&o7ifYVxvB236Rgwi6doXC zBUe#{%AzhcydsF?;29{;9oQ4-5M9X*`3CL7{AtmhwnuH5IKEwWMQfnX*W8zd?93ui z8*!@W##DNA=Dz$QGz?K{nBoC+^x+Ab-5&K*#>@zdFfaC;4%@TL3#P-6BF_N3sr|}+ zg4*E;I3S5NqjoKu1iUg>e>@H-fnflZcUlobg_SZV_jHLs#I!V;iYy9ZbK3;HmcVlh z;K8$iR8jCR5Fxf3CJs*RKRBViL0u~kO?_oz0_0;J4MEI{KdSeS^}>O#!UTZ4%kVct zUQrNlJ+hBZHf5Ieiej~p)md~I;Cm;us)G~HO{m4kFF!20qO~&36a9d8T5v=n>m+=u z&<`Czlr~zyDMUxx%xeYDSFBSRem4gXOz^$h8xsegQ?EJx!o*=QFNqUkKE%VFK`szZ zE#k#DOlVI{XnU-$AI+o}*2W_DlMWk_Zcrl_>jLpM!=0{DDpstO$C`#!VhXCmfq%0h zT_*TAy`GfMCs)cB@{u6uPxGdEDXU}Znq^|mQ~^3#vF6m>c5q^1;$X^#qoos*P1$%7 zmuT-{ymJ3T0;3ZO?v$t;3os*hAri*g6r?-1A%g%FzOrsaMgi;TNC3fzivg;F1Q4vS zz!M+<5@6VsG%5^85CIyC+?(dH;G|XcvDh#c6=Ok)78K3EFl0&t%F2DZvG_3-dKq9k zkc5v|J7hH>1lM5$9zoDVekZ8WS>y%soALr3IH+Lr05w47K;o1mAak-^oJn_r(!yUK zxh%0c;G>Lh2#eW9Kwdh@BgY@5pP&R0qE(S==)gh#wB96*lv<>-ThKFen;dN>nFfJ- zKu8)V`3>%%3p_(pnu`qj5ZVj3ofQL6g&uA)TqICLT;k{@u zeWFP;39S1HHH)4P;{%$fF}76D;RX_8%wr?C9p-mpiUMMZHh{BoY_!oaw&@9c>0~@< z5olbZ!6uv@qDi3PJUS84Zi0^JRdq3E>D!nxXF>O=;Y7j`3V{?GPH&s$Em{XACYv|f z=TD!_8smHohP_AWOwir{=sth=@YH5~tb7C7GT@ks)&!;LaKy5p9S~z`<@jgxy>YXE zBP1Bp8sp(p?+0(9c#;?! z&Ke#6Kq#3Idd1#V#4Jjz0B7mU2bCw84uTfmPzO__0mJ4O z0HMmR;A;R3D$tEHO<3&sB?q)Q2YC8n`~c4scKF2kpiz@Xdo)pGogiE}rJn|!ODYj4 z{6MDpoHjo71%8_dEE0IfiFVHJ3q_9~1{qUZ1W9{m`x-=&=$cNu^<9k#=(IbzcTT&n ziQMY6TWo6pLDJY{8)vZp5;Rt9KN<(tYNuGM)A)C(mxozrNDashxV!s)dQYi-I2kjz*?Ezm!3vV>`9scE7K+X)rb(v@Bv&&Z~a$XO@} zvHyT=;sW^Qw!5rOFo$&Dq@~HKW0F&MxEqtqFv1{desH_anH78(**b9*+2LPmZz|Vn_EGT{e=$)cso3V2R#J+ju)Eie0 zUunP#5ITIK46r(=!;11P(+(EuExCg!(>M|dcuepC?ccQ( zdt5j(=UODfYK$!%n$P6XOvXchr5jBe_MumtY(? zsGGzweT3#D_+r2T`x|qT<3J-b1~Zy?M4HZFnvFP4Q^s*RSW4+bpFi;i==YtRzc5k@ zs1o4>V2SG`#zQ}Sb=oP`38#zTXP`b!P5415Kmbkwk!Y5h)Eg9HC2kaSG|?Wxh}5yC z$!X*_hA0MTeLcY&B>78^s5?nKwVk6V3h~r%*N3(Rs{tW9mA4kr9weGLkf`3^GeLyJ z@j)E62@Xxf$?E-J@0$4nQY*n$0KBJUJhL+Ig5Q)3j-;vrBu2YB&WLsa4&j4{;45lY zkTnp%WDJ&xD+8qlR3xn?-dGT8EZjVz*GagzSxdZ8teYNFL_8C@Kf|U03Di93ROXvF z8PUGvXG9MMatQAJWS9_7L!1(wGDzP_X+e0yR0^Sl2g*q-3-bCTWhM9(j1}lsr;5sw>oFNC$s+wh#I}zIhjlM|^ zO-;>+mcymOf{faU<%p3-j0x<|M>{7ML?T-ctOT)pVQ6R9#Hvqk(~2=wL%vA1Yw$Ot z^z9gK5OosG?TWx_$~cX7SAKF!Br>?8liJ<(=~WY5JBMVup!0FQ0sCEymzp6TTLsQG zcpDSrr&N+2mKG2eZV1gH z1%H9RP@%2mcU5S`T5$!xOG9F&WM5W_<)9eX>1I5t4j+7Vwoyre;Z`WFG$MWC@uv6I46YEi{`U;~x zLanorAC96O{viK>)&=?DM;ffl5;wvBo=$!^3O&_y`QfZ|KY~uv&eQb*Lgyvc2xv|H zi*wzy=cKxeMwr51_=N`F&SWAl8HAhdAU11BUOW{Gh`NyY?vLhYkM=@`Hp3%&#l7uWOThiFThh z!Ix{_5c^v{BTmip9-T1B55z~FF~2TY0xwCjw3kSIsOw{CKM7tmdd4z{WQqbp9f^G+ zbdiZYhPEW{pE&0z`JMueIN6VInc)2;_a>U5Mo20mxl)ctwt){$FF!!O1ZPHo0gE8o zAXtkA6lnglt++5@~`^9wI41=T*eIkxW8xIzt&k zXwh^|7E**%Qk!`<$d0UKT$l2LHS5aIgNP(izQf3ovGDz z;l$P&!j#^RNrpHJei^U;zpU#PrB>HqnbGb$=a-G;lTZdGC0OQngJ(8c*T-$h5GV1? zCYXp+<7XyUMF0_9WV=%r*o07p#hDHheLtR=T%`-dLeZdW8c3*0;>kOfsemLxIx)!* zLfAITQ^0E}Ly($Amm%Pd2gd0^9nIy2+A!T=0ijvO1wVEWk3+MWa@nof-|Hqs}G^*M`kQ0mc)V=!f}QYAY&bN)rU zqe&|!;U{%{XQRJN;T;khOhH%lHU5|F!g7?bMCxM{=dOg~+3+MZI8uz7*OkItdy?>bc5dE zYv8canL>?EFSSTYQG+nk8B6~T927*~a0nrSDu}A?av|)rg8owkacjIu_Do)IGbxN` zTn%%#vOAD!B3!y>lJ55=ct5=l0-NY#1|{;0eQC{apL~_5MB|j`zMAxZHpkU=Ne}fLo_6Q(n$PWwd$y-*ckWK(-vnCjLK?>x?748(|B_Qa{1R3>dO@+;x zU?h1>P+a}|f?zkBGlH2{Gj}Z@Cb}fPM|716H`xc_jjj_vnF`IU6BqUYIW3(I(R8qt zh!kNa@J&W|hEgHwmH99)g{?!bFcrC+yvQwpx+>|gM)F1EnNIFrC@80yeP3O;Pz4A8B`g%Uz-PhOs@$R|8A6wLWQ0^7= zL>aeR{)8+$UxF7kR~|g^CE-PFc4gYKT%iLf_sr8Dv>n$$~kv`E&lbdiQk*&eC_M; zuiY(vqmO(xqI4^l&ivfD@h6V-9r?NVJ=%-wUmS`59G~F1C}J5J;M<<;FBV0$#~vTtpfOf?0Akzcr!yQWV0)>q8t`$&SH3_vM~fsp)dly=?VG*Q`=49kua!^WwD~@Gf7q zbY%17IRn{gJ9=i}x*BUKLqpTRw8ZR_*T1dzSIq@$*O5 z?OPArQCJIdsDYRqbfY|*=z zY7H5G5Ud~>&2T#@Ypfmm%~YL`9Z%oGd+!!@De8=6q4XTmU}(N zf5a#l6QX*np-7Z+r6cV$5tx@(ZR~7wc5hiRvTajyO+|fH;0yg*_FOdCHMAkz9k{up z-nD+&#qEnde8qwVqZ^i0HPn>lbmsm3J%?{!an72m(jR-`7gyE@c=VoF#HWyV*#)X1 zG+NlRB;B?zMtXnPntGHaZa3_a>28E6;4W90*NzIrA+NrAl2Mylvwi!TRclut;(yw( zXxZX(kMC7Ke0(p#d%=mVN+#gl$x!<+J}*FteHXzhj=(nCez40{8^01JG*ICyfpZ}K zh=R9TRYaqzbF52HeYdeZ5-u*xbJ{?kJ9&pgB2%=POlcsxEl~vVQO3GfRDIMF+C|9h z2uh3?RmAmC&gNjDLbTeSCCbxA%f)xRVD-iBZO-n>!dTbla~7-_?#Sz^Ja1Fsit}CD z>}}D)##lq``r%bWJq5ird$xFLV%3qs>R4sTXI2dqmDiTf3k1?fx;mCw?YyA3W#P!O zxp^g3rA4*QK*rjh&L!Ng6!$ePUC-Az=e9&z>>18@Q+XTW2UO(5-Hm+PFX23i04*j( z-Qx|+W_Q|cDExtl45tGyNexV84itD)92P{V0t=NIAsONzV=tZ>>z>F#CA#~4dBw$ft#O=NDR5~(bmzE$%t$r2frhz}eb=TSymLQ+ z223WZCID6zl*M$wgWX}HQ_wKN$|U!trJQxdnj1?SN*n6yYHJX&TNnyTn54}LlQOc> zk|8(&mynkZ`vC31h%Atct%;B!6Ew6x8?YdVj9%E**FCqttGOkourQ}(8Zcf51d{ML z$~Sa2%*#FS!4G~fKPQJuts!=QuhJ^&mXtG8tS-rcq?FF>C{PQw6~m^1=edKKNWt-8sgMwB5qr1R@o7Eu~SXAlPP5V{9Laf{jo- zEMdmpac-Tsc6r!_00xJ(cxgK-45V8MT8h;Sn=7lDo2x3DF$_TD4*m=NUX|jrPG!4vhN@vhSMOMM<5jp{ zk4;9&s9z|4@vM*-2*RiJaYaiUErqEXaObicuF}4nXj5+&^=DC!ZG$=oW12A^BANi! zd5?|nR_{K(3b0Jxf0l7jG%d75esssi$H%cGmuuG`XcE5(HcP>~xiF5il($dPT$FnM|j%6ZK*&9TxB(CCMAW)ltb`+$LEx zS;K7U6bkzT`uA`&wkM$kMee;Yq zFKb|NVd*(*3;0J+c=qAYf`tW<^`ix_9d7Xkj%Nmgna2Z^%u_*LxVKOP{3T@nj<7}X zp~5_z0GSZlKnLNThCCp26u@cKM(G8R;PW zxjdJIAHj`cw)#OB_R4e>C?Kl_!>9mBC{;7KtGj#G;Lv&9+BIoIv97T|bLPDD-{aY7 z3)*8tuD*SX|FGoZzP^i=zDJu1*7P*i4MdgwzxhqD27DEG{~Y$FvWWiy9Di^rN;$KUFDeSi87@Hr?Z_Dw4vsS0qCeJ*1JU00-96uZ?-iHvy@w9%*@N%( zxz81I4=2XGGBNJ5(olZe!l8<7hvlHm*i4kl%=PDNEqO=*hSsaRTd@4;)@5?@z4b4T&}Qa_fd#v%8XK8}A^=1&{Py2Lmx zpS=w^p2S@Gr?v6^L>qatw;{(P+IW9Lo^MaAfk~cEg(TMC{aCZ-#N3njx1VCoXunH+ z0r=;W^#v!jzaQ@Jrb*?{bJ*O)I$aoJtV z8yn~dJ!k#Mnib2IE*=`3*B_tL*&b_c*x0zSuBM{AxG=XguQce-$jQv{`bxtg#G>+` z5L)Skp`>O=qhd(;JfaI)E#=l$DZS!Wz1B2t#rdo&9q|kuTqMvU%i8~A?mgh+ERO%- zXUlV^JM}xAdarJhPj@<<xHHtr200~ROgY|EAhxw*&ochus6^pnOs5y;A&Cko2VJzFJgI6*OL4!9;xx0~X0buzlm#TZ{F z>2O<|PbB6#o36~F;2HSDdr{|$s*HG@n@&W_7+Yd~RdaNr&THf2**3>mb?RrFzln4F zps4}eBabrxhPVk96DBMm5IwMO96Qj3EJ7pDZZNtbJq?!|m8XT%!%)LQ?9$ia3ALE$ zMRA)I?!Q6j!qa?CwgZ((TG{lKMlOMwU5zu!* zTcZ^exc&!27dmI`;)n>hImU*nN}S;`pogfhsxKS=E7S+pp!U_oS&MuJ2FEN65}Ftd{gQUF&!nQ4z z4Y)lK%LfX@IF*WV93|?4e%vXQ;Z9@2>>6VDYik;2H&j=a78l|2E?<_S=49C&H4JT2@t4@@PTfBPFXs;J%@yOAE`&3d_8n zw9L#j53Ynso-E{JUt=%wHz-m&A`(| z8SAH&@$br@qKxI!%1H3}Q8A^tKU%V|}jL#J_ti`6!6~LdkVb@1rBuyxMqhDp?`(3QS3tLq1ep94cu%! z8`A`VN5w-}k7JRJAsbJO6e_VaOm6II@#11K*g(=!TuBbGNgo%>C_S~{vK8e%pHNK7 zJK|su5?3#h;o|E2+|1%-!8umo$*cljMPYGW2seV36_?aC0L2r(fKE&34Qh=rDZjgf zKtm5@iVwgy8VN16^fFrz6yq z1qDofaCnhik^3iwYMys(3Bjy_|o;gn3Fui_VXGaU{bVy^D=?dQ!wY1385X*-V7E$GR4|g7PtHT z_=I-9iHnc>MAjwjfwb*i?SeB|3}f?c_ClN8&@uktzC?Cka+bp@2tin1TlbF*?CFW9ZXCO4|3!O72Sy{idv zd+U}>8`rOGJE#4e6L)Lg|D;>rrPr(CeVyp_MCkV8I@z-Oj`tn+N%lXvcjows%M?M- zj;YU+7>-XwASa5C8=5V`v7T68#4<3>lR!U}Mx7BbZfeQGz~l2^Z7L?Nq`4J@IbB?9 zz~SCb8`yE6I!Smf1FLg6lUz{uf{4^+1R=4xF$;;FE&!)~_bkF=ShG-;8xhQQ$~-?G zQtkY}{6M{bb`3zQ%*-kG%q>rG70$(g)EgFN8m~EC?5}d>z;p;nPuS?imd-5;SE5tG z0kRl&`dtxar@#3c>WP(HHWJ%jH@kdM)`!F7e)8K5X99Y z&4t0f^<1IEAhFL+-VSGSe}bN5xtdtAFi}gl8Ze16;ljyiV!%Ki63^^&qpKwaiS&Va z7p_!>Wk~D}i+#SAerBR)3u}*E*%iCSAmcwbDrg$^!g6e3w|C zux@b|pK{LRF+8~I6;~O;J_L7hzA|~atG<7?%s2k?UbBNc&AUfmer4o7=43~|SwYtx z!ZDNoldhJ0?Uy7qDRqkD z7#D1*a}_L5^hCxZO3r*cu??*tgVQ>_fX_A3c{i zQ?t0~OC`y+J`!hAcd0%qvHD0*xA4;^N!paV`HUtLfLCD{z)7Sy877Cll@QTJVgz)x zWT#-5D-Sq8e6sL3ktqfN8X$H}s{has-E)cFo9y~{*HPJfAcAAR039_*{JOvg*0;Dl zu%p4e7sqb8^z@`QA1KuN1d}+Mna%#qK+v-jC}e7E7NT zB@=81)?*FEA_HfK7X|98DvNTmy&0}#T*EalFBhBYpzRks1IVQSTO71fZVqsNcwrXD zjx!T>*_t4>bP2ERLTtv8Fgu4}rmfOr5Z{F#cPtd0J|+@69A2r3si}!QbIt(mZ3^bC z-5foAQTrOYIkt^dddrerWu91CWiYRL&8C5E*VWFQQ+M6`hF~4N`r@SBTjwuu{>z!O zch$!Jq)RSIs);?e`^m_M-6@PDW5MC|us2h32G?xb>$;fUId^f|ZyXIV!`WOnx5b?b zlwqzeF}9NzXe0Db+g9CCibY_)IQt+DKEOD=QyhzMO22V*A(n|PrQ*zj6HdWxX%I!7 z-6AD*qARc!dFp8iY&fWr_q-^NYGSj2IGGrG`u_WS$Q3;gJkS$6Z~KE?-@(7G2OoS8 zb9xLg-42)vj6DjbVy6iyD#e`y@1=k$Ej5|BTyO^q{zwyj6p{&Y$xThcoX>>L5$9#GbrF*n2pqe?a9|eu3)P8P`*5}}CV;52s0TOe`eHwL zS)9J9! zLnjlQo4YC|n5EAUWq~!bds=B%={KbAU z@iguePn-IB&AjUB+S=;sd9JS5NNsghZEaO`ZM!g&8IJKAq0mXvZS$gS6-JHmG1a~~ zph$Gb*39G#=E9D}t?nf1OvjcLM>Ne$Whq!{CE7U;iA5}0%iyOsNo5jpyUvm_rMAu`kdnT8s!AN}xE2Jti4VX+IpladI4Zc^cf%1z95#y7da9 zuO(u&(t%cjk7c;hnKRkp+?f(*t!s?rWOpQ!xZQ2;wK>^P*`~SO4u@eB7i3ppiQ)5L zr(RlS8oU&{Q{8X}?r=G@V{VTJY`02SHJQ~sv9=J+6t)16fVKd}?(hx!URRBq_^oQw zv2PVrR1_2!l~ok{jvT(=g4jjh6pi_d__?jTu%NuWpg@=lFuvX~ZlOu!&!EhIe}5Sf zz~FD<9iB1%7SA9bm35$8Hh#0w3hm7%S#Gk?(y|x?2A7Toh$IIL0;k8_~ z;t7k(+v9V!y2Aag9Y?P+e-NLj7n=LU^j&ed%bKOTB6E%PMd<3UkB?^Ef2Go>$CyS)p8Og60L> z5AZ@Mot)x=ny4z~2YDrS_aU_&`&WaMPz;Cv8VG2y0r1vc)sN5>1;v1#9# zlM`fK`Rt93-^zUp7mmNq&y0?K)8BBPV(&Z5>q`4eg^TU|AMH(0zU{E{@mj5K2)4C%p(?I5aeDZEm zPalwTMAF?EX;|ywJ|ih<2q9L88YEQZgLLt{2WLOZJ+V@8I}7dkXyhh`0~d!n95;7A zyC>Fm&NEoI&^Vq_VToyPY01m>f={0M>LNEMJq@s=3KI3m)rFS@bISDc!WmAmteo*9 zuf94K<=5&Z#<|hk_$T8-Z0Dj1QcY$Zx6W7%+f{6qv4s4FZZWDEHh<%MQQ^d|V1dH< zHFEFdq(qErhoGw@P!?>(sctX@booh@4=xw1WN9v}=#ec64M-AnCL18A8UZgm_AH?O zKKs)#&qJ|u5Pa!n2`Gq6z$;coAXtq@QGY5%3&y)A9eWu70oc@xYr?53>a;Y&Nb{!Q z%uXDaf=yYVcf*Qm`NF?ZN$Nqm?*ReyoF7sDMYfP6TQP&nT#i{EePoZ5Y2K0-# zXw8(g09K2OQm~;HvimNfiINABuoOkZutpY3WT{_-Pde zCI^mA92p-MEjudkC)*_Sn5lx7!t`VD8Js!A3Y-fEpu(vK#B&^a<%A0qTH{4B8c~Ba zUUFo+9yU*VSXB0dqxU={ad`BoptErpPGx;^UP%>v%~qe%$IhrYJ-)gyW{!%QGF=`2 zz(b=iy)^dy@!@!NPsg4T)nV*i7UxMtF&ud~o+nLCjz5Ytw@bcNG=3i1S3}RjU1VY6 zU`4kI9+%)>{9kR5bGejr#ZBB*Mo&vO&dG_5`&hL=mOqq?g-sIfNjZcKd9dMNCg8i= zHfh)8N{XbCq@=c_wRzYwCM4a`qTH&y%B-9$tlS)4hgYm-T;jSK(~}mLa7{_A7O_@A z#?zv_mT`}r0U3AV3PD$3f6v4!c@n>y-p0Ruw12vwd!HoiBxe^W@0D@L^Uq9`ci%9U z&<=XYs5h1f>RW*Q870Me8Od%p$YAx7V4!yPEaJokt%3jrX&4bGZHTdwLc zWD%$$YH;!tLkn6!Wu$iIAU>QU2Axw3Ij2Yild99i4B*498zR=cZcS&_(i~Q_vGm;1 zbIX?Jm`PdPSuQiTvuwC@xO77i&t06ge9iK#vLvV|ys_`c){-N!$Gw;>DlCoeLWq zQ(V`f^C6cX0l$7*w||wfpe20T$`uJDqzWXgTGp~uBO>|4h^YGS5D{13$OZVSHOoDV z^A%c#OP52a@NUma;Mx*TtqMWB-8-ivK_ti|e1n4lJRI zmFo7XfQ|M}yfF@p1dWRG?=I zRs4)_pAdF7{t{%rhnTpvF9TU_}SB}bh(1FMCW_2Q)djdPovZ_KDzowrmfR@wNspih1SI0%DxcN)uDT0566S~$OM zR%LlvQ9f{hb7mewu~h?i^r3%*YB1sU&yItz5e5o`ob;|Jn4)MtAu?j$JRp!EShZ9j zl80w^g>u(!?mK;P`MN6F9b03m7AKA^3RbV)ER@c3=F~#z+)xXp^9-2D-n)9^uB1yZ z<$0diPk=V9h9qWj(#-njc}uWA5&tlcLxvRdcmb@Svy6Ghg)Qe7k&JW@GHwXwY3xuA z$%FzkGx-qq+A}Y9XQX45o<-7geKdolXYBIezSa~s#TjC?`fXa1ol29Fo0Heho?Qsp zboM+Lr{}=TT2)wCSP4yCX-V;nI^aC$fXl)#x5~euGl<18)UWcdB3$9Dk`k7$ET;-7 zq;BVPRh!Q#+rGPcRrL+{Q{mI9Zm5nek|N%jv0EP^hi@pmfqaNJ{G{`)&Y$3)dMI(M zYy7Rdz9jW_bm9%@j;kU2Xx%Y(KS3pg-M#;T?l`Qq?NWDaA2Ux$)p4wE>WpM5k7t^H zYcc;Sn5qnnW1tU!VTE6u1?^ZB)aa=x!cg{~Dz@#wO`T+KdE<@9n{URpPX%@AX=gpYUA6 z&2u3g3d7?rY)Y7N|6xH3bga`I+#HumnH`T`2Vj*elqqT*u*2McbXoHP^Zuh(?ND%b zty3W4J>!g}8=)#;wXJNeVaJ;BA3jZqHal3P9$^8NyJO$+6hf=&sd{VoTW{@t{}POfg%#b_=^K=Io?2nzS3AjkIo0Mka$s2!lH$vJt22 z(7%Z)L+NKsT+9;m8D&LZCy?;q``e=x7AIxnxfD$o9GsF~foBEPCCfBIi; z?5TJ!Nxd7*L?0|Ru5C$%9-KNCK_@H@=8HbSRzY!~#)Qq@98M-~hx;;EpMhRj@pmJ& z!$G@5CP$Ch+~C0GcpR+KIj|)iN|blaf}K|&iN(g^rpC%jiR&6qipDgn&pstAQ>W7U zy_j2CSPqm1v0dJqRa{shQCd)#1s^vHtAWx&A7TZf0~JL@S=pr}vx<+%F%^53dP+*O z^J}W}^Q&v}#j~+y_QI9<)gnUu<&>5<|Df~=OTqWHVA{kPSxNqyf;GbRfhC?u#mp2@2?r5C ztnq^gHo~4t&=b?dzNxa*u|q&_ei0D8auKMzpeQS=u%OH@C>r6qZ7Ua62Py>m3-inB zm)b?eDH2ye;JRVfoP{gwJrP1rtgw1P>pBJB*kRn+lI$UFo({8gibbhyIPMT`jYT(R0pO z+fLuSey!jfOP4HK(AeOwn}hXQaba#YoM5FIJID@U&94H&Ym`nz>2>W)DK}O@-D0k|uTvNyUSKvw%3e2X>HQWE4vsQdk&~EQKNo zlFGRgzroV;XPy$Lv&2KbPjYv~K07!}GR3wf07+9^&(c4_n+)n2{~PMM8+8>K@cLDl zD^(r3N=w&~sItf?l2w}1s&v{`#Z_eD&+{gp5^LW~0YD~s7yvAx3$V|rr^wsn0r-v?RpRR`*g^zf04YkYAiSaAFcD7g!6S%tN-o@e zaASk?#s&`+Qw|=TAZ=F*TqD8@N^W)*OmuE+DS_7+;a;ppj(WJm(&vvb?BQnyGPuLh zJ!iq3%9?_bs%=|4=Ptme@cfc0?B@<ME=ZB()fh6laRVdFZ4C8BTYK^91FzEVmf# ziHic&Xpl})5)LHQtU8St-~^jiZED9x$>y-XZgx#Yc}Y=@FBAGqbi+!rGGlr-h;v|~ zAA~C)gmGH>U3>^)vpy8^xZ^s0T&XwE5tuzYzqoqa?9SS`i)-fwE1OoiPwZT<6Q`T< zSCAj!2-DjIH8llQ1q&C$x4Z~0tWQ6g!$Ei?{9$p~h5AernRrXD&7>T$sEL|bi@~@R zmm{#*2bUr`;KNhM5yX9&5E!tF&0*{o_p}oer>mjn?SXh<5-CSmIdE=H$Pw?BB`!xS zTmWgU+>4(oAxDJ6HbG1ZX3B^$U4RSc2s7(lM~Y`b4#+Ahsu03fWg!GF>>;YJTC{Ro zEv7VtFp(kF3+Wskki1nx({Z#lqP&AxoMNPske{aJUL(ttGK8 z<3(}@x!VXD7yloL2*j`igMvIbZNS!V&|;7Tg@~Y7f}JB+lhIT`;H;`ZSwWGvZrh4Q zkVYX~Wffsg$7F+8%=9W2^S_9F@s#HC>on~|jDNNypG}h7=Md_W&Y^@1+GJ$7GcGlf z-0*}q>>=>=cUf8r#U5X1Vq9)82(g5$WFEwRO{mHLI3)v@R7Anjlc|PcAFM-kRxa zhAHneldO$|X;^G^xa$qCnE6F#lou3dWfd2IiXrP37Rd!hu&OFpRa7G4(P0Z$cGU?X zP0GtMwzv{0#L@&Qur$%7_=*dw3T_q@PO39=D=KoPFDR_{70t728Z1HJxMx*``xlb% zX)J8qLOx61feGJZz{4-Bs@D8(z*Y+ZT3n!;*f0mifGt$%>4uT+Nr$yUn*MROBvjgP zK_^Zn3G*W)DyPt@#=<||_A&C+SizVZ&P`I?=aUlh68R|UiT$(dS#Pn^S?qlln*-68 z#^pHQ_jBlu)8Kte-l!pV9i(GZE!28q5d&GChI&o=2euGRJiGjvG32C53g+PdkR`T>5J!VEUT(214*F% zR{Z2h-F1o3`w5vuY=tez%~4hv3{R-}As}T_00hmWZSS}?e6aoAJZ}z%*OhQ69CG3> z=#zgwr!S1Zijes8BCd7+{{3@rm^*}jc+9U2?|K&s?$bg9jIMEx2`I*TS!T zV&hHkC%#)Z+$!KB#!cjtXNhtj+7fSm>|?jZ6Q8&2dIlBo@_(gRMJEqs4TWo1cmW#y!SpJKew%PYjAq`1O* ziZ;ZqLjA?E{u)`kI68vLMF(hOKh&gh$2G$oAW>zjCH6%5tXbvwOO%c>JLsj8r7RPD zQ6kI40v^M~lHDz9p)9K=m=n8ibZ{@d^y;f6JXa&{Ij5Ev_LJDv{d@N5yfhX<-fzpi z{}~OSK(S*n_U2&kNbI$}eIue|1=nN`t)Bcb#^TBSXTpaELkXX8pPfak@45@PC;&{? z049f_@e5hT;$~oFYB{6)$>D&9#EEhM5-WKBnOFC(Un^h`s;8OCf~Fm1p+MVV5tQZ0 z6o*AD{E8NRL6o%T{U~eA8ii*+eedLXfGgFgmwi+Xa+`XIC$=3)ca+I+vx8;LG*V${nX?E@Em5GB7Y%beyb;)^i%8CBmY6r-U7A&^VeF@$E)s0fw+_- zh{k|+M2vH}sR#Qj;RCgxC0l%<_M465hpra*z7}(8S!JB8;B>S>og9TrU}x-$fwYqK z{WbNT8hYsxZ>o3MtctR1;dmBnKfo}e$7GeHw0yp z{_P{Zq}}M0Xtt|&WiBe>n}OX_Pzc(KEe0Ak32v5 zMfk6GPr-#m!al&MZ^Xs&0w}=pA{$@iDXgg<6fPiXdde(Z;8=oo%~A1samB{P0rGrj z#j166VOekNs>xZC#gkvg7&uk_s*f~CjvnW)PbHW(jr%D1?|cf|>wyQVxDz&vtG2dq zxV^ne_~OYgD;p2j)?t-Y8x9s^=jFlsPXYR(Z!%*tIC;~l(vAYgzhxDU6t>eM*J=Pv0Gc&79>{JkBVv2*z0%(-0Je$Wx zmS-0>1u7Q$3Yupv3;(n^C)Ja`eKGY_7F6KU1QOehI_H4`GK@M|X9XlUbg~!@^4{We zm|%J9iIJY_bQl=~BxyNgk*Dp%E>hv3F6fK>rm20le@%KxQBmIFpEk}eUR08jKhNtc zY(qU0SCL}qQFfm?Zp65qxQbp!idRE~n|NgMg~{jW+60}8aX91rX+q^S@d&x6JGP>j z4(Pi}V!p`_Pkscn{_gXy$RG2Oh3&D22N^vU1I{|2lIhW0CIdvKBl;txv-x}i96ZJwqV|9?vj-X!nqLu9GM6#LQ zCOVaGu)4}(ApjOvqO1-!2Xfgxpod5Kj{lb4P`UQ)i|vHK3ajkO)?$1x(oq41!Fu3@ItfW7~x z@$+eN(lJX;YJ%J(&c9i5603!rbSFkf^#8=q)v3!z47#-$(a zA5D{k*}fnuQ>qN7O`Vu-e@TlvK0hGv1${`dPs;U(vq=+eDzT4B_r^SfYU+v zI$21soBSGE0Y0@z;nX9U)jkX}P%V-)QJnhCL?n^t+O0SxQ6(F0uau~SGzE2u@N`!3 zVsVCdL1uF2vxIFc4{Ln7n%q&Nhp{&cLY?fo3GEaxcL+z0E-Phc4sm;dH zf#-zm^e%KeO=cR6%SS=Lq65<8hy6b0GKJgE&t-?nT7iE91QJxNF!P$UP!mRy=M5>0Xj?z8T`O z<8fE8O2|DTZ%#b!>+~4po);098;`q^)k5wOFz4CgIuLg~;__7-M%~XKZ`}+z>LfBD zv~@zThEIFv&k|}Caln~4P&whO|4@X1rb-$G`F2_GNIIY6?D zr<>`>#xh;Dwg@kDmX`p#hHP@})~)NOYsr{-@x>Qeqt$u}-k8vroZ`F>dOhL1KTS_E ziyoRhgo_*)&eJc1JwvoypoNL{bF5IXok{wQq&;vk%;`qa=JYi9t8ns6Q}ii=wi^e- z(FcMz*~ZBABhiDUYr0oA%$wJ+x|>d1eDQ@V7KuhLT7k}kT>C$(8xqsBy6-v|9a;MB zb$Q`W{ug{<%0Q((?e(}&cE#wvk0UrxT$5#gt^;fkt8_RWH58jnU>ZR{+MS@ z+|`l;y8s+>z|if@D9S7n=atJUT~b`M=`tMYbSnNnU+XSd&^fQcom5_7Ys$jZ)SQ;t zrD^%e{%QF1(@P*9-U1n_#`uA9nK=vlpO^AN)b4(@6xY_kFKK9QX?2ba46ZzLMF5u&tvHj-_2zqv^Rs6Mv+}$} z1=(`~Us$=Yq^hc9AuK60R*3C5Mox5*ET>^T@4x$3O8f;v#^Cr>{}EHxGJ<$cs{|w zLG1LR`*7}n^GgKjYPGu%w$QEBQ`7N_W=@DL9MbgVOZSPRI!aNO1j1%hg;EXh*X!J+ zjZ5mno{HFo7TAl^+_^1tDspn`HM&%vV7+xK=(yB)6#iqeQy1_H@|=w|7<{%kaRC>c z_grG5X>^Ttg$pyN*rc}VjxuC`??UYd_e2@R_BQE57w7rq=C<&3lAc;;g083K1UVPw zgPikA^Fhvq1yhMxSg}t;%o;t%Q*rERg(g-9OIk^8)|`Mh*IS(Dn;ra;MO$-N%H%~- zZuXu!|IUDQ9sJvCdeEBV`L|ZCSH!OCj}9$pTeGsdG*ni-a%~&C^uU3Gor}fjS=_03 z`2Vba8xN1ye@}1k_A^hd{xs}X0w2#5L^6#xTYMaDeomc_ADTyP;z=xW%TL5`;5kY*p)lmu54Cc`AomX{bSxIrh zoWj|{&oh$Y0w&?T2$~^j6t=cl(fG>8VyqVM&&~E%W~XK>tDjRkyEs1+A^%5OR-IN+ z)LdM-a&-&)SawcEn!_=x4ldI(Qk~A4y7wvGsZc3d*q1j%zzuPM zjClwFENLbw0dSVjR>~sdojs5)GYtP-icHK-=yLa!(m1y3!7<9et5wr}Wucam(8VGUZ z9z#!bolt~B9)MXuhyy&I=X(k=g_c8I@dvMXa>qqQI7eIt1J9=L+P&?(^X653D6eSn zw%Z10mEMq72!DXvC&njg$%XT}3I;s2-rH`w?XId-xg*|&qS&>7p?|WC{F$8(d=?8o z8M0ynJKF^qJH?!bYptEwg@UoZ6;qd^8?&KC#{ToAVG+!Nl2kxa`a9U;oTs&VFBt&xD(>q*Z4fO387!&1CXH@>(pi zYT^hUzb#yz<8Lh>-dHxNLbzZ&_K03C5EOzacK4n zHIY2W1SSOt;hoK4z||C9))Aw2ZWVY`VFB(dPQg7J`6N$VQz8~l;+_q0*N)h4h|34% zu0yD1h;?U=*ShFIT{Sx>?%#0xHv~f)>fG`!j%R-quB{D+yFAt6S>;)eTRM*9RlE{h zGiToFz$>_uWo=#so%=G<)J~jxqjOfdxXH47mJ>Rqr*K!^85kp6=&P{^5E7eZ@XO2) z7kGGajVEyj0(5Qc33JxOfWQR=DV+~}*HVDZLdX-R9Jzg1cwAsu|7Q}|KL~jtR=E#9 z#mM$y`q7C2dpU<>{m|42J=nBjAl1lXTr`+T*G?RvYXd0aI(pqvaq#BffCB|cFp9|w z`(l*!W1>@<3aReqA;p|fTsIT$lW@e zVHENf9nQp_*t3jwW60Qt+cSnSOYSsw!B=`I=+rO&N{!8ki6Z7S{EixJNEJc4L1P4Q zYmjpgf2GEH#1CN+6E%8e{#IiQ&s~TcmMLe+az|0m2yieT|LsI6BE^`|10UPHNVylW z$Ja7boK^4a8PeOKS_63cP|q03-iYu{ga!crFxn>kdN<&2Awot^E0^=f86yZJizW+GtIADnX>Lf*tfQ2P7^8ovRcA{$2^+2!8tzKL%I@)`k%lbSu(s!YSg_c&U9>w@7Jr18E zXpI=(`|w@#si4XMJjM9jiE+0MC9M7ra~)3?i4kERIYMn9|4l|Q?j#ph@7Av=>=>2C zk1;LaxD_^&3uj|V#t$*KyGb%hA*tYpX~tJbI>{iJXwg@V4-yYN096|k#-!0lyd(>{ zomb)5A{*lY@ zI8lhKCF{s~+;FbOB$pLa6IY`bo_K^3G3&@4!BJy5i0EgFhllPIsTurVa*BT?_1LT9ox#UCS!{j66I&wY6$!WMx>0jhy zZ$_UuyLXBb&TCVVQ$+(en5Umeq@|Zer&vC93zjAM~y4V zW5!nU6Y^8?IQf}zhH(-0!2ZHGWV{czS3N;~MV=(THr|VyseVJACcnk)m(Sov%jd}R zR;_$#{kQnY?9u+V~9l z3;8Sg8~Ho=2Tm0Ile|OzMUIkja*Rxn7@35z5GFdTZaMs~IpAbD37gp6G?}K*RGhI% zrx`f^>A{^$S-7_;8~c%SX&!E;DZuSQMerG0LQ82GEvFT<68=`JX$_r4XVW=!E}chf zX&s$U{j{D2XplDGKKDi%#=TC>bOBvR7tzIZ30+ECXe(`_?Q|J@QFYSgbOr9GJdLiR ztLYlthPjTeryJ--x`}S4Tj=R@D{h7AqTA@1^elQd-A=pdIW$6hXfN%fQM!Zfq`PQ8 z-A(u4M#8;xkPgv(^jtbjN9ZUWqxx<-%qcm*U)R}2j~ashm0E_7-B~ay`FxQevE#ceu93I-atP^KTSVFKTB_< zH_^}0&(oXfE%a9U1^Pw$C3+jZoqm~q1)d19paIOr?%rJJ((+*oDWqSeU!!->uhS#+ zPI?!;o8CjeLGPva(QnfG=>zmz^xO11^g;Sv`aQ^Ze>eVNyiLCk%Ye|57aO-j8veXd zZhX%8zHzycN*|&RH-l5v~yZR0!iDJ)vt^f&Zr`dj)t z`V4)RK1ZLYzo#$IKhPKHOY~*>3jHH}mA*z_r*F_V>7VGI>09(K^sn@9^zZZ^^lkc2 z`VRdUJxa&vF*-qGbP`G~Vew%&_i8fSj?I$banH??Sqe*KX)K*(z=@EDd07_ov22#Z za#0D`VxX!nnlv77o8wvMS?NRt-1lHO5ETEH<0XVRP9$R?F(x zeCB8MEWm=SfrVHj3$rHH%oebPY!O?`mawI)g|)Ia*3Oo(4%W$*vlVP5JB_VktJxa1 zmaSv!*#@?eZGv3=XX7p7Ud(nMFv{Qu`g-F!<0HlwjGHkFwi+L1o7on2I@`+5Fg|5` z()fgNi}7*R#kR3C*;(vtww-mebD;bG0gJF6*30@>lzRbSDzRJGF?qFYMN7$Y0E_OG&hkb+H%kE>}WcRZN*tgiX*>~83?7QrH z?ECB?_AvVa`yu-g`!RcjJ!;&?9%DaYKV^@zpRu2_U$9@YC)lsplkC^*DfS!oH2W?4 z9eaj7%bsJ;v){89*dN%7>?QUxdxiaxy~=>I64xg~pB5;lh#~tt`4u9crdgp>2AepD|RG!Auc?Qqq9`5B?+{d$d z4$tLzPz@CDLSDp+c?mD&WxSkM@Je3At9cEd#b@(5d@i5IYk3`?&;7if2Y8S-@DOk0 zVcvv`AtN9wfmapUM`3Am`Z{nNz z7JfS4%Fp0kd>cQLpT*DS+j%!Xhevo1@8x|w%6IUcd>8NMyZIhI!1wY&KE(I&bNMhI z!Rp;*Twz>hyx+LWxZ1dwkMc2WzxbnZnC~~f#}DxH_(6U?e-FQaU&t@w@8yU1`}kpg zF~5Xg$}i)W^DFq3{3`x_el@>_U&}whKgd7CKg>VEujAMAkMfW4kMmFPPx2f1r}(G& zXZUCNjr=D5IsSQmGrxu3%D=$B$iKvI8^1N4F@9q_Z9Ho{ zZx)(GX0cgfmYQW|xmjUWnpI}CS!2#JXPa}(x#m2x)~qw#=X4q^p zo6QC0LUWP1*j!>RHCxP9v(0Qbmzf=Ar@7o*VXib!Ggq0b%{As)bDg=~++c1rH<_Ew zE#~RwR`U$A%iLz3>1gd4j_!{-#|HcBJ6b!`v#n7-{rVZu&j#`I*S9ZI@2&D3`P%in z&ez(c-&^%lm(v<>w(gDe4i61FTZeYy!m>Ti){aQ;*l0Aly|;h3cWm#Df#`Ye_P(Lf zNN;a+aMZD^H-gl73=c&{9UT%@M~945MYm~?+jZ6Lx~g^!a(jcjBVL@&qM>VRb#`cI zIy5x0bDm~cfSS_*RSRHS%zdqQ;SEEkHTJ>qI?NdXDbqwxwtg}_S zOgCnkZuByZmu0%^mRWeyUD)1XuG=*knQ`hYp8{8Qg9@{$* z85?!3(@m4u>1a(}H!=_z*`*-es2?_fLyeA2GB$bBw8jVOHNefXDt~=bC*KVGIyT#~ zH%hSlf%;a*7F(M;blW-_%`J(xbm#&*HAXtDw&^x?bfj*X(v~f{En8GKnOlbYf!r;! zvm9F$*jp1|ySDcAM~9;${UeU8JBK6tqsd)~j|!cjq%QeMze?Qu13``5&L+n;S*&|o zoTwZTTf08_MQzDam{dEIFy#t#! zu2OKcYqYdCJNq>p{d%bO%ifoD;HI+V-H9?)y}@wGo}I(d=-@zPu&=+@F(9$0zBRWw z2I2_9IBw?y0MRk15Ih*!H#9OjJhX3D)G=sF*3ihJAiE(u#MWrkC|#!UwoIdTneO&w z7V35Pw|AODiSe*Zx3a^^rBf}_9oJExIy7ZG3~5}bvE7zDWE(H0l$&@Jx>n`4QV zc4+)`YJ7EAE!QpX=u91(($X=jrF!I#$&o*%M*acSr~`>cxemlf{sA@e4<zJ_yQU(zm?8{ z+iI^>kA~N;%lGU0{JI{$E+=5Yr|a`;_?xY#E+3+d7zYhXWb!w(>2@p83GX_crq~8G z`}iAzI$coXNAZ5dYy5<){O&~P+pxEeG(4H}-1RlcsjLBrRe;nF<4A!NaA zwb!ag!yD4&hje`*T~A1t(_q1;>kC=^X5m$*!&ImGPp50s?Nw7N`cJ1*yw%^((QLL3 z?AsOLZPC$)xjeFWZ$uUlY;JIN>>KF^KjYi*iFM%f=3NN!m5^f1Rgr!BA`s*D_Vh*Q znlZX|jGoaCF{xij!E}8;+qi4U+|<8wZ-i}*j5)WcqS*Rf{j42->qq)kHLcBVS^wzJ z;Lu2lu2H@up+*^Si3-(sUA}tJWy%-#y1mhzI*~|jF|Kr-$a+_mV#0{XM)#mS=1$RQ zvoDGZe4SC<3Si~6jKkT2=_#Y&zv?Oo;2AjucEtW5=F!&MU9 zSoxBK#>#+#Urn+8pqg^=Y;=s(FAD`FwFc@H*Tu6{Mk}HZ)CU?|=SPQ!>co#IC*W_A z!wyeLhImS{#Z!_go^lxADTf7~av0z#hXI~)7~m;~TfiSy!`R=ZhM&Jp4Fi9hE-$Rh zgOdhXe^{3n*5!qDd0~~mRSC-hzZ&j%Hl~UDriVr$=|m%a(P34L;wAxqu+!Z;gdu^6 zYb08*FFM>m)F;++kdOPMtkvGSS$@l&`I{^)tQrvrH_9;`2!|DN!i{pw27-!r<0*Lt zo~rRd#mfWD8ad4hIexzqg9CmwhXTq5&#r@zw+6e_qi&#oXC!Y*l>JNo)GrY8B507z zl&(KPoRRNd{ccZFFg32*{w+g)8;FjK$O3$}i0*i7wvLTJqEeEmOzi1__!S+9?ilU1 z0LT(id!nOLB7OGAc%g+lcDR4%uF>wnvAsRfVT{Q^RkZ4#ZuO8+c~he7Uvj2?iPw;& zT0b!7D1vB-do$&e(|tq4aX$+ktDC_0hdt5Q#?q+n{?RGh1Ci2^(- z!rm|GDk|QR+>t0an4s+Lcu2xt9)C@INQ7h(PxQQAFvV{5P&lxn;yB2$$8;xP%d(nf z$G0~gDM6A&X2;{KfQ&A&-nx$q$nS}w5_OhDMnK>FBYV1!3&=dac(fg5-gvBB9>|n= z399Pe7a0~jW5?)mU*c3OzZBT=*yvW(Z2M+wx-Hg*>9ctPN zs}&yNrPPLJ*cBPXliDTgS$ATURdIykgV(R;4Jx%;2Z(8$}hJ z9i3`&@wavIKCDrB$Cx!oEA>ObuSEVpK#9ZwtY#%}fsmS0F~7Kak#l$q6Q25_C!Aob zny3P*+CV@pico@@g#${64+NCbE)c+i6;0S1FQ-FIgaLm?GCHq+e`Fv!*c(-K1e=qi z=k;U64vzLm22>mlDu~%VsPsK}s#!hQs%H71TErmUN~b2+Kv+p1fewX>K%2@JXj1jJ z`jxcOsuokggeotfrI3IU`U3%fyIb`_q6vEL4(Pc&pj3E)fS%(6VZRGmM#g$Zq8fQk zp`_^EeWM2v;T{;;*^jj_R>dwI92!pP7jnf&v{y_mCfW<_GJgI3HjP!a#0&(R<(~3N)*p3t$x@dOFaod$7GR zWgm1&fIwn0X=JQ-*XXW@LTP=2Kh64T12Ul0`RL9z7Yf^t%oZUjooOJT!3=2B1)3Yv zgr);DIyNxczi;56hN9W6qW2AqjW{F2!$Swg_Q_B6&0)8Em(qrgYI4b_zM%uM=P;m} zRg9P>becvL(=#->ONGYv_36|ar}etu>UBTXYpSl-K-X*B)@$moZ*NwhK*KV&FI9oi zGavy=vEBqs@fT6K0;fZfK)vQiLBB$OSd&<|Q;}Y{Q}d@zl|H1!`;ZpzLlE!#2791< z+#|~kY4JX!#rsfG*wkP5*;47w4mByl4e4PSYFg$T*kMc8q=+ljqzE~L#li5X?R&F= zGSsY~3^i*go7Hd+H7mvzYS#I6uZMIiLwX>EG~z=TNCTtL_V-0i`RnZ4qn?5^L+u(` z%~V3l0uczQr4zoZ;T3A{aD#9Md&UL^Gz$nR;|`L9T|4>_-Pbd8o4!(v zb6|&pN2v_}sYY#^B8-scpdn?h!gs}CLz+j0)H)62Ya}Txc_7rNyGD)3X}Fa71RjDkUK%x0m0lI)S@|@4N}VD+3aN6HdMXf7YQ;cEspSG8zvBEMrRKv_ zr^^p$c$GR5=`}ol4UbX-BE2T9MhkwcevO9)oxVYr7uKY!)M9`~!>81MfJfJ_*Quef zhEFd6LwX4q(!4w5*Yzp2AK0meQ>n#JzOFB9wMWCN)Tw}9e^=^8v{S>Q*TbQJhF_`a z0+s>*?gcbn^$^k;fRL6QLVDT@HR}9&dJO5MZ%EJJAw469^t2gj(EX~^U1*PnH=yIS z#1T^JTi{FgyI%K)!aAK^LWlGcI;8agABQnX)} zuhhKwZo#YRS*cl(PQPo#K}e}Z5wH74OA;ZaZUp^m)}+*$pj#`QZl9K*LQ0K{dNtma zni}uAKBb;SJr>@qbhH=uus-luS=}2Z*+-O`(Efe`jUI10|Pow zYHtLxr}gH84M*_P=*H;i*zllEqhR+3eSMM9$m;&VJsl&xk$qOJsZb?GN3FNqzUcn` z-e|i5v2$o_SQnBr<-@u`D?{Ft_|3aub(=BA<^w}I-V+_{Teo9Pw6A|`ua3%)QJbUZ zjp~S86)_wc9NF7HG6G>ze<(WcLz|el_1CoMAO!N^gZec!YHw&3CavhEC|15u9a_yw z-!U}2w=){;(^-5whlj@YO;1$-D^~ycz)56aa|BajL1e<*tx zr408?2S0f@x(_B$xr9j@+10;ebfpD-x_n(XW+6VsPLRHl(a7-Vx*aQ^TZGYF1Le`N zw(iOl^6hBEUuZa(dkW7-5NRn8Ur;8P`()h_lIf?fv ziY%{)m&y|vaC<~DI?>sSRZY)952iImZ+xCikkM6WoAgs z*b2(AMc5IMWse8Z$=td2NL{@A;In@aVHuk)V-q-0Wy<$N=M>9Cnr^gy-UgpXeztU? zve^77QB%4oRerL-&9vU)YJCN#7(@Ec2EB-}w@IN&jU$;%wSI16#1p$Yw|LWE)j z_7-L*^4SN0#}*w?3iljal)Z#}TYMrYfhbSB+gd!O9jbn{>BYtr<)quF*EWr6ZR6Ln zES^%f_6ORebb+Uof&Bq&yOOi5wq0s7pFijiyW|#{-l4rcF1cGqgk)Nn{E|hUpufG& z+A0&&TQ?A=(@5DLX>isK0wZQQQ^*)VYut@V}UVG9u z`%A$7(r$lgw7;~%H5=7H`P}6B6=&;@v_S?eEws25~VXcm* z7hx;C2wUkzIGCYGN|rA{u|@c&M>J252-+iLozo+xlp$-MoGoEBYzdwRo5M zkPg4vE`_I#SNjw29^`ActX|DFt#8M zh;cstBgO?d%Rr1PaiWl5hy82#eFJBji19Y=d?F-`xMn>^_9zhA@ zd~yMP--}a%gj|f%fCOg%ufp%uIQK_z>hHt&{WSSBes3h7!|xZ!?fAU|5D|G+kBD=6 z2;Wb>joG6> zf5Puu1^BS8>k1owwr`Cr$9%%_I2j<+!FCaxOx3LYUC+V`z)tikpta%4<+6;c`aH2G+bz4WN(SYqE;&-F? zUDdh`ziZa5#_z^;Yw){Se#LfPgrzrWaYh#~?TrlYG1B(#*}Dg)=A^tk z^3TF)HxZwNzZ9H$Gs%~6$A^RyZ8T&Xb0wT`GKKS4f(i{ug&|3WXGtpDFRAc=q{73J z3LlqL_;_k5GP$hh2&g8 zg*e>`D#Qs_P$6=F3US62REQjRlDlxe6;z0vphBE!1r?Gj1r?%@_9jjz2KKk}fUKk{8c zf8=|hzt!aX;v^G!2=q5dejw~Xr3IxEiG5D&#`%XV9F0zRDs7bK{Xy|`yVhc2)}iFSDV;&D?- z$%gY4tCb?8a>zLNH}QQ&ggiILL$_HWU*c;#&U1(L)hfjoON0~-kis7K25RKKzasW@ zE98L}6%{vQ=pOr5&(k8W=X>$EAH_pIwL-ogE97~?3i(j4&ilL-=Rq&(dJ|A3Lh(|p z79llyA-hFjNK%OkiT*udNaXMUV$jQBE1gx|6ugL1RwrFib^a!IQ^!Si>mOT#G zKn`!673Xb;hZb0&Y*qICMJrax7O>S?RDPDZDqr$suELxjA$ zMIRx&D;^p>KJ@>!c0TY`9oL<|Gw(?VAqgQpJ%o^j5JG<+`iBrg7D5Ptv5+w)1hWdk zgb+$?N(d&DrK}edN~ud+m%1)XScekIQkPIdh~rR72_=L&j_bHAC6u_-Wm(rtU6#6p zP*>USIdkuQPaxCo=TjatZ{{~M=bSk+b7tl8P$SvR@ zE5MB^snBjXE1;v$O#E`eenzD)Osxn~`P+k33@raOsh7m^pASm&Ukp-G&!-or@^`0V zK9#)zmVY2j9ST!NgH#;({1%)O9Oe8oVe0iDCH4H$w}Mn`Rgj9$7wyQuf+OyGz$nNb z+9`Pcg)ntFNX3(-A(sDcSUQUoYbIVNJpB0#4?iXQk(=X#q+)AROWn+lZ3wW~Ghu3L zkcwj+9lewkd|lguj-a%lJ52QisT3W|3o&1M^pZh1FFGi&K`Q^f`=&k!OFs-!$yt|w zM|gnu7o3n(!8xQ9>Zdi89;UMHmy))w#lTc7PpK3JrLmGQRUV|0En+nx#=h@*8EXhr zEkP=f9(mD=Z`Z<^6I%ctrEY($JxnDrQn4;Aoh|((H#gbB%?;76%u{DYWxctSV6mlA zDyt_2dqc5RAvQl=CZiv(D>xFSUcFx`wl=j?W=Xs*wjsb`&xEP1K`I^(Q*d)F3OWL; zpgTy#UIFIg|pM(iLpDx@^2 z-PkE~cwDg9;V^Y9OiAfkDNVKzd*C!)peyvQ(gB#85wVL5xW|u-VakZ!qlxGB|HKv5MYc}z&9h%m9B2pny&a9>2EI>>6uc%V%1(aoHcmIOYdnte12|lGqo9Wdyp;NGfu#>QBPTTDwa|@*sc*;{(?)6 z7j0$a=NDWdzW+!w=5BlgZKR%Z9j4kP`8P3ahEim`P6lH)Nj<X|M+vWmlD?=Ec7yHJQh3B)OQ9lswT0F@N$yNasoWc1%o}KoY4qcx zq<eeb85E>~V;WDLFydPc$mc6yL8^AV@wNgR|Vl6ty1S9 z;!i2w;Kx$GTGNwwZ>gj~yst-iGq7owyMyKzw6xvDN*Owig0 ztF$kZReOK0y(<)5dH<^E#Zt%n6mQiKsf1diQut-<(W4sA(|#qiUyo>=GNF$qrGBMy zFVj|4O7khjJ0u=XF9p^??@r3;@6rNDz@rXPnNoZ{R^p6D5o-RXdu6ep}lbMH;ncLba68`cJ85T2$svoe7UC(x^y6(SCo| zsp(3W)>+33Ly_}`8h=rFJ?_gO`e~PO#0RI;>CyO0iX{4Pg3MLT{EPPMAGNeo>3`c# zpP)`cxpXR$P&pGn$GbJU63SoGwmlku+SQRe$ILXDGYu|wxKd8|X&J$i(i0|tXLOGuryrZ_@ zgOpO-ftmixKX1}B^Qr#_G7I~E;v+n_q|TI3R->|(5qFr6d-}x-MtCOn0k1Z>!IQBx zeKMAVzpt5iW2{G-%YMLm;z`lvvBV)Bln?g(F7+h5MY!On1MJ`W9*o}I*!^jk{&!>^ z^}nw1KAA@#62GqTdBx9@o`8qZ#rOnX>5122`E2wy^IUg_x6|8&kII+vhWH9TX3y*A zRglx(IsDq5$D`U6KG%5KcGJ6!U)Lxea@{8r@49hQEF&T_zW)dEuknv% zFCo2IWA*^jSp1)l5i8mMQ;ly60)7B|l-B=H7^z=!6db&-Yp6=79rziF4=_P%7dP|<3^7Jc}T66$4DUnqr z&w7PVdJ3nz%ZA*iEaN_9L+?|Td7rXj_bJP|Pg!fv+oUvDqVpe=vw?-H{fM?626h!y-xh9 z&Q!nMkK#Faf%iBbdq0Io*3aO^GArr7c>mSg!fM*C9v`1)cYV=& z2~VP5VO{+mE9(GWS-;NeI*OOpSH17Bx=vwf&a%RO;QfX7HmmHfSZ9~l_i?Fc@uhvM0KxXHt7bs>JLOUzg^j_2G}rq)cr?{pK-y(i;e z`ayh3cbYD|NI!%J={e>RyhT5TkLXY09r{0+PvH&v2|Pi6mgnKWfcNL8@c8_Bo`FA& zhv#1wJsCL}MDX*x3GdFBOqbHMF<;gin>GG5ji1$ci^khD{#A{?r14f_%aidJH1``C zKd12yjdz;gj#Nc6)0d_1T*$U(UV0VHT5?2j?NjqnRw^u+r@ds>x;J+-=4Prfy@UsHRn9=d`VSF zTgmxp`%B&(Gk@CtY5T`49dlvKd!=oqy`{Iu=8fGm_HbEo*Y&cxvUBZA$}WxT8MkuW z#VJ|iZkBH@-#I>KeDV02@sy0eRI#*uNyWy>j>>tJ@3b$eyk51teM$S0s)N;a?MtdV ztM^yGT9Z*zRGbKdF_qbwYBdO-$+Cg>*{jrauZt;*AllUtemiI!Y%S8 zbw@<{y3_TuntJOO)xT1IrlF;&w_$d}apE@`8yb5W4>z7`>Y!F%)BDXiO}8hmY|fdu zu^FxLDQ;ffe5ZL+^L64olQJf)nzXH@yJbnsk(Spd7q?bSu9^J&QF z(L;}(omVoib>5zNuRfOZSk+^jAKU%d&G}jLx6eQDiOf%wf8x|9PAyol;FSfhe6sG7 z7sJo>PhMY`v#@tz-@?^=HZ44|@cQG;k1u?D!y-A0$*z!r1zYVki!XMp&6jx*NO2@ zx=4A7kJrIHysCfKkMZo7VFJ=okuSli`T+BN)cX%qH!J7<*x`0{@h z+xfb8fpgaf*vLB^0W(ZFe)n6DZ9SgcFPN+R;^rpr=j*i7?HteIo1FIq;-CBx;%+;a zc&2@nc$S?<{E&T&c($ES{ILB5agSZ#Mb#ttH`C^NL-9d=0H5H;>`8p=ek1xPU=i^E zuHQ%OpYolK=kPyJKj5dxS@Bu!rQs3$`}SN^kTg7u;|<*YnWm59(fiHlC9V0#_AK>J zXj&;pUy2?fmo2`^@%p<9AHLsGpS^#IXWqYzURDa<6K~+r-;`F-vw}q0)C=&RlOBZ+ z^Mm*<7w_cX#=E%q6aOI|gujBn;J`!h*YODaDn5RHh*#ggrA--L(ZwhFD|kHrj{O0? zhIiv%*m)QJn(t5ekJN|oxA7eOT|5PUA0NTu9r#E11O99L0AGPhmikoxDt^?zj`!gc zco%*P&%ytbl61RAeFy(I`Zwfk^e4m-@oda@CjQv*!j5O-D z79Kb2NE zh50!7{d43#81;MM*z+Q3;hXMS^zbXho-IBSuJDRm=x09~5Ux>9PbHj7I)z4OzYBBZ z9+&d${J^twy5@9g-ptv9OiiSPR)$~W4KVtrNXP?ySe-qbH0`$NAiU+ z?>w33t-zWHogEq?Jv-z>eeFZf1~1yP!F?2q^vseEb(bqmk8?jWsi&a_4fHTiB~T*o zfHXZtgjPyhi3QE~sg}{NGWjSPOOY?isWO!I;am3Fz2n}F7A5d54qwU#Z+n&?SJ!ZT zct2(3q=io0aeVLsxjY|X7Ta~2c6*47KDz~owdoOXmZp{Fx)#w(s}%WBJVydHYZGgChDd5KMf>x}JSXp*%1 zt#3HW@Zz`C@Os+U*j-kvi*@7&pIg@%&vu<54)VvyADcB#^M)RquKmK3Q0lmM?F1u$ zjMZ3Ieb)xAlm=P#UCXGw44TV`10M6dNY_01C}L-wpCxkfEKuolia7@;jKRb_Y|u={i5uglt;<$tm$;^yPu=&7SbYbJrqezdl!sxS0vPwVNTlb`@3!i zR1d&?NXNRL_7X@rDWCr|-m%w_C!Y{m3&Lw$rmYQ; zrCwy}2U9<&-lK?}adifBa_VJrB2S~xp79pQITyg1eAzi;Og%RBm|riHo_h?|p7W(2 zM6XjfLW$6ET{)VL%jBOVFFfH^ok6~j{2Q7_j;THL>qN(iFyBW0&{W^z&1j;oNG}pJ zJK3fdf}w9kl9FZWh#v>HoY$TjZ0@xq4Z*fwCieB%&bvd~Uzd*}w(C^aDQd~HFQMHc zQgE_j%f1AeMS=7gmeZzK(Y}1#+4875rU>Scm~9thQ@dUKe~h+Ad&y zFA%Gqy4ol|OIqm2n-xj5F&Yv`KbWN7w%h#1V0~@dO6{%C+)5nqV1~48C(?T>$IwdACA|3uvu3Erolr*^!dVv90&^wKC=z2_1W(r#-2Zwev#9 z3z|36IUjUvCM_~dcQqAXn&XOyzX+dWjSidA3)&~A-&JS*n&ZZR1_+0#-iSp_zVU@O{*10FSAq@qSX zirCJzoolI8NKUBEf{*E30uprr>>eR2j{G> zfmqweIYQc~R>rs64^=L)0#(eD`J9ZN;eI4M+SX}^Ontd|R`V=caE@)?J&isy*CJD& zYi??8QWRQkJsx*jxR1j}vB!X3(meXe>ZEjSqrTNPz-U;@se>%Erbf+AF$`Q{_IWke~ zy6Sfd??IjN^29Y0-7aoBUhH@gd6rNv^f_JVOg2+CfcAu#$g>O%8P1CVc6;(}Xb@V%U3cX1?jwY2JjJF>PSBFjc221atzzu(Ys9{mCUafecChWB=1se-uwBBF z(C4_fybs2DS0v<~kJNg9X%NfO@~USDwrxJK&!=TSJ4a{Be!c~<5AJ>tEwt<;Cp7gs z`$4$06@fkzVwAQ#38i#msrPA(b>`=DYGfUr)PBo3sDizA7NfU<6WVssWlLQcRJZlm z#+DKdnr|y6ouk2*a#Fu%C-oBt`47l{pjR(?-O>yndZ>?O}yeoCLC>E)Vv59%;DAxt!P2_ zC!zY3$k2M)GZPq9_NM@Y-^2r+ov@*qxu^9)8GM`Z$G**YHeAQ|*tm(ypu*VK9F~vr z7rJx3Xw7c-Q7qEhB_Ge!Y$Gpxen}-wv|l&dt$jFcJjW-j6}8UJ3{pf z(r)teAaA<>Ci6n1;6zb$2|uES%BuZtpIx%tV5A7pk|@#!=zguX=-g zLZk?~E1Jae2ygcPYT3zz{yNvD@iv(2JLeEB!`8SvMp4Gsvyle|ze`a|Pb6@aqSPA? zk$=WBRkt+{m)g~yt$MHOJy+hs?q79LIe2RDVTe zn6#66ShGeOV$yOplx8=4pxCAq8R#Wicu8d#)aEz7MC&ZiG#pi)rurjBgV3KUnajr%i{~OjetabG#FnZM|C|~CC&F_+)Pg;8LjMG^4Zm>=t3H3F0 zmCCy7<7I6~r=1J_Y^}fL+4@_=LH-)~YZJpWSv}Wy^%treoGcR;V}s9X(Aidhg!HQ# zG~e7p`hYL%W+!Vs<0Jv}*-)>hexq@6-em>r*+mGpemQX<(|j*dKVLqI*okjVe2ZG0 z*%WK<`jvHFAyVBBet(t1X(zK~ez{c4hX-ACptZdNg;%5*i)=RON`>aM!b{zYj=$!lsAC2+aV4OL#JU@luuDXb z`g_5E6I&5gy<0d3?+r z;R!d{KL|~-Qqe$7KY8X{({nDLz*0|mo4nJAsa{JSo8)W6OgKdTDEU5Dzp<74KJq=9 zN6HC1(NLRe1^P{Sgc{03%HMF(PhgMW9PN-$dcChL&->&`ZhfR!M=W^uIsI!D-wyuBJ@1EwX&s z=dl26nU91rj^zXt{eiFHU@p%JPO^zoFOn#2sB4hZ41G`JXt0T#26rAdjZvs(`ka1K z>NMQMwsHclzpcCkLylV3VeN%_W+%B9G}c*EdJ6vMeg2{wd5$CZ=GO8Q9BQ?DG+2J6 z@QTX7`2uN7EhnJ*UG=*Z6Z+g^tlui15Me#kudQEO>z{ub`Wl!C^-C!i8Fs3yvp{-X z0Q+rUR%Uj6YkjLKPS+9eb46m!|Hf7a6;^?k3-Y*!rIO9@gm<;Yavgl?MAab|dH;Ax3E(vvceUVyU-F zV;wu0-&Rh8GQYR^lDPTZ!g;li=lh$4>ICZtIm5s?Ve3{gkC-PDE+`VIezo>S9ix-D z0(M3*GvNq%u?oI?oT?&;wenHKPUxE;8eU3HWcjLan85r`^tu4H*U4SG07|V1 zH~-~%maj+NYA$DqqoE$lxd$6wmn5h~u(id+B7?0dN^C_gt_W*0i37PVamKk-d#U!4 ztCcvNI8Ci{h4zWhFXq{S()8XpO@ z9_K2N-n|me5~uZWb=9yB_(3>DDxR#`Uz-EAL4#nn>V=v+Kg@O(GTHfB5p1f)PLtYAmbE)THyA=mOXuf>Bz%LatzlrQV^W?A1Ny`N3y%HS3IEt45nOF#bg{1OKUA&* zPIHy?T0;3wrAhrtuFcE0l)JfasGQjMOL)`KN7KfWD^#I&+|k$h>*nwuC+TyZc`TeUDJKDTVDa*132sgZE!p>; z)Q@nrm7SHHpo@Gye*$JIS^xS(rkigM8FU@-8!1a@Q0z}N*4}Y$o1cGOCv zm0bjlD<8o`;tI~0XU4Mb$bCO4ft(KIY-nEri||{z&qUlcM{ut9&#L3DBL7vSxmqqg zQ<~%6_9ElnF7GbyR>Y1^jAsUvi|rFGf3DIL(vF!|&S}HPC>^&8O1sK46=Usaiwx$8 z?#lKch^%%uLONTGxjZK2`h z9Nq1o^WFW|l;3;A7ea3#^cIfsEnvxQkZzFfF>9dYWNw0b)0ib=mMCJ!T^@HCxq8V7 zx3{Qe#+{>G7HDgTQCe`@vjw-uFz=}Mqoh=vVr+DeFVz4mQgDV=gpwP|OK5OSUvj17 zissF@rIfuzS}6XdlaIgrHYF#0L~!l7j9K)n?nECcPPw*_U%dGDt@xXGLx>bC9C>-< zWm;-~3%WqM3c5zhIgYU?yIywPGb3MB${zkD>95S>f?`lkSm1(*tjv{yjFF5cxeFR6 zM`4%WUzx!vGQ=23LL~O~*cZpXNIRtz!%D?Y#!imitcWdJS+>$MV^@0l0=(ZAAl@^FO^KlVVM zmYcDcs4G@QWch1fVn#pCNGKw4auj~sje>nPWfW4l=W{xiP#W&a`KLTvx~2F!RFr!@ zPf|1(OZoLf-Ua@0M)py6 zub`cK1&jH69l5V)ilNCov;|$G-=jvviD2GW0*l$9BnKbZY5VqOz$?4WowaTJQqFk4@e zk0N%=@iE7txmBnW{+IM<4E8^^#s#oze#_^ev^d6yYCVZ{-sGHTwtmN-tvn=9O@IPvy!1K?4%N{@%%j z&nBCHhFGxoHP#W#KgjtYkkaJuwm(!I4X|OOKk$qnd^tw*bDdEBnd4<@zz86BLSDw?^82e`wx-MwtwX({qe@XI zz3jNU}uEu@7$Poy>V8W`3?5sAazMR$hw{n3zn%6Zj;8sWZI z4WlzhV>8362CN3$Zh>_Bfj@@z}Bo?+~L%gG?S-sgd>75X4@HNyC(>VR`He>W^6Jm_pXO=}l|*>n_+M@PBw zFhyCE%UB5gsN*>51uz0gTFA?cTF=QT;A}>%wC7ag?p&E-p9@cUhF}ZIiG`<)UmArj z3lD?k5&Lo!?#71q7w+a;YmM46Y74ctlM~KEXlX{R#;#+V3t4eK##iA|_Kh>df?=z) zMR-z=x+~+Sd~MuiJ!3H_#yp#Sjo6nYhNiR6$1L9}N#X6n+w2K9d`U7zlESN=$vzBv zS-A=Z^L(zcvUd}UB+0)gu^D-K@8iVa8p=nv1UvF&V&z!yT45R3GhjQ2eYx_vz8$$C z|4F``TuY_T`Tq5-$yT{~Ifu>%mD!4jzFf@IksWew0n3q?fQB--%H*ERTPl~FJlwDE zhTB<%?oRU8iG%Vj#bSVCLjG#6v_p>h)piE}tTX0#ED z#>S^ez{!SLA$OZCzqVA%LYloG=M~!&&XrQ`@cDlWnL`~38A}7Ha^&m2rOBplP3ETn42?|Nmk^DsszIKMNhYUGK z9OPdk|62BSUyfDOJxE$KQ0?Rxg7uUDf>qNpdOl>6ar@0(Ba+R?5$uo^*>0z$SvIzL z$b#(c*|OVW&+^jqu*2EweLe}1bOaV=NFC@hkY7OFSzwd(K6&PT)>@SfHtEft&03bVO!H<$A7%5EFOPJc zROxwOohlO&hcc<{u)D+gka99idxygfS7urK3;3kH;YEhsk&hxa_eL)J(6IM>Uf4EP z^<|LrE+Crx9SmP-tgKC*SZoD3uN?_3I@y z0Rc;`Eq7PW`@&P&bA!RSVM358fz12a@Ml;Hh{h> zJdI$|5}TgAeCV4#c9%5Km$AxDn$)|VsnRT^ob$82Hgt#b7MgR>@%f<}hi-JzWZ%xd z4d0c%H0>fy_EoMt4udXG&Vorxb|kxdXs3_KRnH6fK799W|TsE zxn1tpOG@bGzuYP1mz}=F68o95b8u2K5^O~vhuIG`dDD(>vCWI*(=*yMZ?c%PCK$=- zj=y0n4H`tE=@Jvrk69x-hut&SIx|OTafCWYhFlH#aJDrs4|#it-~X(6S@eI%DW&I` z8PfkO`fup_5Lwd>)k^@?a&T8gQ#ZiMmE$aleU4~6`i{;B`P&7zM-1SF?+l~Co#3P$Pd&I! zZuWU$|G9@QxMw)=YHBMvET$rIjr^>n3BC09+;BLUsms0uSKWLlgP39Wb+j^gG zZ<6oO<-&z~G{U!hAV>9-AsmY+k#pi*r-3xA9>JRSv~c~Was6v*(l(~~>woC&p|`0O ztbeQna$IEwL_yv97Yq@i=g`xQv`&>LweN1_%ipSs{eCz6b^Cykj&6qnfxlJqS5kBX z^!D=6Sv8dY^BX(Sr)TE*92b(qS|~C=*Xmxj%d&j=v0l!e!3mr$xNzB)^XdM}Xo=3%pi_Eh4{d66v3VJQNjub`;HE+ZYMP%ob-YrV% z+TQXJnb&bi6Oy|A8ad%OsIINp{dUo{Jr;1aHKJ>~&+b#i4k;Z{O08f)b(PYqs(bHuNMnfg5PuX z%_FnybNACVXMcYUiLT8db4c?hJwb2wC_T?CN$OhOa0inm#KwMZAV>D3?|=x$L3Pbj zUqi6?GMXK7J&CTxzme<$oWjzMrLkw4z)mj(GiiH4G6}iD&j=>{+=^~)aj(~5#H6I} zPS=0!>-wp|bsem0c8rw%vtu04yh)?~__-6Bo>`XcKU^Imb1ix9byxf1^+@{v)crL6 zal3_{S%ckTc?!ou<+z;K@Hghdw^$HDILGY|$O&Jk_W>(7x)}>apvQhsqnsZYZGT^k zc2O4Sdxhhx`;prhS5Ru~)5HTgo&d4@&EnJd?oZe#BO%E#(x1vPBJ&{N$hC=3j$8(F z9A)(w`$gh`9RCDFIDYY7j*&f3kWdu#F~T)mBr}q!c@ts2+B-_m<0S7mJ_+V5C8@i3 z$uEn9*B1ui)c_wtO7A!&CiTg0JCeOy<#^eCFxR_Pqzung25_|EM@u+<2HO$rzA0x( zi?%hmF+(r*5Vgy#Xib+V$Vq)zpak{ax+X*vJYJ**rt(UH$!@a$jk;-P>Q= z2`xghzqVmOe=TLfXs+>j$>_WOt|4XY6T~nMW~}-Zlm0&8_jkaIHE$v*A<5C4Oy$TG zTax2i#}QiJ<$MHhQwcxT7=LtTJfnSrz>XnUE?h$a5>GoFfWv<4ceW2L`v7^2BqoA z6$AF!Kh>!=oV8NiIyq!L2NH0Kw|o7OSV_6ebs76oe#PL=Q~m-1kH^x+Y=ob*>m>q{fH(Vs>C1p@ynZxq#hiZ5i5)u01{&~VgLdb7?)euXx2emO?z2J=VW zG4q}s>Rq>ub`p26X+sdbEy6#|ZIk{V?19ii`=@+Rpgb>AKh73E&Ud^a(T}42ULO7h zv%G?|rnDxn6rX}qy|Jn<*=ve@%^XC+a*@>h7wNB#K(K3ZUF?a>#T@2K(n`JTw6e5v zFE_0+tI<>}htzo<deNiu1w_JWD!n9x`%z*P0n^ymtXb(~XkCb9-p6O?6o zva8{x**=b~c*?d}PWODb!YOJweG5j~+R0XYmV4U9^-fl5o>KG7Z%Q44{5ILmPv#>j zDFJs9Xq}}d)qKt+#o_vu^INJ=T1${<9epXLl%q|djF*9YSIq3ag^mY@F* ipV1lowsbKaUSrwa{$1-fkjbE_OeCb=NU3`8y#EK5nIdZd literal 0 HcmV?d00001 diff --git a/selfdrive/assets/img_couch.svg b/selfdrive/assets/img_couch.svg new file mode 100644 index 0000000000..5b3c048318 --- /dev/null +++ b/selfdrive/assets/img_couch.svg @@ -0,0 +1,3 @@ + + + diff --git a/selfdrive/assets/img_experimental.svg b/selfdrive/assets/img_experimental.svg new file mode 100644 index 0000000000..0eaec3b3cd --- /dev/null +++ b/selfdrive/assets/img_experimental.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/selfdrive/assets/img_experimental_grey.svg b/selfdrive/assets/img_experimental_grey.svg new file mode 100644 index 0000000000..dc87105ac5 --- /dev/null +++ b/selfdrive/assets/img_experimental_grey.svg @@ -0,0 +1,4 @@ + + + + diff --git a/selfdrive/assets/img_experimental_white.svg b/selfdrive/assets/img_experimental_white.svg new file mode 100644 index 0000000000..ae4f18fde2 --- /dev/null +++ b/selfdrive/assets/img_experimental_white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 84e055752a..669c214746 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -58,7 +58,7 @@ qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_libs) qt_src = ["main.cc", "qt/sidebar.cc", "qt/onroad.cc", "qt/body.cc", "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", "qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc", - "qt/offroad/driverview.cc"] + "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc"] qt_env.Program("_ui", qt_src + [asset_obj], LIBS=qt_libs) if GetOption('test'): qt_src.remove("main.cc") # replaced by test_runner diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 3fe00e6ed9..3f3c9a5885 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -4,6 +4,7 @@ #include #include +#include "selfdrive/ui/qt/offroad/experimental_mode.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/qt/widgets/drive_stats.h" #include "selfdrive/ui/qt/widgets/prime.h" @@ -22,7 +23,8 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { slayout = new QStackedLayout(); main_layout->addLayout(slayout); - home = new OffroadHome(); + home = new OffroadHome(this); + QObject::connect(home, &OffroadHome::openSettings, this, &HomeWindow::openSettings); slayout->addWidget(home); onroad = new OnroadWindow(this); @@ -128,11 +130,24 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { main_layout->addSpacing(25); center_layout = new QStackedLayout(); + // Vertical experimental button and drive stats layout + QWidget* statsAndExperimentalModeButtonWidget = new QWidget(this); + QVBoxLayout* statsAndExperimentalModeButton = new QVBoxLayout(statsAndExperimentalModeButtonWidget); + statsAndExperimentalModeButton->setSpacing(30); + statsAndExperimentalModeButton->setMargin(0); + + ExperimentalModeButton *experimental_mode = new ExperimentalModeButton(this); + QObject::connect(experimental_mode, &ExperimentalModeButton::openSettings, this, &OffroadHome::openSettings); + + statsAndExperimentalModeButton->addWidget(experimental_mode, 1); + statsAndExperimentalModeButton->addWidget(new DriveStats, 1); + + // Horizontal experimental + drive stats and setup widget QWidget* statsAndSetupWidget = new QWidget(this); QHBoxLayout* statsAndSetup = new QHBoxLayout(statsAndSetupWidget); statsAndSetup->setMargin(0); statsAndSetup->setSpacing(30); - statsAndSetup->addWidget(new DriveStats, 1); + statsAndSetup->addWidget(statsAndExperimentalModeButtonWidget, 1); statsAndSetup->addWidget(new SetupWidget); center_layout->addWidget(statsAndSetupWidget); diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h index 6636da56ec..ed1c215467 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -22,6 +22,9 @@ class OffroadHome : public QFrame { public: explicit OffroadHome(QWidget* parent = 0); +signals: + void openSettings(int index = 0, const QString ¶m = ""); + private: void showEvent(QShowEvent *event) override; void hideEvent(QHideEvent *event) override; @@ -45,7 +48,7 @@ public: explicit HomeWindow(QWidget* parent = 0); signals: - void openSettings(); + void openSettings(int index = 0, const QString ¶m = ""); void closeSettings(); public slots: diff --git a/selfdrive/ui/qt/offroad/experimental_mode.cc b/selfdrive/ui/qt/offroad/experimental_mode.cc new file mode 100644 index 0000000000..f73149cdf2 --- /dev/null +++ b/selfdrive/ui/qt/offroad/experimental_mode.cc @@ -0,0 +1,75 @@ +#include "selfdrive/ui/qt/offroad/experimental_mode.h" + +#include +#include +#include +#include + +#include "selfdrive/ui/ui.h" + +ExperimentalModeButton::ExperimentalModeButton(QWidget *parent) : QPushButton(parent) { + chill_pixmap = QPixmap("../assets/img_couch.svg").scaledToWidth(img_width, Qt::SmoothTransformation); + experimental_pixmap = QPixmap("../assets/img_experimental_grey.svg").scaledToWidth(img_width, Qt::SmoothTransformation); + + // go to toggles and expand experimental mode description + connect(this, &QPushButton::clicked, [=]() { emit openSettings(2, "ExperimentalMode"); }); + + setFixedHeight(125); + QHBoxLayout *main_layout = new QHBoxLayout; + main_layout->setContentsMargins(horizontal_padding, 0, horizontal_padding, 0); + + mode_label = new QLabel; + mode_icon = new QLabel; + mode_icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + + main_layout->addWidget(mode_label, 1, Qt::AlignLeft); + main_layout->addWidget(mode_icon, 0, Qt::AlignRight); + + setLayout(main_layout); + + setStyleSheet(R"( + QPushButton { + border: none; + } + + QLabel { + font-size: 45px; + font-weight: 300; + text-align: left; + font-family: JetBrainsMono; + color: #000000; + } + )"); +} + +void ExperimentalModeButton::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.setPen(Qt::NoPen); + p.setRenderHint(QPainter::Antialiasing); + + QPainterPath path; + path.addRoundedRect(rect(), 10, 10); + + // gradient + bool pressed = isDown(); + QLinearGradient gradient(rect().left(), 0, rect().right(), 0); + if (experimental_mode) { + gradient.setColorAt(0, QColor(255, 155, 63, pressed ? 0xcc : 0xff)); + gradient.setColorAt(1, QColor(219, 56, 34, pressed ? 0xcc : 0xff)); + } else { + gradient.setColorAt(0, QColor(20, 255, 171, pressed ? 0xcc : 0xff)); + gradient.setColorAt(1, QColor(35, 149, 255, pressed ? 0xcc : 0xff)); + } + p.fillPath(path, gradient); + + // vertical line + p.setPen(QPen(QColor(0, 0, 0, 0x4d), 3, Qt::SolidLine)); + int line_x = rect().right() - img_width - (2 * horizontal_padding); + p.drawLine(line_x, rect().bottom(), line_x, rect().top()); +} + +void ExperimentalModeButton::showEvent(QShowEvent *event) { + experimental_mode = params.getBool("ExperimentalMode"); + mode_icon->setPixmap(experimental_mode ? experimental_pixmap : chill_pixmap); + mode_label->setText(experimental_mode ? tr("EXPERIMENTAL MODE ON") : tr("CHILL MODE ON")); +} diff --git a/selfdrive/ui/qt/offroad/experimental_mode.h b/selfdrive/ui/qt/offroad/experimental_mode.h new file mode 100644 index 0000000000..bfb7638bbe --- /dev/null +++ b/selfdrive/ui/qt/offroad/experimental_mode.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "common/params.h" + +class ExperimentalModeButton : public QPushButton { + Q_OBJECT + +public: + explicit ExperimentalModeButton(QWidget* parent = 0); + +signals: + void openSettings(int index = 0, const QString &toggle = ""); + +private: + void showEvent(QShowEvent *event) override; + + Params params; + bool experimental_mode; + int img_width = 100; + int horizontal_padding = 30; + QPixmap experimental_pixmap; + QPixmap chill_pixmap; + QLabel *mode_label; + QLabel *mode_icon; + +protected: + void paintEvent(QPaintEvent *event) override; +}; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 85b09dc183..01cb0ea720 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -39,7 +39,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "ExperimentalMode", tr("Experimental Mode"), "", - "../assets/offroad/icon_road.png", + "../assets/img_experimental_white.svg", }, { "ExperimentalLongitudinalEnabled", @@ -100,6 +100,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { } // Toggles with confirmation dialogs + toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg"); toggles["ExperimentalMode"]->setConfirmation(true, true); toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false); @@ -108,6 +109,10 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { }); } +void TogglesPanel::expandToggleDescription(const QString ¶m) { + toggles[param.toStdString()]->showDescription(); +} + void TogglesPanel::showEvent(QShowEvent *event) { updateToggles(); } @@ -299,8 +304,15 @@ void DevicePanel::poweroff() { } void SettingsWindow::showEvent(QShowEvent *event) { - panel_widget->setCurrentIndex(0); - nav_btns->buttons()[0]->setChecked(true); + setCurrentPanel(0); +} + +void SettingsWindow::setCurrentPanel(int index, const QString ¶m) { + panel_widget->setCurrentIndex(index); + nav_btns->buttons()[index]->setChecked(true); + if (!param.isEmpty()) { + emit expandToggleDescription(param); + } } SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { @@ -341,10 +353,13 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView); + TogglesPanel *toggles = new TogglesPanel(this); + QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription); + QList> panels = { {tr("Device"), device}, {tr("Network"), new Networking(this)}, - {tr("Toggles"), new TogglesPanel(this)}, + {tr("Toggles"), toggles}, {tr("Software"), new SoftwarePanel(this)}, }; diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index 4177f28cf4..c63be4e138 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -17,6 +17,7 @@ class SettingsWindow : public QFrame { public: explicit SettingsWindow(QWidget *parent = 0); + void setCurrentPanel(int index, const QString ¶m = ""); protected: void showEvent(QShowEvent *event) override; @@ -25,6 +26,7 @@ signals: void closeSettings(); void reviewTrainingGuide(); void showDriverView(); + void expandToggleDescription(const QString ¶m); private: QPushButton *sidebar_alert_widget; @@ -56,6 +58,9 @@ public: explicit TogglesPanel(SettingsWindow *parent); void showEvent(QShowEvent *event) override; +public slots: + void expandToggleDescription(const QString ¶m); + private: Params params; std::map toggles; diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index fcf29181e7..50f891dd56 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -174,6 +174,7 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* par pm = std::make_unique>({"uiDebug"}); engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); + experimental_img = loadPixmap("../assets/img_experimental.svg", {img_size - 5, img_size - 5}); dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size}); } @@ -378,8 +379,9 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { // engage-ability icon if (engageable) { + SubMaster &sm = *(uiState()->sm); drawIcon(p, rect().right() - radius / 2 - bdr_s * 2, radius / 2 + int(bdr_s * 1.5), - engage_img, bg_colors[status], 1.0); + sm["controlsState"].getControlsState().getExperimentalMode() ? experimental_img : engage_img, blackColor(166), 1.0); } // dm icon @@ -409,7 +411,7 @@ void AnnotatedCameraWidget::drawIcon(QPainter &p, int x, int y, QPixmap &img, QB p.setBrush(bg); p.drawEllipse(x - radius / 2, y - radius / 2, radius, radius); p.setOpacity(opacity); - p.drawPixmap(x - img_size / 2, y - img_size / 2, img); + p.drawPixmap(x - img.size().width() / 2, y - img.size().height() / 2, img); } diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 7edca6b3d5..9e18355970 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -51,6 +51,7 @@ private: void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); QPixmap engage_img; + QPixmap experimental_img; QPixmap dm_img; const int radius = 192; const int img_size = (radius / 2) * 1.5; diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index 53ad7467ac..fb96e1d540 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -20,7 +20,7 @@ public: explicit Sidebar(QWidget* parent = 0); signals: - void openSettings(); + void openSettings(int index = 0, const QString ¶m = ""); void valueChanged(); public slots: diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index 04ce15ef23..198b1edbf6 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -53,6 +53,7 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { QFontDatabase::addApplicationFont("../assets/fonts/Inter-Regular.ttf"); QFontDatabase::addApplicationFont("../assets/fonts/Inter-SemiBold.ttf"); QFontDatabase::addApplicationFont("../assets/fonts/Inter-Thin.ttf"); + QFontDatabase::addApplicationFont("../assets/fonts/JetBrainsMono-Medium.ttf"); // no outline to prevent the focus rectangle setStyleSheet(R"( @@ -64,8 +65,9 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_NoSystemBackground); } -void MainWindow::openSettings() { +void MainWindow::openSettings(int index, const QString ¶m) { main_layout->setCurrentWidget(settingsWindow); + settingsWindow->setCurrentPanel(index, param); } void MainWindow::closeSettings() { diff --git a/selfdrive/ui/qt/window.h b/selfdrive/ui/qt/window.h index 0bd328aa8a..71fc466c20 100644 --- a/selfdrive/ui/qt/window.h +++ b/selfdrive/ui/qt/window.h @@ -15,7 +15,7 @@ public: private: bool eventFilter(QObject *obj, QEvent *event) override; - void openSettings(); + void openSettings(int index = 0, const QString ¶m = ""); void closeSettings(); Device device; diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 21fdc48fef..963eeadd81 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -281,6 +281,17 @@ カメラを起動しています
+ + ExperimentalModeButton + + EXPERIMENTAL MODE ON + + + + CHILL MODE ON + + + InputDialog diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 57c688ffe6..9defc2c36f 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -281,6 +281,17 @@ 카메라 시작중 + + ExperimentalModeButton + + EXPERIMENTAL MODE ON + + + + CHILL MODE ON + + + InputDialog diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 2d7195e0d2..a1c966da45 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -281,6 +281,17 @@ câmera iniciando + + ExperimentalModeButton + + EXPERIMENTAL MODE ON + + + + CHILL MODE ON + + + InputDialog diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index fb9b6dd6f5..e77b3ef63d 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -281,6 +281,17 @@ 正在启动相机 + + ExperimentalModeButton + + EXPERIMENTAL MODE ON + + + + CHILL MODE ON + + + InputDialog diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 86d5482355..f667fdc978 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -281,6 +281,17 @@ 開啟相機中 + + ExperimentalModeButton + + EXPERIMENTAL MODE ON + + + + CHILL MODE ON + + + InputDialog From 1899d439f4aaf8f218ad7d40d8d70bec0d6f151a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 23:11:53 -0800 Subject: [PATCH 0315/1179] Multilang: refactor experimental description (#26518) * refactor e2e description * forgot to update --- selfdrive/ui/qt/offroad/settings.cc | 23 +++++++++++------------ selfdrive/ui/translations/main_ja.ts | 24 ++++++++++++++++++++---- selfdrive/ui/translations/main_ko.ts | 24 ++++++++++++++++++++---- selfdrive/ui/translations/main_pt-BR.ts | 24 ++++++++++++++++++++---- selfdrive/ui/translations/main_zh-CHS.ts | 24 ++++++++++++++++++++---- selfdrive/ui/translations/main_zh-CHT.ts | 24 ++++++++++++++++++++---- 6 files changed, 111 insertions(+), 32 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 01cb0ea720..330f636e2b 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -120,18 +120,17 @@ void TogglesPanel::showEvent(QShowEvent *event) { void TogglesPanel::updateToggles() { auto e2e_toggle = toggles["ExperimentalMode"]; auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"]; - const QString e2e_description = tr("\ - openpilot defaults to driving in chill mode.\ - Experimental mode enables alpha-level features that aren't ready for chill mode. \ - Experimental features are listed below: \ -
\ -

🌮 End-to-End Longitudinal Control 🌮

\ - 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. \ -
\ -

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.\ - "); + const QString e2e_description = QString("%1
" + "

%2


" + "%3
" + "

%4


" + "%5") + .arg(tr("openpilot defaults to driving in chill mode. Experimental mode enables alpha-level features that aren't ready for chill mode. Experimental features are listed below:")) + .arg(tr("🌮 End-to-End Longitudinal Control 🌮")) + .arg(tr("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.")) + .arg(tr("New Driving Visualization")) + .arg(tr("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.");) auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 963eeadd81..2e01ce0dd1 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1017,10 +1017,6 @@ 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. - - Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. @@ -1029,6 +1025,26 @@ location set 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: + + + + 🌮 End-to-End Longitudinal Control 🌮 + + + + 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. + + + + 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. + +
Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 9defc2c36f..8ce618edff 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1017,10 +1017,6 @@ 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. - - Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. @@ -1029,6 +1025,26 @@ location set 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: + + + + 🌮 End-to-End Longitudinal Control 🌮 + + + + 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. + + + + 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. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index a1c966da45..2dc1538017 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1021,10 +1021,6 @@ trabalho definido 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. - - Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. @@ -1033,6 +1029,26 @@ trabalho definido 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: + + + + 🌮 End-to-End Longitudinal Control 🌮 + + + + 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. + + + + 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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index e77b3ef63d..fe569e1fb0 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1015,10 +1015,6 @@ 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. - - Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. @@ -1027,6 +1023,26 @@ location set 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: + + + + 🌮 End-to-End Longitudinal Control 🌮 + + + + 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. + + + + 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. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index f667fdc978..3ec67f3961 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1017,10 +1017,6 @@ 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 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: <br> <h4>🌮 End-to-End Longitudinal Control 🌮</h4> 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. <br> <h4>New Driving Visualization</h4> 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. - - Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. @@ -1029,6 +1025,26 @@ location set 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: + + + + 🌮 End-to-End Longitudinal Control 🌮 + + + + 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. + + + + 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. + + Updater From d8bc69c788c581485ac9e65e8f6d06e4c368935c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 15 Nov 2022 23:52:47 -0800 Subject: [PATCH 0316/1179] Multilang: add missing translations (#26519) * add back missing japanese translations that haven't been changed * other languages * fix --- selfdrive/ui/qt/offroad/settings.cc | 2 +- selfdrive/ui/translations/main_ja.ts | 4 ++-- selfdrive/ui/translations/main_ko.ts | 4 ++-- selfdrive/ui/translations/main_pt-BR.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHS.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHT.ts | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 330f636e2b..bde8628dc4 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -130,7 +130,7 @@ void TogglesPanel::updateToggles() { .arg(tr("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.")) .arg(tr("New Driving Visualization")) - .arg(tr("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.");) + .arg(tr("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.")); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 2e01ce0dd1..ebf40cc5c5 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1027,11 +1027,11 @@ location set 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: - + openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。 🌮 End-to-End Longitudinal Control 🌮 - + 🌮 エンドツーエンドアクセル制御 🌮 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. diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 8ce618edff..98d46149dd 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1027,11 +1027,11 @@ location set 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: - + openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 🌮 End-to-End Longitudinal Control 🌮 - + 🌮 E2E 롱컨트롤 🌮 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. diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 2dc1538017..4a698947f1 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1031,11 +1031,11 @@ trabalho definido 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: - + openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: 🌮 End-to-End Longitudinal Control 🌮 - + 🌮 Controle Longitudinal de Ponta a Ponta 🌮 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. diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index fe569e1fb0..dc94fbc953 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1025,11 +1025,11 @@ location set 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: - + openpilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: 🌮 End-to-End Longitudinal Control 🌮 - + 🌮 端到端(End-to-End) 纵向控制 🌮 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. diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 3ec67f3961..46fb5578a3 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1027,11 +1027,11 @@ location set 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: - + openpilot 默認以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: 🌮 End-to-End Longitudinal Control 🌮 - + 🌮端到端縱向控制🌮 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. From fe2368c9eb14ee49eb59af6d892becdb4d449443 Mon Sep 17 00:00:00 2001 From: Oxygen Date: Wed, 16 Nov 2022 19:11:45 +0800 Subject: [PATCH 0317/1179] Updated main_zh-CHS.ts (#26524) --- selfdrive/ui/translations/main_zh-CHS.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index dc94fbc953..31202e45f2 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -285,11 +285,11 @@ ExperimentalModeButton EXPERIMENTAL MODE ON - + 试验模式运行 CHILL MODE ON - + 轻松模式运行 @@ -1013,15 +1013,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纵向控制。当使用试验性的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: @@ -1033,15 +1033,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 e099e42147af23a700bf4b64e08540574aa1d285 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 16 Nov 2022 18:12:31 +0100 Subject: [PATCH 0318/1179] 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 0319/1179] 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 0320/1179] 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 0321/1179] 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 0322/1179] 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 0323/1179] 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 0324/1179] 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 0325/1179] 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 0326/1179] 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 0327/1179] 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 | 322 +++++++++++++++++++++++------------ tools/cabana/chartswidget.h | 52 ++++-- tools/cabana/signaledit.cc | 7 +- tools/cabana/signaledit.h | 2 +- 4 files changed, 256 insertions(+), 127 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 +#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)); - 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; + 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; } - value_text->setPos(text_x, pos.y() - 10); } - item_group->setVisible(value != vals.end()); + + 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()); + int text_x = pos.x() + 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() - text_rect.height() / 2); + track_ellipse->setRect(pos.x() - 5, pos.y() - 5, 10, 10); + } + 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 0328/1179] 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 0329/1179] 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 From 0b79ba8acb99f6c1dc3957a985229e3d5a15892b Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Sat, 19 Nov 2022 19:20:41 -0300 Subject: [PATCH 0330/1179] Multilang: Update pt-BR translations (#26549) * update pt-BR translations * fix some cutoff texts * update pt-BR translation --- selfdrive/ui/translations/main_pt-BR.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 4a698947f1..105d6f77f0 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -285,11 +285,11 @@ ExperimentalModeButton EXPERIMENTAL MODE ON - + MODO EXPERIMENTAL ATIVADO CHILL MODE ON - + MODO CHILL ATIVADO
@@ -1019,15 +1019,15 @@ trabalho definido 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. - + Neste carro o penpilot por padrão utiliza o ACC nativo do veículo ao invés de controlar longitudinalmente. Ative isto para mudar para o controle longitudinal do openpilot. Ativar o Modo Experimental é recomendado quando em uso do controle longitudinal experimental do openpilot. Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. - + O Modo Experimental está atualmente indisponível para este carro, já que o ACC original do carro é usado para controle longitudinal. Enable experimental longitudinal control to allow experimental mode. - + Ative o controle longitudinal experimental para permitir o modo experimental. 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: @@ -1039,15 +1039,15 @@ trabalho definido 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. - + Deixe o modelo de IA controlar o acelerador e os freios. O openpilot irá dirigir como pensa que um humano faria, incluindo parar em sinais vermelhos e sinais de parada. Uma vez que o modelo de condução decide a velocidade a conduzir, a velocidade definida apenas funcionará como um limite superior. Este é um recurso de qualidade alfa; erros devem ser esperados. New Driving Visualization - + Nova Visualização de Condução 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. - + A visualização da direção fará a transição para a câmera grande angular voltada para a estrada em baixas velocidades para mostrar melhor algumas curvas. O logotipo do modo Experimental também será exibido no canto superior direito. From c3822bdddadab3c24e9275ea5037cff96456f2fb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 19 Nov 2022 14:43:20 -0800 Subject: [PATCH 0331/1179] bump to 0.9.1 --- RELEASES.md | 5 +++++ common/version.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index e15286c5f0..97c92dfa47 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,8 @@ +Version 0.9.1 (2022-12-XX) +======================== +* New driving model + + Version 0.9.0 (2022-11-21) ======================== * New driving model diff --git a/common/version.h b/common/version.h index 74a56a7c1b..7b5764785a 100644 --- a/common/version.h +++ b/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.9.0" +#define COMMA_VERSION "0.9.1" From 649663e06d43a6d1b05fe83120391f3bd2401b8f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 19 Nov 2022 14:45:34 -0800 Subject: [PATCH 0332/1179] body: add can fingerprint (#26548) --- selfdrive/car/body/values.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/selfdrive/car/body/values.py b/selfdrive/car/body/values.py index 66f1b947a8..418835a3e9 100644 --- a/selfdrive/car/body/values.py +++ b/selfdrive/car/body/values.py @@ -26,6 +26,12 @@ CAR_INFO: Dict[str, CarInfo] = { CAR.BODY: CarInfo("comma body", package="All"), } +FINGERPRINTS = { + CAR.BODY: [{ + 513: 8, 516: 8, 514: 3, 515: 4, + }], +} + FW_QUERY_CONFIG = FwQueryConfig( requests=[ Request( From 5b8aed2ebf80ba0875ed21b8130a6ab7451e5740 Mon Sep 17 00:00:00 2001 From: Igor Biletskyy Date: Sun, 20 Nov 2022 11:44:04 -0800 Subject: [PATCH 0333/1179] body: fix UDS reqests (#26552) * bump body * add new fw version --- body | 2 +- selfdrive/car/body/values.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/body b/body index 04aeb30ce0..dc780f858c 160000 --- a/body +++ b/body @@ -1 +1 @@ -Subproject commit 04aeb30ce0bb14759989cd374158233877e1e151 +Subproject commit dc780f858c1ef641471d09b72569e199e3e10acb diff --git a/selfdrive/car/body/values.py b/selfdrive/car/body/values.py index 418835a3e9..548039bc70 100644 --- a/selfdrive/car/body/values.py +++ b/selfdrive/car/body/values.py @@ -46,10 +46,13 @@ FW_VERSIONS = { CAR.BODY: { (Ecu.engine, 0x720, None): [ b'0.0.01', - b'02/27/2022' + b'02/27/2022', + b'0.3.00a', ], + # git hash of the firmware used (Ecu.debug, 0x721, None): [ - b'166bd860' # git hash of the firmware used + b'166bd860', + b'dc780f85', ], }, } From 17b1839e0a358302e049f37f5c843532fb9c7f26 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 21 Nov 2022 05:23:59 +0800 Subject: [PATCH 0334/1179] Cabana: faster align charts, visual glitches removed. (#26543) * faster adjust chart margins * delay adjust * update foreground after set margins * set display range on create * fix init display_range * common function updateDisplayRange * set min max to 0 if no values * fix axis y * use mapToValue * cleanup * get minmax from series * cleanup * cleanup eventsMerged * cleanup include --- tools/cabana/chartswidget.cc | 119 ++++++++++++++++------------------- tools/cabana/chartswidget.h | 2 +- 2 files changed, 54 insertions(+), 67 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5a129b5f61..bc1f1e2a38 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -54,13 +54,25 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { void ChartsWidget::eventsMerged() { if (auto events = can->events(); events && !events->empty()) { - auto it = std::find_if(events->begin(), events->end(), [=](const Event *e) { return e->which == cereal::Event::Which::CAN; }); - event_range.first = it == events->end() ? 0 : (*it)->mono_time / (double)1e9 - can->routeStartTime(); - event_range.second = it == events->end() ? 0 : events->back()->mono_time / (double)1e9 - can->routeStartTime(); - if (display_range.first == 0 && event_range.second == 0) { - display_range.first = event_range.first; - display_range.second = std::min(event_range.first + settings.max_chart_x_range, event_range.second); - } + event_range.first = (events->front()->mono_time / (double)1e9) - can->routeStartTime(); + event_range.second = (events->back()->mono_time / (double)1e9) - can->routeStartTime(); + updateDisplayRange(); + } +} + +void ChartsWidget::updateDisplayRange() { + auto prev_range = display_range; + double current_sec = can->currentSec(); + if (current_sec < display_range.first || current_sec >= (display_range.second - 5)) { + // reached the end, or seeked to a timestamp out of range. + display_range.first = current_sec - 5; + } + display_range.first = std::max(display_range.first, event_range.first); + display_range.second = std::min(display_range.first + settings.max_chart_x_range, event_range.second); + if (prev_range != display_range) { + QFutureSynchronizer future_synchronizer; + for (auto c : charts) + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::setEventsRange, display_range)); } } @@ -79,24 +91,10 @@ void ChartsWidget::zoomReset() { void ChartsWidget::updateState() { if (charts.isEmpty()) return; - const double current_sec = can->currentSec(); - if (is_zoomed) { - if (current_sec < zoomed_range.first || current_sec >= zoomed_range.second) { - can->seekTo(zoomed_range.first); - } - } else { - auto prev_range = display_range; - if (current_sec < display_range.first || current_sec >= (display_range.second - 5)) { - // line marker reached the end, or seeked to a timestamp out of range. - display_range.first = current_sec - 5; - } - display_range.first = std::max(display_range.first, event_range.first); - display_range.second = std::min(display_range.first + settings.max_chart_x_range, event_range.second); - if (prev_range != display_range) { - QFutureSynchronizer future_synchronizer; - for (auto c : charts) - future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::setEventsRange, display_range)); - } + if (!is_zoomed) { + updateDisplayRange(); + } else if (can->currentSec() < zoomed_range.first || can->currentSec() >= zoomed_range.second) { + can->seekTo(zoomed_range.first); } const auto &range = is_zoomed ? zoomed_range : display_range; @@ -122,15 +120,14 @@ ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { } 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 { + setUpdatesEnabled(false); + if (show) { ChartView *chart = merge && charts.size() > 0 ? charts.back() : nullptr; if (!chart) { chart = new ChartView(this); chart->setEventsRange(display_range); + auto range = is_zoomed ? zoomed_range : display_range; + chart->setDisplayRange(range.first, range.second); QObject::connect(chart, &ChartView::remove, [=]() { removeChart(chart); }); QObject::connect(chart, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); @@ -140,9 +137,11 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo } chart->addSeries(id, sig); emit chartOpened(id, sig); - updateState(); + } else if (ChartView *chart = findChart(id, sig)) { + chart->removeSeries(id, sig); } updateToolBar(); + setUpdatesEnabled(true); } void ChartsWidget::removeChart(ChartView *chart) { @@ -175,8 +174,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { 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}); + chart->setMargins(QMargins(20, 11, 11, 11)); track_line = new QGraphicsLineItem(chart); track_line->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); @@ -200,21 +198,12 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { setRubberBand(QChartView::HorizontalRubberBand); updateFromSettings(); - 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, this, &ChartView::remove); - QObject::connect(chart, &QChart::plotAreaChanged, [=](const QRectF &plotArea) { - // use a singleshot timer to avoid recursion call. - timer->start(); - }); } ChartView::~ChartView() { @@ -300,7 +289,6 @@ void ChartView::updateTitle() { void ChartView::updateFromSettings() { setFixedHeight(settings.chart_height); chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark); - auto color = chart()->titleBrush().color(); } void ChartView::setEventsRange(const std::pair &range) { @@ -320,18 +308,19 @@ void ChartView::setDisplayRange(double min, double max) { void ChartView::adjustChartMargins() { // TODO: Remove hardcoded aligned_pos const int aligned_pos = 60; - if (chart()->plotArea().left() != aligned_pos) { + if ((int)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)); + chart()->setMargins(QMargins(left_margin, 11, 11, 11)); + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } } void ChartView::updateSeries(const Signal *sig) { auto events = can->events(); - if (!events) return; + if (!events || sigs.isEmpty()) return; - for (int i = 0; i < sigs.size(); ++i) { - if (auto &s = sigs[i]; !sig || s.sig == sig) { + for (auto &s : sigs) { + if (!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(); @@ -357,9 +346,7 @@ void ChartView::updateSeries(const Signal *sig) { } } } - - QLineSeries *series = (QLineSeries *)chart()->series()[i]; - series->replace(s.vals); + s.series->replace(s.vals); } } updateAxisY(); @@ -367,6 +354,8 @@ void ChartView::updateSeries(const Signal *sig) { // auto zoom on yaxis void ChartView::updateAxisY() { + if (sigs.isEmpty()) return; + 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()}) { @@ -376,17 +365,16 @@ void ChartView::updateAxisY() { } } else { 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(); + for (int i = 0; i < s.series->count(); ++i) { + double y = s.series->at(i).y(); + if (y < min_y) min_y = y; + if (y > max_y) max_y = y; + } } } + if (min_y == std::numeric_limits::max()) min_y = 0; + if (max_y == std::numeric_limits::lowest()) max_y = 0; if (max_y == min_y) { axis_y->setRange(min_y - 1, max_y + 1); } else { @@ -394,6 +382,8 @@ void ChartView::updateAxisY() { axis_y->setRange(min_y - range * 0.05, max_y + range * 0.05); axis_y->applyNiceNumbers(); } + + QTimer::singleShot(0, this, &ChartView::adjustChartMargins); } void ChartView::leaveEvent(QEvent *event) { @@ -406,9 +396,8 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && rubber && rubber->isVisible()) { rubber->hide(); QRectF rect = rubber->geometry().normalized(); - rect.translate(-chart()->plotArea().topLeft()); - 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()); + double min = chart()->mapToValue(rect.topLeft()).x(); + double max = chart()->mapToValue(rect.bottomRight()).x(); if (rubber->width() <= 0) { // no rubber dragged, seek to mouse position can->seekTo(min); @@ -431,8 +420,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { 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(); + double sec = chart()->mapToValue(ev->pos()).x(); QStringList text_list; QPointF pos = plot_area.bottomRight(); double tm = 0.0; @@ -467,8 +455,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *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()); + qreal x = chart()->mapToPosition(QPointF{can->currentSec(), 0}).x(); 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 8f0af95b1a..c8e5a1040c 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -93,6 +92,7 @@ signals: private: void eventsMerged(); void updateState(); + void updateDisplayRange(); void zoomIn(double min, double max); void zoomReset(); void updateToolBar(); From de443d30b37aa5d8b15c94749399d836155bcf60 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 22 Nov 2022 02:47:36 +0800 Subject: [PATCH 0335/1179] Cabana: 'edit-find' icon is not avaible on some platforms (#26561) Fixed edit-find icon is not avaible on some platforms --- tools/cabana/signaledit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 93b7aa88f7..5d627a49da 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -95,7 +95,7 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa plot_btn->setAutoRaise(true); title_layout->addWidget(plot_btn); auto seek_btn = new QToolButton(this); - seek_btn->setIcon(QIcon::fromTheme("edit-find")); + seek_btn->setText("🔍"); seek_btn->setAutoRaise(true); seek_btn->setToolTip(tr("Find signal values")); title_layout->addWidget(seek_btn); From 89eeb72dbdb82258fdd26d7260f0c6455a371bf1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 22 Nov 2022 02:47:47 +0800 Subject: [PATCH 0336/1179] Cabana: update chart and video position (after a click) in pause mode (#26560) update chart and video position (after a click) in pause mode --- tools/cabana/canmessages.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 3bcaae4bbd..a8e881c5fe 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -124,6 +124,7 @@ const std::deque CANMessages::messages(const QString &id) { void CANMessages::seekTo(double ts) { replay->seekTo(std::max(double(0), ts), false); counters_begin_sec = 0; + emit updated(); } void CANMessages::settingChanged() { From 2b4b0cc67f59c896caf32fd937ad6ebf0f7ae640 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 22 Nov 2022 02:47:58 +0800 Subject: [PATCH 0337/1179] Replay: fixed the freq of video and events are unstable after changing the replay speed (#26559) fix freq is unstable after changing the replay speed --- tools/replay/replay.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 1337a4ef2c..1464a6cf57 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -358,6 +358,7 @@ void Replay::publishFrame(const Event *e) { void Replay::stream() { cereal::Event::Which cur_which = cereal::Event::Which::INIT_DATA; + double prev_replay_speed = 1.0; std::unique_lock lk(stream_lock_); while (true) { @@ -397,10 +398,11 @@ void Replay::stream() { long rtime = nanos_since_boot() - loop_start_ts; long behind_ns = etime - rtime; // if behind_ns is greater than 1 second, it means that an invalid segemnt is skipped by seeking/replaying - if (behind_ns >= 1 * 1e9) { - // reset start times + if (behind_ns >= 1 * 1e9 || speed_ != prev_replay_speed) { + // reset event start times evt_start_ts = cur_mono_time_; loop_start_ts = nanos_since_boot(); + prev_replay_speed = speed_; } else if (behind_ns > 0 && !hasFlag(REPLAY_FLAG_FULL_SPEED)) { precise_nano_sleep(behind_ns); } From 7b46928fc9cda9e5200d72c15253f60981eedc74 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 22 Nov 2022 02:48:08 +0800 Subject: [PATCH 0338/1179] Cabana: fix auto zoom y-axis for multiple line series (#26558) auto zoom y-axis for multiple series --- tools/cabana/chartswidget.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index bc1f1e2a38..3029d9db89 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -365,10 +365,10 @@ void ChartView::updateAxisY() { } } else { for (auto &s : sigs) { - for (int i = 0; i < s.series->count(); ++i) { - double y = s.series->at(i).y(); - if (y < min_y) min_y = y; - if (y > max_y) max_y = y; + auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); + for (auto it = begin; it != s.vals.end() && it->x() <= axis_x->max(); ++it) { + if (it->y() < min_y) min_y = it->y(); + if (it->y() > max_y) max_y = it->y(); } } } From efbfbc062280063b1cde744a97ecde5abb711784 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 22 Nov 2022 02:48:19 +0800 Subject: [PATCH 0339/1179] Cabana: display dashes if no value available (#26557) show dot if no value --- tools/cabana/chartswidget.cc | 45 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3029d9db89..5d530a8c8a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -420,34 +420,35 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { const auto plot_area = chart()->plotArea(); if (!is_zooming && plot_area.contains(ev->pos())) { - double sec = chart()->mapToValue(ev->pos()).x(); QStringList text_list; - QPointF pos = plot_area.bottomRight(); - double tm = 0.0; - + QPointF pos = {}; + const double sec = chart()->mapToValue(ev->pos()).x(); 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; + QString value = "--"; + // use reverse iterator to find last item <= sec. + auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); + if (it != s.vals.rend() && it->x() >= axis_x->min()) { + value = QString::number(it->y()); + auto value_pos = chart()->mapToPosition(*it); + if (value_pos.x() > pos.x()) pos = value_pos; } + text_list.push_back(QString(" %1 : %2 ").arg(sigs.size() > 1 ? s.sig->name.c_str() : "Value").arg(value)); } + if (pos.x() == 0) pos = ev->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()); - int text_x = pos.x() + 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() - text_rect.height() / 2); - track_ellipse->setRect(pos.x() - 5, pos.y() - 5, 10, 10); + QString time = QString::number(chart()->mapToValue(pos).x(), 'f', 3); + value_text->setHtml(QString("
 Time: %1  
%2
") + .arg(time).arg(text_list.join("
"))); + + QRectF text_rect = value_text->boundingRect(); + int text_x = pos.x() + 8; + if ((text_x + text_rect.width()) > plot_area.right()) { + text_x = pos.x() - text_rect.width() - 8; } - item_group->setVisible(!text_list.isEmpty()); + value_text->setPos(text_x, pos.y() - text_rect.height() / 2); + track_line->setLine(pos.x(), plot_area.top(), pos.x(), plot_area.bottom()); + track_ellipse->setRect(pos.x() - 5, pos.y() - 5, 10, 10); + item_group->setVisible(true); } else { item_group->setVisible(false); } From 96c9b8c50e0413ba92e7729e1820884d88598989 Mon Sep 17 00:00:00 2001 From: protonchang <2095341+protonchang@users.noreply.github.com> Date: Tue, 22 Nov 2022 02:48:30 +0800 Subject: [PATCH 0340/1179] Update CHT translations (#26537) * Add missing translations * Fix some CHS -> CHT wording --- selfdrive/ui/translations/main_zh-CHT.ts | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 46fb5578a3..0379e926c4 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -113,7 +113,7 @@ Decline, uninstall %1 - 拒絕並卸載 %1 + 拒絕並解除安裝 %1
@@ -132,7 +132,7 @@ Driver Camera - 駕駛員攝像頭 + 駕駛員監控鏡頭 PREVIEW @@ -285,11 +285,11 @@ ExperimentalModeButton EXPERIMENTAL MODE ON - + 實驗模式 ON CHILL MODE ON - + 輕鬆模式 ON @@ -859,15 +859,15 @@ location set UNINSTALL - 卸載 + 解除安裝 Uninstall %1 - 卸載 %1 + 解除安裝 %1 Are you sure you want to uninstall? - 您確定您要卸載嗎? + 您確定您要解除安裝嗎? CHECK @@ -875,7 +875,7 @@ location set Uninstall - 卸載 + 解除安裝 @@ -1015,19 +1015,19 @@ 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: - openpilot 默認以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: + openpilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: 🌮 End-to-End Longitudinal Control 🌮 @@ -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 5b8f0db3e5dea3b7fcc90250ee7aefb8fa00555b Mon Sep 17 00:00:00 2001 From: ambientocclusion <1399123+ambientocclusion@users.noreply.github.com> Date: Mon, 21 Nov 2022 15:23:02 -0800 Subject: [PATCH 0341/1179] Multilang: add missing Japanese translations (#26556) * Add missing Japanese translations * Update some words --- selfdrive/ui/translations/main_ja.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index ebf40cc5c5..8226dd59f9 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -285,11 +285,11 @@ ExperimentalModeButton EXPERIMENTAL MODE ON - + 実験モード CHILL MODE ON - + チルモード @@ -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によるアクセル制御を利用できます。実験モードと合わせて利用することをお勧めします。 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によるアクセル制御を有効にしてください。 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にアクセルとブレーキを任せます。openpilotは赤信号や一時停止サインでの停止を含み、人間と同じように考えて運転を行います。openpilotが運転速度を決定するため、あなたが設定する速度は上限速度になります。この機能は実験段階のため、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 ded66e6307825d9327c12145e1bc6acd2e835346 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Mon, 21 Nov 2022 15:25:23 -0800 Subject: [PATCH 0342/1179] long_mpc: fix e2e source condition (#26546) * fix long_mpc source param * rm print * add back space for formatting --- selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 6b79813117..79a9ec4f0c 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -352,7 +352,7 @@ class LongitudinalMpc: x_and_cruise = np.column_stack([x, cruise_target]) x = np.min(x_and_cruise, axis=1) - self.source = 'e2e' if x_and_cruise[0,0] < x_and_cruise[0,1] else 'cruise' + self.source = 'e2e' if x_and_cruise[1,0] < x_and_cruise[1,1] else 'cruise' else: raise NotImplementedError(f'Planner mode {self.mode} not recognized in planner update') From 5402e02785ce2dffa404acf888fcc36d3df133fa Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Mon, 21 Nov 2022 20:28:34 -0300 Subject: [PATCH 0343/1179] Lexus UX Hybrid 2020 Fingerprint (#26551) Lexus UX 2020 Fingerprint alex.takeda@gmail.com --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index ba26c7e03b..b4b3ac4131 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -821,6 +821,7 @@ FW_VERSIONS = { b'\x01896637621000\x00\x00\x00\x00', b'\x01896637624000\x00\x00\x00\x00', b'\x01896637626000\x00\x00\x00\x00', + b'\x01896637639000\x00\x00\x00\x00', b'\x01896637648000\x00\x00\x00\x00', b'\x01896637643000\x00\x00\x00\x00', b'\x02896630A07000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', From 62ad278829bbe7e6756f4bb3c44386e9c85d731c Mon Sep 17 00:00:00 2001 From: martinl Date: Tue, 22 Nov 2022 01:34:20 +0200 Subject: [PATCH 0344/1179] Add FPv2: 2022 Subaru Outback Wilderness (#26540) Add FPv2: 2022 Outback Wilderness / @valtou --- selfdrive/car/subaru/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 7a1e9a8a3d..9975e495dd 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -461,6 +461,7 @@ FW_VERSIONS = { b'\xa1 \x08\x02', b'\xa1 \x06\x02', b'\xa1 \x08\x00', + b'\xa1 "\t\x00', ], (Ecu.eps, 0x746, None): [ b'\x9b\xc0\x10\x00', @@ -482,6 +483,7 @@ FW_VERSIONS = { b'\xe2"`p\x07', b'\xf1\x82\xe2,\xa0@\x07', b'\xbc"`q\x07', + b'\xe3,\xa0@\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xa5\xfe\xf7@\x00', From 548888d6341a4f44ea2e4154fb8c820c3fc38e4e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 15:59:42 -0800 Subject: [PATCH 0345/1179] docs: update Toyota DSU footnote (#26568) --- docs/CARS.md | 4 ++-- selfdrive/car/docs_definitions.py | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 59b8145556..a0d22a3d27 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -225,8 +225,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).
-2When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
+1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
+2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
5openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 8e057a1563..6ec9ac5c40 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -73,12 +73,11 @@ CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only"], default class CommonFootnote(Enum): EXP_LONG_AVAIL = CarFootnote( - "Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `master-ci`. " + - "Using openpilot longitudinal may disable Automatic Emergency Braking (AEB).", + "Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. ", Column.LONGITUDINAL, docs_only=True) EXP_LONG_DSU = CarFootnote( - "When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace " + - "stock Adaptive Cruise Control (ACC). NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).", + "By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace " + + "stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).", Column.LONGITUDINAL) From 94aa39bdd406400ab48765d8b50f08e03ecf9eb8 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 16:18:51 -0800 Subject: [PATCH 0346/1179] enable experimental longitudinal control on devel (#26544) --- selfdrive/controls/controlsd.py | 4 ++-- system/version.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index a18bec83a8..a395f85580 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -12,7 +12,7 @@ import cereal.messaging as messaging from common.conversions import Conversions as CV from panda import ALTERNATIVE_EXPERIENCE from system.swaglog import cloudlog -from system.version import is_tested_branch, get_short_branch +from system.version import is_release_branch, get_short_branch from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can from selfdrive.controls.lib.lateral_planner import CAMERA_OFFSET @@ -132,7 +132,7 @@ class Controls: safety_config.safetyModel = car.CarParams.SafetyModel.noOutput self.CP.safetyConfigs = [safety_config] - if is_tested_branch(): + if is_release_branch(): self.CP.experimentalLongitudinalAvailable = False # Write CarParams for radard diff --git a/system/version.py b/system/version.py index f0817b3a9f..6031531556 100644 --- a/system/version.py +++ b/system/version.py @@ -7,7 +7,8 @@ from functools import lru_cache from common.basedir import BASEDIR from system.swaglog import cloudlog -TESTED_BRANCHES = ['devel', 'release3-staging', 'dashcam3-staging', 'release3', 'dashcam3'] +RELEASE_BRANCHES = ['release3-staging', 'dashcam3-staging', 'release3', 'dashcam3'] +TESTED_BRANCHES = RELEASE_BRANCHES + ['devel', 'devel-staging'] training_version: bytes = b"0.2.0" terms_version: bytes = b"2" @@ -96,6 +97,9 @@ def is_comma_remote() -> bool: def is_tested_branch() -> bool: return get_short_branch() in TESTED_BRANCHES +@cache +def is_release_branch() -> bool: + return get_short_branch() in RELEASE_BRANCHES @cache def is_dirty() -> bool: From be3d6527adb3f58500e7c9f2d689b4821c233791 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Mon, 21 Nov 2022 18:22:01 -0600 Subject: [PATCH 0347/1179] Add missing HIGHLANDERH_TSS2 ABS & engine f/w (#26534) `@shakir07#1323` 2020 Highlander Hybrid DongleID/route ce56baaf82559131|2022-11-16--23-54-01 --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index b4b3ac4131..cf37a3c2f2 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1015,6 +1015,7 @@ FW_VERSIONS = { b'\x01F15264873500\x00\x00\x00\x00', b'\x01F152648C6300\x00\x00\x00\x00', b'\x01F152648J4000\x00\x00\x00\x00', + b'\x01F152648J5000\x00\x00\x00\x00', b'\x01F152648J6000\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ @@ -1022,6 +1023,7 @@ FW_VERSIONS = { b'\x01896630EA1000\x00\x00\x00\x00', b'\x01896630EE4000\x00\x00\x00\x00', b'\x01896630EE4100\x00\x00\x00\x00', + b'\x01896630EE5000\x00\x00\x00\x00', b'\x01896630EE6000\x00\x00\x00\x00', b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630E66100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', From 23a7a987f6ab75ebee4dd856ba0a0c179b2f90b0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 21 Nov 2022 17:05:13 -0800 Subject: [PATCH 0348/1179] controlsd: add test around cruise speed gas pressed behavior (#26486) * test * test * debug * test * test * test * clean up * clean up * add test * stash * clean up * clean up * clean up * assert equal --- selfdrive/controls/lib/drive_helpers.py | 4 +-- selfdrive/controls/tests/test_cruise_speed.py | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index bdbdb7023a..f0dc2e9467 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -12,6 +12,7 @@ V_CRUISE_MAX = 145 # kph V_CRUISE_MIN = 8 # kph V_CRUISE_ENABLE_MIN = 40 # kph V_CRUISE_INITIAL = 255 # kph +IMPERIAL_INCREMENT = 1.6 # should be CV.MPH_TO_KPH, but this causes rounding errors MIN_SPEED = 1.0 LAT_MPC_N = 16 @@ -73,8 +74,7 @@ class VCruiseHelper: long_press = False button_type = None - # should be CV.MPH_TO_KPH, but this causes rounding errors - v_cruise_delta = 1. if is_metric else 1.6 + v_cruise_delta = 1. if is_metric else IMPERIAL_INCREMENT for b in CS.buttonEvents: if b.type.raw in self.button_timers and not b.pressed: diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index 3d6f55931e..a635198ceb 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -3,7 +3,7 @@ import numpy as np from parameterized import parameterized_class import unittest -from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN +from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN, IMPERIAL_INCREMENT from cereal import car from common.conversions import Conversions as CV from common.params import Params @@ -110,6 +110,30 @@ class TestVCruiseHelper(unittest.TestCase): should_equal = standstill or pressed self.assertEqual(should_equal, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) + def test_set_gas_pressed(self): + """ + Asserts pressing set while enabled with gas pressed sets + the speed to the maximum of vEgo and current cruise speed. + """ + + for v_ego in np.linspace(0, 100, 101): + self.reset_cruise_speed_state() + self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + + # first decrement speed, then perform gas pressed logic + expected_v_cruise_kph = self.v_cruise_helper.v_cruise_kph - IMPERIAL_INCREMENT + expected_v_cruise_kph = max(expected_v_cruise_kph, v_ego * CV.MS_TO_KPH) # clip to min of vEgo + expected_v_cruise_kph = float(np.clip(round(expected_v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX)) + + CS = car.CarState(vEgo=float(v_ego), gasPressed=True, cruiseState={"available": True}) + CS.buttonEvents = [ButtonEvent(type=ButtonType.decelCruise, pressed=False)] + self.v_cruise_helper.update_v_cruise(CS, enabled=True, is_metric=False) + + # TODO: fix skipping first run due to enabled on rising edge exception + if v_ego == 0.0: + continue + self.assertEqual(expected_v_cruise_kph, self.v_cruise_helper.v_cruise_kph) + def test_initialize_v_cruise(self): """ Asserts allowed cruise speeds on enabling with SET. From 4478241bea02cb673983aa6b97428702a54dd1c2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 17:17:36 -0800 Subject: [PATCH 0349/1179] spi goes on boardd core --- panda | 2 +- system/hardware/tici/hardware.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/panda b/panda index 5dc5cd8e20..2e90b6f308 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 5dc5cd8e20668dfb15d35b175fccbfd3f7b63b09 +Subproject commit 2e90b6f308dc09bf1734f6cb5cc990cb8149486d diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index e2fd20c1be..b5f5e00410 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -416,6 +416,7 @@ class Tici(HardwareBase): # *** IRQ config *** affine_irq(5, 565) # kgsl-3d0 + affine_irq(4, 126) # SPI goes on boardd core affine_irq(4, 740) # xhci-hcd:usb1 goes on the boardd core affine_irq(4, 1069) # xhci-hcd:usb3 goes on the boardd core for irq in range(237, 246): From 1367f84425b5fbdb3ecf8452b134b641998e404a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 21 Nov 2022 18:01:08 -0800 Subject: [PATCH 0350/1179] Car docs: add a make-specific init function (#26565) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add a hook function for makes to implement custom docs logic * don't need this * use the pre-defined list for honda's harnesses * one line 😎 * Update selfdrive/car/docs_definitions.py * i didn't know you didn't need a pass! * don't change docs order --- selfdrive/car/docs.py | 1 + selfdrive/car/docs_definitions.py | 3 ++ selfdrive/car/gm/values.py | 21 +++++++----- selfdrive/car/honda/values.py | 52 +++++++++++++++++------------- selfdrive/car/volkswagen/values.py | 20 ++++++------ 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 58afed27eb..03313e2ff6 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -40,6 +40,7 @@ def get_all_car_info() -> List[CarInfo]: for _car_info in car_info: if not hasattr(_car_info, "row"): + _car_info.init_make(CP) _car_info.init(CP, footnotes) all_car_info.append(_car_info) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 6ec9ac5c40..7cf44514d6 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -172,6 +172,9 @@ class CarInfo: return self + def init_make(self, CP: car.CarParams): + """CarInfo subclasses can add make-specific logic for harness selection, footnotes, etc.""" + def get_detail_sentence(self, CP): if not CP.notCar: sentence_builder = "openpilot upgrades your {car_model} with automated lane centering{alc} and adaptive cruise control{acc}." diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 35f87307d6..0a8cdc6dbb 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -1,5 +1,5 @@ from collections import defaultdict -from dataclasses import dataclass, field +from dataclasses import dataclass from enum import Enum from typing import Dict, List, Union @@ -84,8 +84,13 @@ class Footnote(Enum): @dataclass class GMCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC)" - harness: Enum = Harness.obd_ii - footnotes: List[Enum] = field(default_factory=lambda: [Footnote.OBD_II]) + + def init_make(self, CP: car.CarParams): + if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera: + self.harness = Harness.gm + else: + self.harness = Harness.obd_ii + self.footnotes.append(Footnote.OBD_II) CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { @@ -96,13 +101,13 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), - CAR.BOLT_EV: GMCarInfo("Chevrolet Bolt EV 2022-23", footnotes=[], harness=Harness.gm), - 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.BOLT_EV: GMCarInfo("Chevrolet Bolt EV 2022-23"), + CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210"), 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", "https://youtu.be/5HbNoBLzRwE", footnotes=[], harness=Harness.gm), + GMCarInfo("Chevrolet Silverado 1500 2020-21", "Safety Package II"), + GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", "https://youtu.be/5HbNoBLzRwE"), ], - CAR.EQUINOX: GMCarInfo("Chevrolet Equinox 2019-22", footnotes=[], harness=Harness.gm), + CAR.EQUINOX: GMCarInfo("Chevrolet Equinox 2019-22"), } diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 2510f2e1ff..151c2140f5 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -106,40 +106,46 @@ class Footnote(Enum): class HondaCarInfo(CarInfo): package: str = "Honda Sensing" + def init_make(self, CP: car.CarParams): + if CP.carFingerprint in HONDA_BOSCH: + self.harness = Harness.bosch_b if CP.carFingerprint in HONDA_BOSCH_RADARLESS else Harness.bosch_a + else: + self.harness = Harness.nidec + CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { CAR.ACCORD: [ - HondaCarInfo("Honda Accord 2018-22", "All", "https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), - HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), + HondaCarInfo("Honda Accord 2018-22", "All", "https://www.youtube.com/watch?v=mrUwlj3Mi58", min_steer_speed=3. * CV.MPH_TO_MS), + HondaCarInfo("Honda Inspire 2018", "All", min_steer_speed=3. * CV.MPH_TO_MS), ], - CAR.ACCORDH: HondaCarInfo("Honda Accord Hybrid 2018-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), - CAR.CIVIC: HondaCarInfo("Honda Civic 2016-18", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec, video_link="https://youtu.be/-IkImTe1NYE"), + CAR.ACCORDH: HondaCarInfo("Honda Accord Hybrid 2018-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), + CAR.CIVIC: HondaCarInfo("Honda Civic 2016-18", min_steer_speed=12. * CV.MPH_TO_MS, video_link="https://youtu.be/-IkImTe1NYE"), CAR.CIVIC_BOSCH: [ - HondaCarInfo("Honda Civic 2019-21", "All", "https://www.youtube.com/watch?v=4Iz1Mz5LGF8", [Footnote.CIVIC_DIESEL], 2. * CV.MPH_TO_MS, harness=Harness.bosch_a), - HondaCarInfo("Honda Civic Hatchback 2017-21", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a), + HondaCarInfo("Honda Civic 2019-21", "All", "https://www.youtube.com/watch?v=4Iz1Mz5LGF8", [Footnote.CIVIC_DIESEL], 2. * CV.MPH_TO_MS), + HondaCarInfo("Honda Civic Hatchback 2017-21", min_steer_speed=12. * CV.MPH_TO_MS), ], CAR.CIVIC_BOSCH_DIESEL: None, # same platform CAR.CIVIC_2022: [ - HondaCarInfo("Honda Civic 2022", "All", harness=Harness.bosch_b), - HondaCarInfo("Honda Civic Hatchback 2022", "All", harness=Harness.bosch_b), + HondaCarInfo("Honda Civic 2022", "All"), + HondaCarInfo("Honda Civic Hatchback 2022", "All"), ], - CAR.ACURA_ILX: HondaCarInfo("Acura ILX 2016-19", "AcuraWatch Plus", min_steer_speed=25. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.CRV: HondaCarInfo("Honda CR-V 2015-16", "Touring Trim", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.CRV_5G: HondaCarInfo("Honda CR-V 2017-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a), + CAR.ACURA_ILX: HondaCarInfo("Acura ILX 2016-19", "AcuraWatch Plus", min_steer_speed=25. * CV.MPH_TO_MS), + CAR.CRV: HondaCarInfo("Honda CR-V 2015-16", "Touring Trim", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.CRV_5G: HondaCarInfo("Honda CR-V 2017-22", min_steer_speed=12. * CV.MPH_TO_MS), CAR.CRV_EU: None, # HondaCarInfo("Honda CR-V EU", "Touring"), # Euro version of CRV Touring - CAR.CRV_HYBRID: HondaCarInfo("Honda CR-V Hybrid 2017-19", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.bosch_a), - CAR.FIT: HondaCarInfo("Honda Fit 2018-20", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.FREED: HondaCarInfo("Honda Freed 2020", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.HRV: HondaCarInfo("Honda HR-V 2019-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.ODYSSEY: HondaCarInfo("Honda Odyssey 2018-20", harness=Harness.nidec), + CAR.CRV_HYBRID: HondaCarInfo("Honda CR-V Hybrid 2017-19", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.FIT: HondaCarInfo("Honda Fit 2018-20", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.FREED: HondaCarInfo("Honda Freed 2020", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.HRV: HondaCarInfo("Honda HR-V 2019-22", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.ODYSSEY: HondaCarInfo("Honda Odyssey 2018-20"), CAR.ODYSSEY_CHN: None, # Chinese version of Odyssey - CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), - CAR.PILOT: HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", min_steer_speed=12. * CV.MPH_TO_MS, harness=Harness.nidec), - CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), - CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS, harness=Harness.bosch_a), + CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), + CAR.PILOT: HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), + CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS), } FW_QUERY_CONFIG = FwQueryConfig( diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index cb2343e08f..f24448adbc 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1,5 +1,5 @@ from collections import defaultdict, namedtuple -from dataclasses import dataclass, field +from dataclasses import dataclass from enum import Enum from typing import Dict, List, Union @@ -165,7 +165,9 @@ class Footnote(Enum): class VWCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC) & Lane Assist" harness: Enum = Harness.j533 - footnotes: List[Enum] = field(default_factory=lambda: [Footnote.VW_EXP_LONG]) + + def init_make(self, CP: car.CarParams): + self.footnotes.insert(0, Footnote.VW_EXP_LONG) CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { @@ -197,28 +199,28 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { VWCarInfo("Volkswagen Jetta GLI 2021-22"), ], CAR.PASSAT_MK8: [ - VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.VW_EXP_LONG, Footnote.PASSAT]), + VWCarInfo("Volkswagen Passat 2015-22", footnotes=[Footnote.PASSAT]), VWCarInfo("Volkswagen Passat Alltrack 2015-22"), VWCarInfo("Volkswagen Passat GTE 2015-22"), ], CAR.PASSAT_NMS: VWCarInfo("Volkswagen Passat NMS 2017-22"), CAR.POLO_MK6: [ - VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), - VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), + VWCarInfo("Volkswagen Polo 2020-22", footnotes=[Footnote.VW_MQB_A0]), + VWCarInfo("Volkswagen Polo GTI 2020-22", footnotes=[Footnote.VW_MQB_A0]), ], CAR.SHARAN_MK2: [ VWCarInfo("Volkswagen Sharan 2018-22"), VWCarInfo("SEAT Alhambra 2018-20"), ], CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022"), - CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), + CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_MQB_A0]), CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22"), CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"), CAR.TRANSPORTER_T61: [ VWCarInfo("Volkswagen Caravelle 2020"), VWCarInfo("Volkswagen California 2021"), ], - CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), + CAR.TROC_MK1: VWCarInfo("Volkswagen T-Roc 2021", footnotes=[Footnote.VW_MQB_A0]), CAR.AUDI_A3_MK3: [ VWCarInfo("Audi A3 2014-19"), VWCarInfo("Audi A3 Sportback e-tron 2017-18"), @@ -229,10 +231,10 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2019-23"), CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018"), CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20"), - CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0, Footnote.KAMIQ]), + CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_MQB_A0, Footnote.KAMIQ]), CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21"), CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"), - CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_EXP_LONG, Footnote.VW_MQB_A0]), + CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_MQB_A0]), CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-22"), CAR.SKODA_OCTAVIA_MK3: [ VWCarInfo("Škoda Octavia 2015, 2018-19"), From c0c94b4961e8e32c3f8dbcfed2b7d91c28000085 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 20:32:23 -0800 Subject: [PATCH 0351/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 2e90b6f308..c075050d5d 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2e90b6f308dc09bf1734f6cb5cc990cb8149486d +Subproject commit c075050d5df70570cfadd8c0d7507f25fe67d247 From 8ee07def5c8b21c479b9f342ba490887237b2d0f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 21:18:35 -0800 Subject: [PATCH 0352/1179] jenkins: set hostname on startup --- selfdrive/test/setup_device_ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh index 02c7d76637..9e06b98662 100755 --- a/selfdrive/test/setup_device_ci.sh +++ b/selfdrive/test/setup_device_ci.sh @@ -29,6 +29,7 @@ sudo abctl --set_success # patch sshd config sudo mount -o rw,remount / +echo tici-$(cat /proc/cmdline | sed -e 's/^.*androidboot.serialno=//' -e 's/ .*$//') | sudo tee /etc/hostname sudo sed -i "s,/data/params/d/GithubSshKeys,/usr/comma/setup_keys," /etc/ssh/sshd_config sudo systemctl daemon-reload sudo systemctl restart ssh From e9dcabcef73aaffeee8eaaeab29d48e8277d98a6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 23:13:41 -0800 Subject: [PATCH 0353/1179] boardd: end peripheral panda discrimination --- selfdrive/boardd/boardd.cc | 3 --- selfdrive/boardd/panda.cc | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 5496902252..1f1249194d 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -528,9 +528,6 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) { cnt++; sm.update(1000); // TODO: what happens if EINTR is sent while in sm.update? - // Other pandas don't have fan/IR to control - if (panda->hw_type != cereal::PandaState::PandaType::UNO && panda->hw_type != cereal::PandaState::PandaType::DOS) continue; - if (sm.updated("deviceState") && !no_fan_control) { // Fan speed uint16_t fan_speed = sm["deviceState"].getDeviceState().getFanSpeedPercentDesired(); diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index deccee3e76..b82de593c8 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -24,7 +24,8 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { (hw_type != cereal::PandaState::PandaType::GREY_PANDA)); has_rtc = (hw_type == cereal::PandaState::PandaType::UNO) || - (hw_type == cereal::PandaState::PandaType::DOS); + (hw_type == cereal::PandaState::PandaType::DOS) || + (hw_type == cereal::PandaState::PandaType::TRES); return; } From 65fa87a96965000986e76604ac868891e35a86bc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 21 Nov 2022 23:43:24 -0800 Subject: [PATCH 0354/1179] cleanup panda types everywhere (#26574) * cleanup panda types everywhere * one more --- selfdrive/controls/controlsd.py | 11 ++-- selfdrive/controls/lib/events.py | 3 +- selfdrive/debug/test_fw_query_on_routes.py | 2 +- selfdrive/thermald/power_monitoring.py | 9 ++- .../thermald/tests/test_power_monitoring.py | 63 +++++++------------ selfdrive/thermald/thermald.py | 3 +- 6 files changed, 34 insertions(+), 57 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index a395f85580..7b95b3b29c 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -275,12 +275,11 @@ class Controls: # self.events.add(EventName.highCpuUsage) # Alert if fan isn't spinning for 5 seconds - if self.sm['peripheralState'].pandaType == PandaType.dos: - if self.sm['peripheralState'].fanSpeedRpm == 0 and self.sm['deviceState'].fanSpeedPercentDesired > 50: - if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 5.0: - self.events.add(EventName.fanMalfunction) - else: - self.last_functional_fan_frame = self.sm.frame + if self.sm['peripheralState'].fanSpeedRpm == 0 and self.sm['deviceState'].fanSpeedPercentDesired > 50: + if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 5.0: + self.events.add(EventName.fanMalfunction) + else: + self.last_functional_fan_frame = self.sm.frame # Handle calibration status cal_status = self.sm['liveCalibration'].calStatus diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index a761cceecb..1ed2ffa865 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -250,10 +250,9 @@ def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messag def no_gps_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: - gps_integrated = sm['peripheralState'].pandaType in (log.PandaState.PandaType.uno, log.PandaState.PandaType.dos) return Alert( "Poor GPS reception", - "Hardware malfunctioning if sky is visible" if gps_integrated else "Check GPS antenna placement", + "Hardware malfunctioning if sky is visible", AlertStatus.normal, AlertSize.mid, Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=300.) diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py index 595e25e8c3..ba7d96dba0 100755 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -68,7 +68,7 @@ if __name__ == "__main__": CP = None for msg in lr: if msg.which() == "pandaStates": - if msg.pandaStates[0].pandaType not in ('uno', 'blackPanda', 'dos'): + if msg.pandaStates[0].pandaType in ('unknown', 'whitePanda', 'greyPanda', 'pedal'): print("wrong panda type") break diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index 7834569088..e62f0f97c3 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -1,7 +1,6 @@ import threading from typing import Optional -from cereal import log from common.params import Params, put_nonblocking from common.realtime import sec_since_boot from system.hardware import HARDWARE @@ -39,12 +38,12 @@ class PowerMonitoring: self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh)) # Calculation tick - def calculate(self, peripheralState, ignition): + def calculate(self, voltage: Optional[int], ignition: bool): try: now = sec_since_boot() # If peripheralState is None, we're probably not in a car, so we don't care - if peripheralState is None or peripheralState.pandaType == log.PandaState.PandaType.unknown: + if voltage is None: with self.integration_lock: self.last_measurement_time = None self.next_pulsed_measurement_time = None @@ -52,8 +51,8 @@ class PowerMonitoring: return # Low-pass battery voltage - self.car_voltage_instant_mV = peripheralState.voltage - self.car_voltage_mV = ((peripheralState.voltage * CAR_VOLTAGE_LOW_PASS_K) + (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K))) + self.car_voltage_instant_mV = voltage + self.car_voltage_mV = ((voltage * CAR_VOLTAGE_LOW_PASS_K) + (self.car_voltage_mV * (1 - CAR_VOLTAGE_LOW_PASS_K))) statlog.gauge("car_voltage", self.car_voltage_mV / 1e3) # Cap the car battery power and save it in a param every 10-ish seconds diff --git a/selfdrive/thermald/tests/test_power_monitoring.py b/selfdrive/thermald/tests/test_power_monitoring.py index 5d7463d455..4a5def7740 100755 --- a/selfdrive/thermald/tests/test_power_monitoring.py +++ b/selfdrive/thermald/tests/test_power_monitoring.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 import unittest from unittest.mock import patch -from parameterized import parameterized -from cereal import log -import cereal.messaging as messaging from common.params import Params params = Params() @@ -21,7 +18,8 @@ with patch("common.realtime.sec_since_boot", new=mock_sec_since_boot): CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING TEST_DURATION_S = 50 -ALL_PANDA_TYPES = [(log.PandaState.PandaType.dos,)] +GOOD_VOLTAGE = 12 * 1e3 +VOLTAGE_BELOW_PAUSE_CHARGING = (VBATT_PAUSE_CHARGING - 1) * 1e3 def pm_patch(name, value, constant=False): if constant: @@ -34,12 +32,6 @@ class TestPowerMonitoring(unittest.TestCase): params.remove("CarBatteryCapacity") params.remove("DisablePowerDown") - def mock_peripheralState(self, hw_type, car_voltage=12): - ps = messaging.new_message('peripheralState').peripheralState - ps.pandaType = hw_type - ps.voltage = car_voltage * 1e3 - return ps - # Test to see that it doesn't do anything when pandaState is None def test_pandaState_present(self): pm = PowerMonitoring() @@ -49,75 +41,68 @@ class TestPowerMonitoring(unittest.TestCase): self.assertEqual(pm.get_car_battery_capacity(), (CAR_BATTERY_CAPACITY_uWh / 10)) # Test to see that it doesn't integrate offroad when ignition is True - @parameterized.expand(ALL_PANDA_TYPES) - def test_offroad_ignition(self, hw_type): + def test_offroad_ignition(self): pm = PowerMonitoring() for _ in range(10): - pm.calculate(self.mock_peripheralState(hw_type), True) + pm.calculate(GOOD_VOLTAGE, True) self.assertEqual(pm.get_power_used(), 0) # Test to see that it integrates with discharging battery - @parameterized.expand(ALL_PANDA_TYPES) - def test_offroad_integration_discharging(self, hw_type): + def test_offroad_integration_discharging(self): POWER_DRAW = 4 with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() for _ in range(TEST_DURATION_S + 1): - pm.calculate(self.mock_peripheralState(hw_type), False) + pm.calculate(GOOD_VOLTAGE, False) expected_power_usage = ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6) self.assertLess(abs(pm.get_power_used() - expected_power_usage), 10) # Test to check positive integration of car_battery_capacity - @parameterized.expand(ALL_PANDA_TYPES) - def test_car_battery_integration_onroad(self, hw_type): + def test_car_battery_integration_onroad(self): POWER_DRAW = 4 with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() pm.car_battery_capacity_uWh = 0 for _ in range(TEST_DURATION_S + 1): - pm.calculate(self.mock_peripheralState(hw_type), True) + pm.calculate(GOOD_VOLTAGE, True) expected_capacity = ((TEST_DURATION_S/3600) * CAR_CHARGING_RATE_W * 1e6) self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10) # Test to check positive integration upper limit - @parameterized.expand(ALL_PANDA_TYPES) - def test_car_battery_integration_upper_limit(self, hw_type): + def test_car_battery_integration_upper_limit(self): POWER_DRAW = 4 with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh - 1000 for _ in range(TEST_DURATION_S + 1): - pm.calculate(self.mock_peripheralState(hw_type), True) + pm.calculate(GOOD_VOLTAGE, True) estimated_capacity = CAR_BATTERY_CAPACITY_uWh + (CAR_CHARGING_RATE_W / 3600 * 1e6) self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10) # Test to check negative integration of car_battery_capacity - @parameterized.expand(ALL_PANDA_TYPES) - def test_car_battery_integration_offroad(self, hw_type): + def test_car_battery_integration_offroad(self): POWER_DRAW = 4 with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh for _ in range(TEST_DURATION_S + 1): - pm.calculate(self.mock_peripheralState(hw_type), False) + pm.calculate(GOOD_VOLTAGE, False) expected_capacity = CAR_BATTERY_CAPACITY_uWh - ((TEST_DURATION_S/3600) * POWER_DRAW * 1e6) self.assertLess(abs(pm.get_car_battery_capacity() - expected_capacity), 10) # Test to check negative integration lower limit - @parameterized.expand(ALL_PANDA_TYPES) - def test_car_battery_integration_lower_limit(self, hw_type): + def test_car_battery_integration_lower_limit(self): POWER_DRAW = 4 with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() pm.car_battery_capacity_uWh = 1000 for _ in range(TEST_DURATION_S + 1): - pm.calculate(self.mock_peripheralState(hw_type), False) + pm.calculate(GOOD_VOLTAGE, False) estimated_capacity = 0 - ((1/3600) * POWER_DRAW * 1e6) self.assertLess(abs(pm.get_car_battery_capacity() - estimated_capacity), 10) # Test to check policy of stopping charging after MAX_TIME_OFFROAD_S - @parameterized.expand(ALL_PANDA_TYPES) - def test_max_time_offroad(self, hw_type): + def test_max_time_offroad(self): MOCKED_MAX_OFFROAD_TIME = 3600 POWER_DRAW = 0 # To stop shutting down for other reasons with pm_patch("MAX_TIME_OFFROAD_S", MOCKED_MAX_OFFROAD_TIME, constant=True), pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): @@ -125,25 +110,22 @@ class TestPowerMonitoring(unittest.TestCase): pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh start_time = ssb ignition = False - peripheralState = self.mock_peripheralState(hw_type) while ssb <= start_time + MOCKED_MAX_OFFROAD_TIME: - pm.calculate(peripheralState, ignition) + pm.calculate(GOOD_VOLTAGE, ignition) if (ssb - start_time) % 1000 == 0 and ssb < start_time + MOCKED_MAX_OFFROAD_TIME: self.assertFalse(pm.should_shutdown(ignition, True, start_time, False)) self.assertTrue(pm.should_shutdown(ignition, True, start_time, False)) # Test to check policy of stopping charging when the car voltage is too low - @parameterized.expand(ALL_PANDA_TYPES) - def test_car_voltage(self, hw_type): + def test_car_voltage(self): POWER_DRAW = 0 # To stop shutting down for other reasons TEST_TIME = 100 with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh ignition = False - peripheralState = self.mock_peripheralState(hw_type, car_voltage=(VBATT_PAUSE_CHARGING - 1)) for i in range(TEST_TIME): - pm.calculate(peripheralState, ignition) + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) if i % 10 == 0: self.assertEqual(pm.should_shutdown(ignition, True, ssb, True), (pm.car_voltage_mV < VBATT_PAUSE_CHARGING*1e3)) self.assertTrue(pm.should_shutdown(ignition, True, ssb, True)) @@ -157,9 +139,8 @@ class TestPowerMonitoring(unittest.TestCase): pm = PowerMonitoring() pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh ignition = False - peripheralState = self.mock_peripheralState(log.PandaState.PandaType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1)) for i in range(TEST_TIME): - pm.calculate(peripheralState, ignition) + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) if i % 10 == 0: self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) @@ -172,9 +153,8 @@ class TestPowerMonitoring(unittest.TestCase): pm = PowerMonitoring() pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh ignition = True - peripheralState = self.mock_peripheralState(log.PandaState.PandaType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1)) for i in range(TEST_TIME): - pm.calculate(peripheralState, ignition) + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) if i % 10 == 0: self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) self.assertFalse(pm.should_shutdown(ignition, True, ssb, False)) @@ -188,9 +168,8 @@ class TestPowerMonitoring(unittest.TestCase): pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh ignition = False - peripheralState = self.mock_peripheralState(log.PandaState.PandaType.uno, car_voltage=(VBATT_PAUSE_CHARGING - 1)) for i in range(TEST_TIME): - pm.calculate(peripheralState, ignition) + pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) if i % 10 == 0: self.assertFalse(pm.should_shutdown(ignition, False, ssb, False)) self.assertFalse(pm.should_shutdown(ignition, False, ssb, False)) diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 89b81f06ec..eedeff31f1 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -347,7 +347,8 @@ def thermald_thread(end_event, hw_queue): off_ts = sec_since_boot() # Offroad power monitoring - power_monitor.calculate(peripheralState, onroad_conditions["ignition"]) + voltage = None if peripheralState.pandaType == log.PandaState.PandaType.unknown else peripheralState.voltage + power_monitor.calculate(voltage, onroad_conditions["ignition"]) msg.deviceState.offroadPowerUsageUwh = power_monitor.get_power_used() msg.deviceState.carBatteryCapacityUwh = max(0, power_monitor.get_car_battery_capacity()) current_power_draw = HARDWARE.get_current_power_draw() From ceb94f1bcd7eae99977e132fd596db353e4e11b4 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Tue, 22 Nov 2022 11:41:22 -0800 Subject: [PATCH 0355/1179] Revert "Albert Einstein Model" (#26576) Revert "Albert Einstein Model (#26456)" This reverts commit 34c80a6fbdf8780ad0b75f497c226cf1d9de0ddb. --- 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 c0db988cf6..8805b3dce8 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:c73998c9f428380dd2282b451de6011469b717498ae83578cbf7aa95948910f7 +oid sha256:db746e3753de84367595fedd089c2bd41b06bd401ea28e085663533d0e63d74b size 45962473 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index cdd6ed7a6b..f541b6a6d5 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -ca02aa240e629920ad88a6510213cb0a153af92b +30efb4238327d723e17a3bda7e7c19c18f8a3b18 From 7361d1a11b21cc6482ed9ba8e5505b88081b66f6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 22 Nov 2022 11:46:28 -0800 Subject: [PATCH 0356/1179] process replay: support old routes with no peripheralState --- selfdrive/controls/controlsd.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 7b95b3b29c..76f049ddd2 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -275,11 +275,12 @@ class Controls: # self.events.add(EventName.highCpuUsage) # Alert if fan isn't spinning for 5 seconds - if self.sm['peripheralState'].fanSpeedRpm == 0 and self.sm['deviceState'].fanSpeedPercentDesired > 50: - if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 5.0: - self.events.add(EventName.fanMalfunction) - else: - self.last_functional_fan_frame = self.sm.frame + if self.sm['peripheralState'].pandaType != log.PandaState.PandaType.unknown: + if self.sm['peripheralState'].fanSpeedRpm == 0 and self.sm['deviceState'].fanSpeedPercentDesired > 50: + if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 5.0: + self.events.add(EventName.fanMalfunction) + else: + self.last_functional_fan_frame = self.sm.frame # Handle calibration status cal_status = self.sm['liveCalibration'].calStatus From 4662f1e0be77d6636ef7e3f663fb839448d86af6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 23 Nov 2022 06:23:49 +0800 Subject: [PATCH 0357/1179] Cabana: auto theme, detect from system. (#26563) * auto theme * cleanup * get font color from ForegroundRole * fix label color * add padding for header * smaller warning icon * fix bg of binary view * hightlight after init --- tools/cabana/binaryview.cc | 29 ++++++++++++++++------------- tools/cabana/binaryview.h | 4 +++- tools/cabana/cabana.cc | 2 -- tools/cabana/chartswidget.cc | 4 +++- tools/cabana/chartswidget.h | 1 + tools/cabana/detailwidget.cc | 3 +-- tools/cabana/historylog.cc | 17 +++++++++++++++-- tools/cabana/historylog.h | 1 + tools/cabana/settings.cc | 8 -------- tools/cabana/settings.h | 2 -- tools/cabana/signaledit.cc | 2 +- 11 files changed, 41 insertions(+), 32 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index dae4591976..6a4f66dcd4 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -1,6 +1,5 @@ #include "tools/cabana/binaryview.h" -#include #include #include #include @@ -74,14 +73,18 @@ void BinaryView::mousePressEvent(QMouseEvent *event) { event->accept(); } -void BinaryView::mouseMoveEvent(QMouseEvent *event) { - if (auto index = indexAt(event->pos()); index.isValid()) { +void BinaryView::highlightPosition(const QPoint &pos) { + if (auto index = indexAt(viewport()->mapFromGlobal(pos)); index.isValid()) { auto item = (BinaryViewModel::Item *)index.internalPointer(); const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); highlight(sig); - sig ? QToolTip::showText(event->globalPos(), sig->name.c_str(), this, rect()) + sig ? QToolTip::showText(pos, sig->name.c_str(), this, rect()) : QToolTip::hideText(); } +} + +void BinaryView::mouseMoveEvent(QMouseEvent *event) { + highlightPosition(event->globalPos()); QTableView::mouseMoveEvent(event); } @@ -116,6 +119,7 @@ void BinaryView::setMessage(const QString &message_id) { anchor_index = QModelIndex(); resize_sig = nullptr; hovered_sig = nullptr; + highlightPosition(QCursor::pos()); updateState(); } @@ -232,19 +236,18 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op BinaryView *bin_view = (BinaryView *)parent(); painter->save(); - // background - if (option.state & QStyle::State_Selected) { + if (index.column() == 8) { + painter->setFont(hex_font); + } else if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, selection_color); - } else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) { + painter->setPen(QApplication::style()->standardPalette().color(QPalette::BrightText)); + } else if (!item->sigs.isEmpty() && (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig))) { painter->fillRect(option.rect, item->bg_color); + painter->setPen(item->sigs.contains(bin_view->hovered_sig) + ? QApplication::style()->standardPalette().color(QPalette::BrightText) + : Qt::black); } - // text - if (index.column() == 8) { // hex column - painter->setFont(hex_font); - } 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); if (item->is_msb || item->is_lsb) { painter->setFont(small_font); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 0ea111d917..c37b378e44 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -41,7 +42,7 @@ public: } struct Item { - QColor bg_color = QColor(Qt::white); + QColor bg_color = QApplication::style()->standardPalette().color(QPalette::Base); bool is_msb = false; bool is_lsb = false; QString val = "0"; @@ -79,6 +80,7 @@ private: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void leaveEvent(QEvent *event) override; + void highlightPosition(const QPoint &pt); QModelIndex anchor_index; BinaryViewModel *model; diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 1096487973..e7e3eb213b 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -1,6 +1,5 @@ #include #include -#include #include "selfdrive/ui/qt/util.h" #include "tools/cabana/mainwin.h" @@ -8,7 +7,6 @@ int main(int argc, char *argv[]) { initApp(argc, argv); QApplication app(argc, argv); - app.setStyle(QStyleFactory::create("Fusion")); QCommandLineParser cmd_parser; cmd_parser.addHelpOption(); diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5d530a8c8a..6e1f2e110c 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -40,6 +40,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(charts_scroll); + use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value(); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState); @@ -125,6 +127,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo ChartView *chart = merge && charts.size() > 0 ? charts.back() : nullptr; if (!chart) { chart = new ChartView(this); + chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); chart->setEventsRange(display_range); auto range = is_zoomed ? zoomed_range : display_range; chart->setDisplayRange(range.first, range.second); @@ -288,7 +291,6 @@ void ChartView::updateTitle() { void ChartView::updateFromSettings() { setFixedHeight(settings.chart_height); - chart()->setTheme(settings.chart_theme == 0 ? QChart::ChartThemeLight : QChart::QChart::ChartThemeDark); } void ChartView::setEventsRange(const std::pair &range) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index c8e5a1040c..c3fa931e6e 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -112,4 +112,5 @@ private: std::pair event_range; std::pair display_range; std::pair zoomed_range; + bool use_dark_theme = false; }; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 52ae530a56..bf857bd596 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -25,7 +25,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart // tabbar tabbar = new QTabBar(this); tabbar->setTabsClosable(true); - tabbar->setDrawBase(false); tabbar->setUsesScrollButtons(true); tabbar->setAutoHide(true); tabbar->setContextMenuPolicy(Qt::CustomContextMenu); @@ -57,7 +56,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); warning_hlayout->setContentsMargins(0, 0, 0, 0); QLabel *warning_icon = new QLabel(this); - warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning)); + warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning).scaledToWidth(24, Qt::SmoothTransformation)); warning_hlayout->addWidget(warning_icon, 0, Qt::AlignTop); warning_label = new QLabel(this); warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 1b0898afbd..65fea3361e 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -1,6 +1,7 @@ #include "tools/cabana/historylog.h" #include +#include // HistoryLogModel @@ -44,6 +45,8 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i return has_signal ? QString::fromStdString(get_signal(dbc_msg, section - 1).name).replace('_', ' ') : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && has_signal) { return QBrush(QColor(getColor(section - 1))); + } else if (role == Qt::ForegroundRole && section > 0 && has_signal) { + return QBrush(Qt::black); } } return {}; @@ -73,7 +76,18 @@ void HistoryLogModel::updateState() { QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); const QRect rect = fontMetrics().boundingRect(QRect(0, 0, sectionSize(logicalIndex), 1000), defaultAlignment(), text); - return rect.size() + QSize{10, 5}; + return rect.size() + QSize{10, 6}; +} + +void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { + auto bg_role = model()->headerData(logicalIndex, Qt::Horizontal, Qt::BackgroundRole); + if (bg_role.isValid()) { + QPen pen(model()->headerData(logicalIndex, Qt::Horizontal, Qt::ForegroundRole).value(), 1); + painter->setPen(pen); + painter->fillRect(rect, bg_role.value()); + } + QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString(); + painter->drawText(rect.adjusted(5, 3, 5, 3), defaultAlignment(), text); } // HistoryLog @@ -88,7 +102,6 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { verticalHeader()->setVisible(false); setFrameShape(QFrame::NoFrame); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - setStyleSheet("QTableView::item { border:0px; padding-left:5px; padding-right:5px; }"); } int HistoryLog::sizeHintForColumn(int column) const { diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 21be8fc129..dfe037c13f 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -10,6 +10,7 @@ class HeaderView : public QHeaderView { public: HeaderView(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {} QSize sectionSizeFromContents(int logicalIndex) const override; + void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const; }; class HistoryLogModel : public QAbstractTableModel { diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index be806aa705..c90830973b 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -18,7 +18,6 @@ void Settings::save() { s.setValue("log_size", can_msg_log_size); s.setValue("cached_segment", cached_segment_limit); s.setValue("chart_height", chart_height); - 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); @@ -30,7 +29,6 @@ void Settings::load() { can_msg_log_size = s.value("log_size", 50).toInt(); cached_segment_limit = s.value("cached_segment", 3).toInt(); chart_height = s.value("chart_height", 200).toInt(); - 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(); @@ -72,11 +70,6 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { chart_height->setValue(settings.chart_height); form_layout->addRow(tr("Chart height"), chart_height); - chart_theme = new QComboBox(); - chart_theme->addItems({"Light", "Dark"}); - chart_theme->setCurrentIndex(settings.chart_theme == 1 ? 1 : 0); - form_layout->addRow(tr("Chart theme"), chart_theme); - auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); form_layout->addRow(buttonBox); @@ -90,7 +83,6 @@ void SettingsDlg::save() { settings.can_msg_log_size = log_size->value(); settings.cached_segment_limit = cached_segment->value(); settings.chart_height = chart_height->value(); - settings.chart_theme = chart_theme->currentIndex(); settings.max_chart_x_range = max_chart_x_range->value() * 60; settings.save(); accept(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 624a1ce33d..ee6541798d 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -17,7 +17,6 @@ public: int can_msg_log_size = 50; int cached_segment_limit = 3; int chart_height = 200; - int chart_theme = 0; int max_chart_x_range = 3 * 60; // 3 minutes QString last_dir; QByteArray splitter_state; @@ -36,7 +35,6 @@ public: QSpinBox *log_size ; QSpinBox *cached_segment; QSpinBox *chart_height; - QComboBox *chart_theme; QSpinBox *max_chart_x_range; }; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 5d627a49da..254b11efaa 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -137,7 +137,7 @@ void SignalEdit::setSignal(const QString &message_id, const Signal *signal) { updateForm(msg_id == message_id && form->isVisible()); msg_id = message_id; color_label->setText(QString::number(form_idx + 1)); - color_label->setStyleSheet(QString("background-color:%1").arg(getColor(form_idx))); + color_label->setStyleSheet(QString("color:black; background-color:%2").arg(getColor(form_idx))); title->setText(sig->name.c_str()); show(); } From 9fdbe9f397b79f33c0653f4e9dd3b1cbb2e92273 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 22 Nov 2022 15:18:10 -0800 Subject: [PATCH 0358/1179] GM Cam: log when cruise not adaptive (#26581) * bump opendbc * log when nonAdaptive * Update ref_commit --- opendbc | 2 +- selfdrive/car/gm/carstate.py | 4 ++++ selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index 296f190000..871e054d9a 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 296f190000a2e71408e207ba21a2257cc853ec15 +Subproject commit 871e054d9a94629d92c22fe89cae71af5b0d3823 diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index df1b4b2866..de0fd2eed6 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -100,6 +100,9 @@ class CarState(CarStateBase): 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 + # openpilot controls nonAdaptive when not pcmCruise + if self.CP.pcmCruise: + ret.cruiseState.nonAdaptive = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCruiseState"] not in (2, 3) return ret @@ -112,6 +115,7 @@ class CarState(CarStateBase): ("AEBCmdActive", "AEBCmd"), ("RollingCounter", "ASCMLKASteeringCmd"), ("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"), + ("ACCCruiseState", "ASCMActiveCruiseControlStatus"), ] checks += [ ("AEBCmd", 10), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4aa9d60ab5..770b4e40f7 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -959e63af52d9efdb62156cab4b773f88b154fd75 +ff508a46616a1a3d66e8d1154d123ffd11025003 From 636ff5979fc19fe0a965fbceae214694c97c1e3d Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 22 Nov 2022 19:18:42 -0500 Subject: [PATCH 0359/1179] VW MQB: Redundant brake pressed signals (#26401) * VW MQB: Redundant brake pressed signals * retry CI * update refs * update refs Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/car/volkswagen/carstate.py | 11 +++++++---- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/panda b/panda index c075050d5d..e4c4253964 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c075050d5df70570cfadd8c0d7507f25fe67d247 +Subproject commit e4c4253964a25ff980520b70ea9f50aede4a1db6 diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index def14ab019..7d0a3d4dca 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -62,7 +62,9 @@ class CarState(CarStateBase): ret.gas = pt_cp.vl["Motor_20"]["MO_Fahrpedalrohwert_01"] / 100.0 ret.gasPressed = ret.gas > 0 ret.brake = pt_cp.vl["ESP_05"]["ESP_Bremsdruck"] / 250.0 # FIXME: this is pressure in Bar, not sure what OP expects - ret.brakePressed = bool(pt_cp.vl["ESP_05"]["ESP_Fahrer_bremst"]) + brake_pedal_pressed = bool(pt_cp.vl["Motor_14"]["MO_Fahrer_bremst"]) + brake_pressure_detected = bool(pt_cp.vl["ESP_05"]["ESP_Fahrer_bremst"]) + ret.brakePressed = brake_pedal_pressed or brake_pressure_detected ret.parkingBrake = bool(pt_cp.vl["Kombi_01"]["KBI_Handbremse"]) # FIXME: need to include an EPB check as well # Update gear and/or clutch position data. @@ -268,8 +270,9 @@ class CarState(CarStateBase): ("Comfort_Signal_Right", "Blinkmodi_02"), # Right turn signal including comfort blink interval ("AB_Gurtschloss_FA", "Airbag_02"), # Seatbelt status, driver ("AB_Gurtschloss_BF", "Airbag_02"), # Seatbelt status, passenger - ("ESP_Fahrer_bremst", "ESP_05"), # Brake pedal pressed - ("ESP_Bremsdruck", "ESP_05"), # Brake pressure applied + ("ESP_Fahrer_bremst", "ESP_05"), # Driver applied brake pressure over threshold + ("MO_Fahrer_bremst", "Motor_14"), # Brake pedal switch + ("ESP_Bremsdruck", "ESP_05"), # Brake pressure ("MO_Fahrpedalrohwert_01", "Motor_20"), # Accelerator pedal value ("EPS_Lenkmoment", "LH_EPS_03"), # Absolute driver torque input ("EPS_VZ_Lenkmoment", "LH_EPS_03"), # Driver torque input sign @@ -304,6 +307,7 @@ class CarState(CarStateBase): ("ESP_02", 50), # From J104 ABS/ESP controller ("GRA_ACC_01", 33), # From J533 CAN gateway (via LIN from steering wheel controls) ("Gateway_72", 10), # From J533 CAN gateway (aggregated data) + ("Motor_14", 10), # From J623 Engine control module ("Airbag_02", 5), # From J234 Airbag control module ("Kombi_01", 2), # From J285 Instrument cluster ("Blinkmodi_02", 1), # From J519 BCM (sent at 1Hz when no lights active, 50Hz when active) @@ -318,7 +322,6 @@ class CarState(CarStateBase): elif CP.transmissionType == TransmissionType.manual: signals += [("MO_Kuppl_schalter", "Motor_14"), # Clutch switch ("BCM1_Rueckfahrlicht_Schalter", "Gateway_72")] # Reverse light from BCM - checks.append(("Motor_14", 10)) # From J623 Engine control module if CP.networkLocation == NetworkLocation.fwdCamera: # Radars are here on CANBUS.pt diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 770b4e40f7..d4520d2935 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -ff508a46616a1a3d66e8d1154d123ffd11025003 +08ca448a6dcfc1edc4f9fedb2ea94ad6b2b69aa2 \ No newline at end of file From c1e7bed061424387aaf5a91eaa43e96752995cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 22 Nov 2022 20:20:58 -0800 Subject: [PATCH 0360/1179] Navd map renderer: update to larger image (#26580) * rerender 512 * rerender 512 * Removed unnecessary code * rgb -> grayscale * Add constants Co-authored-by: mitchellgoffpc --- selfdrive/navd/map_renderer.cc | 41 +++++++++++++--------------------- selfdrive/navd/map_renderer.py | 3 ++- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index daf89b2636..247b69c4c5 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -11,33 +11,18 @@ #include "selfdrive/ui/qt/maps/map_helpers.h" const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear -const int RENDER_HEIGHT = 512, RENDER_WIDTH = 512; -const int HEIGHT = 256, WIDTH = 256; +const int HEIGHT = 512, WIDTH = 512; const int NUM_VIPC_BUFFERS = 4; const int EARTH_CIRCUMFERENCE_METERS = 40075000; const int PIXELS_PER_TILE = 256; -float get_meters_per_pixel(float lat, float zoom) { - float num_tiles = pow(2, zoom+1); - float meters_per_tile = cos(DEG2RAD(lat)) * EARTH_CIRCUMFERENCE_METERS / num_tiles; - return meters_per_tile / PIXELS_PER_TILE; -} - float get_zoom_level_for_scale(float lat, float meters_per_pixel) { float meters_per_tile = meters_per_pixel * PIXELS_PER_TILE; float num_tiles = cos(DEG2RAD(lat)) * EARTH_CIRCUMFERENCE_METERS / meters_per_tile; return log2(num_tiles) - 1; } -void downsample(uint8_t *src, uint8_t *dst) { - for (int r = 0; r < HEIGHT; r++) { - for (int c = 0; c < WIDTH; c++) { - dst[r*WIDTH + c] = src[(r*2*RENDER_WIDTH + c*2) * 3]; - } - } -} - MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_settings(settings) { QSurfaceFormat fmt; @@ -59,7 +44,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set gl_functions->initializeOpenGLFunctions(); QOpenGLFramebufferObjectFormat fbo_format; - fbo.reset(new QOpenGLFramebufferObject(RENDER_WIDTH, RENDER_HEIGHT, fbo_format)); + fbo.reset(new QOpenGLFramebufferObject(WIDTH, HEIGHT, fbo_format)); std::string style = util::read_file(STYLE_PATH); m_map.reset(new QMapboxGL(nullptr, m_settings, fbo->size(), 1)); @@ -69,7 +54,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set m_map->resize(fbo->size()); m_map->setFramebufferObject(fbo->handle(), fbo->size()); - gl_functions->glViewport(0, 0, RENDER_WIDTH, RENDER_HEIGHT); + gl_functions->glViewport(0, 0, WIDTH, HEIGHT); if (online) { vipc_server.reset(new VisionIpcServer("navd")); @@ -114,9 +99,9 @@ void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) { return; } - // Choose a zoom level that matches the scale of zoom level 13 at latitude 80deg - float scale_lat80 = get_meters_per_pixel(80, 13); - float zoom = get_zoom_level_for_scale(position.first, scale_lat80); + // Choose a scale that ensures above 13 zoom level up to and above 75deg of lat + float meters_per_pixel = 2; + float zoom = get_zoom_level_for_scale(position.first, meters_per_pixel); m_map->setCoordinate(position); m_map->setBearing(bearing); @@ -150,13 +135,15 @@ void MapRenderer::sendVipc() { .timestamp_eof = ts, }; - assert(cap.sizeInBytes() >= buf->len*4); + assert(cap.sizeInBytes() >= buf->len); uint8_t* dst = (uint8_t*)buf->addr; uint8_t* src = cap.bits(); - // 2x downsample + rgb to grayscale + // RGB to greyscale memset(dst, 128, buf->len); - downsample(src, dst); + for (int i = 0; i < WIDTH * HEIGHT; i++) { + dst[i] = src[i * 3]; + } vipc_server->send(buf, &extra); @@ -187,8 +174,10 @@ uint8_t* MapRenderer::getImage() { uint8_t* src = cap.bits(); uint8_t* dst = new uint8_t[WIDTH * HEIGHT]; - // 2x downsample + rgb to grayscale - downsample(src, dst); + // RGB to greyscale + for (int i = 0; i < WIDTH * HEIGHT; i++) { + dst[i] = src[i * 3]; + } return dst; } diff --git a/selfdrive/navd/map_renderer.py b/selfdrive/navd/map_renderer.py index 9000622928..868307bb63 100755 --- a/selfdrive/navd/map_renderer.py +++ b/selfdrive/navd/map_renderer.py @@ -9,7 +9,8 @@ from cffi import FFI from common.ffi_wrapper import suffix from common.basedir import BASEDIR -HEIGHT = WIDTH = 256 +HEIGHT = WIDTH = SIZE = 512 +METERS_PER_PIXEL = 2 def get_ffi(): From 13cdddc6c806c963b65c477d409329ea717c7e11 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 22 Nov 2022 22:28:11 -0800 Subject: [PATCH 0361/1179] Toyota: whitelist FW queries (#26584) whitelist toyota --- selfdrive/car/toyota/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index cf37a3c2f2..6d6c03df71 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -209,16 +209,19 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [StdQueries.SHORT_TESTER_PRESENT_REQUEST, TOYOTA_VERSION_REQUEST], [StdQueries.SHORT_TESTER_PRESENT_RESPONSE, TOYOTA_VERSION_RESPONSE], + whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.dsu, Ecu.abs, Ecu.eps], bus=0, ), Request( [StdQueries.SHORT_TESTER_PRESENT_REQUEST, StdQueries.OBD_VERSION_REQUEST], [StdQueries.SHORT_TESTER_PRESENT_RESPONSE, StdQueries.OBD_VERSION_RESPONSE], + whitelist_ecus=[Ecu.engine], bus=0, ), Request( [StdQueries.TESTER_PRESENT_REQUEST, StdQueries.DEFAULT_DIAGNOSTIC_REQUEST, StdQueries.EXTENDED_DIAGNOSTIC_REQUEST, StdQueries.UDS_VERSION_REQUEST], [StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.DEFAULT_DIAGNOSTIC_RESPONSE, StdQueries.EXTENDED_DIAGNOSTIC_RESPONSE, StdQueries.UDS_VERSION_RESPONSE], + whitelist_ecus=[Ecu.engine, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.abs, Ecu.eps], bus=0, ), ], From 059e4f5730618812221b080c69f83fb36b68c5a7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 22 Nov 2022 23:43:23 -0800 Subject: [PATCH 0362/1179] Toyota: always log cruise standstill (#26586) these cars def are in cruise standstill, no sense to not log --- selfdrive/car/toyota/carstate.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 8efb2c79e3..dbbb8a6f04 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -6,7 +6,7 @@ from common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from selfdrive.car.interfaces import CarStateBase -from selfdrive.car.toyota.values import ToyotaFlags, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR +from selfdrive.car.toyota.values import ToyotaFlags, DBC, STEER_THRESHOLD, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR class CarState(CarStateBase): @@ -120,12 +120,7 @@ class CarState(CarStateBase): self.low_speed_lockout = cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2 self.pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] - if self.CP.carFingerprint in NO_STOP_TIMER_CAR or self.CP.enableGasInterceptor: - # ignore standstill in hybrid vehicles, since pcm allows to restart without - # receiving any special command. Also if interceptor is detected - ret.cruiseState.standstill = False - else: - ret.cruiseState.standstill = self.pcm_acc_status == 7 + ret.cruiseState.standstill = self.pcm_acc_status == 7 ret.cruiseState.enabled = bool(cp.vl["PCM_CRUISE"]["CRUISE_ACTIVE"]) ret.cruiseState.nonAdaptive = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] in (1, 2, 3, 4, 5, 6) From 6dec92df439183ff15155654e558b37ffa861631 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 24 Nov 2022 01:48:24 +0800 Subject: [PATCH 0363/1179] Cabana: fixed form glitches (#26587) fix visual glitches --- tools/cabana/detailwidget.cc | 15 ++++++--------- tools/cabana/detailwidget.h | 1 - tools/cabana/signaledit.cc | 2 +- tools/cabana/signaledit.h | 5 ++--- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index bf857bd596..c20e2b672e 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -153,10 +153,10 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { for (auto sig : msg->getSignals()) { SignalEdit *form = i < signal_list.size() ? signal_list[i] : nullptr; if (!form) { - form = new SignalEdit(i); + form = new SignalEdit(i, this); QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); - QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showFormClicked); + QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); QObject::connect(form, &SignalEdit::showChart, charts, &ChartsWidget::showChart); @@ -196,16 +196,13 @@ void DetailWidget::updateState(const QHash * msgs) { history_log->updateState(); } -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->sig == sig && !f->isFormVisible()); - if (f->sig == sig) scroll->ensureWidgetVisible(f); + f->updateForm(f->sig == sig && !f->form->isVisible()); + if (f->sig == sig && f->form->isVisible()) { + QTimer::singleShot(0, [=]() { scroll->ensureWidgetVisible(f); }); + } } setUpdatesEnabled(true); } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 41fa0edd41..75409fa706 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -29,7 +29,6 @@ public: private: void showForm(const Signal *sig); - void showFormClicked(); void updateChartState(const QString &id, const Signal *sig, bool opened); void showTabBarContextMenu(const QPoint &pt); void addSignal(int start_bit, int size, bool little_endian); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 254b11efaa..85476c2302 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -122,7 +122,7 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa save_timer->setSingleShot(true); save_timer->callOnTimeout(this, &SignalEdit::saveSignal); - QObject::connect(title, &ElidedLabel::clicked, this, &SignalEdit::showFormClicked); + QObject::connect(title, &ElidedLabel::clicked, [this]() { emit showFormClicked(sig); }); QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) { emit showChart(msg_id, sig, checked, QGuiApplication::keyboardModifiers() & Qt::ShiftModifier); }); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index f035797e72..205be4bb78 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -36,8 +36,8 @@ public: void setChartOpened(bool opened); void signalHovered(const Signal *sig); void updateForm(bool show); - inline bool isFormVisible() const { return form->isVisible(); } const Signal *sig = nullptr; + SignalForm *form = nullptr; QString msg_id; signals: @@ -45,14 +45,13 @@ signals: 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(); + void showFormClicked(const Signal *sig); protected: void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void saveSignal(); - SignalForm *form = nullptr; ElidedLabel *title; QLabel *color_label; QLabel *icon; From 2153bfe27a99b2ecd36ff91fcd10c3e71d952bbe Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 23 Nov 2022 13:08:04 -0800 Subject: [PATCH 0364/1179] camerad: minor ae improvement to OX (#26566) --- system/camerad/cameras/camera_qcom2.cc | 6 +++++- system/camerad/cameras/camera_qcom2.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 2ee06e372a..df5b9e8bf0 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -96,10 +96,12 @@ const uint32_t ox03c10_analog_gains_reg[] = { const int ANALOG_GAIN_MIN_IDX_AR0231 = 0x1; // 0.25x const int ANALOG_GAIN_REC_IDX_AR0231 = 0x6; // 0.8x const int ANALOG_GAIN_MAX_IDX_AR0231 = 0xD; // 4.0x +const int ANALOG_GAIN_COST_DELTA_AR0231 = 0; const int ANALOG_GAIN_MIN_IDX_OX03C10 = 0x0; const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x11; // 2.5x const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0x36; +const int ANALOG_GAIN_COST_DELTA_OX03C10 = -1; const int EXPOSURE_TIME_MIN_AR0231 = 2; // with HDR, fastest ss const int EXPOSURE_TIME_MAX_AR0231 = 0x0855; // with HDR, slowest ss, 40ms @@ -532,6 +534,7 @@ void CameraState::camera_set_parameters() { analog_gain_min_idx = ANALOG_GAIN_MIN_IDX_AR0231; analog_gain_rec_idx = ANALOG_GAIN_REC_IDX_AR0231; analog_gain_max_idx = ANALOG_GAIN_MAX_IDX_AR0231; + analog_gain_cost_delta = ANALOG_GAIN_COST_DELTA_AR0231; for (int i=0; i<=analog_gain_max_idx; i++) { sensor_analog_gains[i] = sensor_analog_gains_AR0231[i]; } @@ -548,6 +551,7 @@ void CameraState::camera_set_parameters() { analog_gain_min_idx = ANALOG_GAIN_MIN_IDX_OX03C10; analog_gain_rec_idx = ANALOG_GAIN_REC_IDX_OX03C10; analog_gain_max_idx = ANALOG_GAIN_MAX_IDX_OX03C10; + analog_gain_cost_delta = ANALOG_GAIN_COST_DELTA_OX03C10; for (int i=0; i<=analog_gain_max_idx; i++) { sensor_analog_gains[i] = sensor_analog_gains_OX03C10[i]; } @@ -1110,7 +1114,7 @@ void CameraState::set_camera_exposure(float grey_frac) { // LOGE("cam: %d - gain: %d, t: %d (%.2f), score %.2f, score + gain %.2f, %.3f, %.3f", camera_num, g, t, desired_ev / gain, score, score + std::abs(g - gain_idx) * (score + 1.0) / 10.0, desired_ev, min_ev); // Small penalty on changing gain - score += std::abs(g - gain_idx) * (score + 1.0) / 10.0; + score += ((1 - analog_gain_cost_delta) + analog_gain_cost_delta * (g - analog_gain_min_idx) / (analog_gain_max_idx - analog_gain_min_idx)) * std::abs(g - gain_idx) * (score + 1.0) / 10.0; if (score < best_ev_score) { new_t = t; diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 1e25e605c5..150ea0a1c0 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -41,6 +41,7 @@ public: int analog_gain_min_idx; int analog_gain_max_idx; int analog_gain_rec_idx; + int analog_gain_cost_delta; float cur_ev[3]; float min_ev, max_ev; From b15018387c774b9f470e88f22b96861d62917656 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 23 Nov 2022 14:03:15 -0800 Subject: [PATCH 0365/1179] tuning: measure steering accuracy for existing routes (#25722) * support parsing route logs * optionally use cached data * support segment or route names * get control type from log --- tools/tuning/measure_steering_accuracy.py | 151 +++++++++++++--------- 1 file changed, 88 insertions(+), 63 deletions(-) diff --git a/tools/tuning/measure_steering_accuracy.py b/tools/tuning/measure_steering_accuracy.py index 7abfb6358a..4819be770f 100755 --- a/tools/tuning/measure_steering_accuracy.py +++ b/tools/tuning/measure_steering_accuracy.py @@ -8,24 +8,13 @@ import signal from collections import defaultdict import cereal.messaging as messaging +from tools.lib.logreader import logreader_from_route_or_segment def sigint_handler(signal, frame): - print("handler!") exit(0) signal.signal(signal.SIGINT, sigint_handler) -if __name__ == "__main__": - - parser = argparse.ArgumentParser(description='Sniff a communication socket') - parser.add_argument('control_type', help="[pid|indi|lqr|angle]") - parser.add_argument('--addr', default='127.0.0.1', help="IP address for optional ZMQ listener, default to msgq") - parser.add_argument('--group', default='all', help="speed group to display, [crawl|slow|medium|fast|veryfast|germany|all], default to all") - args = parser.parse_args() - - if args.addr != "127.0.0.1": - os.environ["ZMQ"] = "1" - messaging.context = messaging.Context() - +class SteeringAccuracyTool: all_groups = {"germany": (45, "45 - up m/s // 162 - up km/h // 101 - up mph"), "veryfast": (35, "35 - 45 m/s // 126 - 162 km/h // 78 - 101 mph"), "fast": (25, "25 - 35 m/s // 90 - 126 km/h // 56 - 78 mph"), @@ -33,39 +22,28 @@ if __name__ == "__main__": "slow": (5, " 5 - 15 m/s // 18 - 54 km/h // 11 - 34 mph"), "crawl": (0, " 0 - 5 m/s // 0 - 18 km/h // 0 - 11 mph")} - if args.group == "all": - display_groups = all_groups.keys() - elif args.group in all_groups.keys(): - display_groups = [args.group] - else: - raise ValueError("invalid speed group, see help") + def __init__(self, args): + self.msg_cnt = 0 + self.cnt = 0 + self.total_error = 0 - speed_group_stats = {} - for group in all_groups: - speed_group_stats[group] = defaultdict(lambda: {'err': 0, "cnt": 0, "=": 0, "+": 0, "-": 0, "steer": 0, "limited": 0, "saturated": 0, "dpp": 0}) - - carControl = messaging.sub_sock('carControl', addr=args.addr, conflate=True) - sm = messaging.SubMaster(['carState', 'carControl', 'controlsState', 'lateralPlan'], addr=args.addr) - time.sleep(1) # Make sure all submaster data is available before going further - - msg_cnt = 0 - cnt = 0 - total_error = 0 - - while messaging.recv_one(carControl): - sm.update() - msg_cnt += 1 - - if args.control_type == "pid": - control_state = sm['controlsState'].lateralControlState.pidState - elif args.control_type == "indi": - control_state = sm['controlsState'].lateralControlState.indiState - elif args.control_type == "lqr": - control_state = sm['controlsState'].lateralControlState.lqrState - elif args.control_type == "angle": - control_state = sm['controlsState'].lateralControlState.angleState + if args.group == "all": + self.display_groups = self.all_groups.keys() + elif args.group in self.all_groups.keys(): + self.display_groups = [args.group] else: - raise ValueError("invalid lateral control type, see help") + raise ValueError("invalid speed group, see help") + + self.speed_group_stats = {} + for group in self.all_groups: + self.speed_group_stats[group] = defaultdict(lambda: {'err': 0, "cnt": 0, "=": 0, "+": 0, "-": 0, "steer": 0, "limited": 0, "saturated": 0, "dpp": 0}) + + def update(self, sm): + self.msg_cnt += 1 + + lateralControlState = sm['controlsState'].lateralControlState + control_type = list(lateralControlState.to_dict().keys())[0] + control_state = lateralControlState.__getattr__(control_type) v_ego = sm['carState'].vEgo active = sm['controlsState'].active @@ -77,10 +55,10 @@ if __name__ == "__main__": d_path_points = sm['lateralPlan'].dPathPoints # must be engaged, not at standstill, not overriding steering, and not changing lanes if active and not standstill and not overriding and not changing_lanes: - cnt += 1 + self.cnt += 1 # wait 5 seconds after engage / standstill / override / lane change - if cnt >= 500: + if self.cnt >= 500: actual_angle = control_state.steeringAngleDeg desired_angle = control_state.steeringAngleDesiredDeg @@ -91,41 +69,88 @@ if __name__ == "__main__": angle_error = round(angle_error, 2) angle_abs = int(abs(round(desired_angle, 0))) - for group, group_props in all_groups.items(): + for group, group_props in self.all_groups.items(): if v_ego > group_props[0]: # collect stats - speed_group_stats[group][angle_abs]["cnt"] += 1 - speed_group_stats[group][angle_abs]["err"] += angle_error - speed_group_stats[group][angle_abs]["steer"] += abs(steer) + self.speed_group_stats[group][angle_abs]["cnt"] += 1 + self.speed_group_stats[group][angle_abs]["err"] += angle_error + self.speed_group_stats[group][angle_abs]["steer"] += abs(steer) if len(d_path_points): - speed_group_stats[group][angle_abs]["dpp"] += abs(d_path_points[0]) + self.speed_group_stats[group][angle_abs]["dpp"] += abs(d_path_points[0]) if steer_limited: - speed_group_stats[group][angle_abs]["limited"] += 1 + self.speed_group_stats[group][angle_abs]["limited"] += 1 if control_state.saturated: - speed_group_stats[group][angle_abs]["saturated"] += 1 + self.speed_group_stats[group][angle_abs]["saturated"] += 1 if actual_angle == desired_angle: - speed_group_stats[group][angle_abs]["="] += 1 + self.speed_group_stats[group][angle_abs]["="] += 1 else: if desired_angle == 0.: overshoot = True else: overshoot = desired_angle < actual_angle if desired_angle > 0. else desired_angle > actual_angle - speed_group_stats[group][angle_abs]["+" if overshoot else "-"] += 1 + self.speed_group_stats[group][angle_abs]["+" if overshoot else "-"] += 1 break else: - cnt = 0 + self.cnt = 0 - if msg_cnt % 100 == 0: + if self.msg_cnt % 100 == 0: print(chr(27) + "[2J") - if cnt != 0: + if self.cnt != 0: print("COLLECTING ...\n") else: print("DISABLED (not active, standstill, steering override, or lane change)\n") - for group in display_groups: - if len(speed_group_stats[group]) > 0: - print(f"speed group: {group:10s} {all_groups[group][1]:>96s}") + for group in self.display_groups: + if len(self.speed_group_stats[group]) > 0: + print(f"speed group: {group:10s} {self.all_groups[group][1]:>96s}") print(f" {'-'*118}") - for k in sorted(speed_group_stats[group].keys()): - v = speed_group_stats[group][k] + for k in sorted(self.speed_group_stats[group].keys()): + v = self.speed_group_stats[group][k] print(f' {k:#2}° | actuator:{int(v["steer"] / v["cnt"] * 100):#3}% | error: {round(v["err"] / v["cnt"], 2):2.2f}° | -:{int(v["-"] / v["cnt"] * 100):#3}% | =:{int(v["="] / v["cnt"] * 100):#3}% | +:{int(v["+"] / v["cnt"] * 100):#3}% | lim:{v["limited"]:#5} | sat:{v["saturated"]:#5} | path dev: {round(v["dpp"] / v["cnt"], 2):2.2f}m | total: {v["cnt"]:#5}') print("") + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Steering accuracy measurement tool') + parser.add_argument('--route', help="route name") + parser.add_argument('--addr', default='127.0.0.1', help="IP address for optional ZMQ listener, default to msgq") + parser.add_argument('--group', default='all', help="speed group to display, [crawl|slow|medium|fast|veryfast|germany|all], default to all") + parser.add_argument('--cache', default=False, action='store_true', help="use cached data, default to False") + args = parser.parse_args() + + if args.cache: + os.environ['FILEREADER_CACHE'] = '1' + + tool = SteeringAccuracyTool(args) + + if args.route is not None: + print(f"loading {args.route}...") + lr = logreader_from_route_or_segment(args.route, sort_by_time=True) + + sm = {} + for msg in lr: + if msg.which() == 'carState': + sm['carState'] = msg.carState + elif msg.which() == 'carControl': + sm['carControl'] = msg.carControl + elif msg.which() == 'controlsState': + sm['controlsState'] = msg.controlsState + elif msg.which() == 'lateralPlan': + sm['lateralPlan'] = msg.lateralPlan + + if msg.which() == 'carControl' and 'carState' in sm and 'controlsState' in sm and 'lateralPlan' in sm: + tool.update(sm) + + else: + if args.addr != "127.0.0.1": + os.environ["ZMQ"] = "1" + messaging.context = messaging.Context() + + carControl = messaging.sub_sock('carControl', addr=args.addr, conflate=True) + sm = messaging.SubMaster(['carState', 'carControl', 'controlsState', 'lateralPlan'], addr=args.addr) + time.sleep(1) # Make sure all submaster data is available before going further + + print("waiting for messages...") + while messaging.recv_one(carControl): + sm.update() + tool.update(sm) From a19b5b91d2bcc0cd405599193828b9e9e187c52e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 24 Nov 2022 19:17:36 -0700 Subject: [PATCH 0366/1179] longcontrol: ignore cruise standstill if interceptor (#26597) * ignore standstill * cmt * standstill * rm cmt * flip --- selfdrive/controls/lib/longcontrol.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 92a4f1f99b..545a4c43ff 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -10,12 +10,14 @@ LongCtrlState = car.CarControl.Actuators.LongControlState def long_control_state_trans(CP, active, long_control_state, v_ego, v_target, v_target_1sec, brake_pressed, cruise_standstill): + # Ignore cruise standstill if car has a gas interceptor + cruise_standstill = cruise_standstill and not CP.enableGasInterceptor accelerating = v_target_1sec > v_target planned_stop = (v_target < CP.vEgoStopping and v_target_1sec < CP.vEgoStopping and not accelerating) stay_stopped = (v_ego < CP.vEgoStopping and - (brake_pressed or cruise_standstill)) + (brake_pressed or cruise_standstill)) stopping_condition = planned_stop or stay_stopped starting_condition = (v_target_1sec > CP.vEgoStarting and From 1efc8b9c78880778f4f604058c639ebdb2e12ff5 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Fri, 25 Nov 2022 13:20:20 +0100 Subject: [PATCH 0367/1179] Fix Tesla cancel button definition (#26596) misinterpreted the dbc --- selfdrive/car/tesla/values.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/tesla/values.py b/selfdrive/car/tesla/values.py index e28666c625..750fe885e8 100644 --- a/selfdrive/car/tesla/values.py +++ b/selfdrive/car/tesla/values.py @@ -99,8 +99,8 @@ BUTTONS = [ Button(car.CarState.ButtonEvent.Type.rightBlinker, "STW_ACTN_RQ", "TurnIndLvr_Stat", [2]), Button(car.CarState.ButtonEvent.Type.accelCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [4, 16]), Button(car.CarState.ButtonEvent.Type.decelCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [8, 32]), - Button(car.CarState.ButtonEvent.Type.cancel, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [2]), - Button(car.CarState.ButtonEvent.Type.resumeCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [1]), + Button(car.CarState.ButtonEvent.Type.cancel, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [1]), + Button(car.CarState.ButtonEvent.Type.resumeCruise, "STW_ACTN_RQ", "SpdCtrlLvr_Stat", [2]), ] class CarControllerParams: From 3253b8590002fa5f56e003add3f5f47a21870873 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 25 Nov 2022 17:00:58 -0700 Subject: [PATCH 0368/1179] Toyota: alert when in standstill (#26585) * add resume required alert * possibly need this (pressing resume with brake held does nothing) * better text (has both meanings) * try this * Revert "try this" This reverts commit 5b2991929b62f5bcd9bfa0767d709b5fe83b094b. * no alert with interceptor * check long --- selfdrive/car/toyota/interface.py | 23 +++++++++++++---------- selfdrive/controls/lib/events.py | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 3f4edb36d2..0139c692c1 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -247,16 +247,19 @@ class CarInterface(CarInterfaceBase): # events events = self.create_common_events(ret) - if self.CS.low_speed_lockout and self.CP.openpilotLongitudinalControl: - events.add(EventName.lowSpeedLockout) - if ret.vEgo < self.CP.minEnableSpeed and self.CP.openpilotLongitudinalControl: - events.add(EventName.belowEngageSpeed) - if c.actuators.accel > 0.3: - # some margin on the actuator to not false trigger cancellation while stopping - events.add(EventName.speedTooLow) - if ret.vEgo < 0.001: - # while in standstill, send a user alert - events.add(EventName.manualRestart) + if self.CP.openpilotLongitudinalControl: + if ret.cruiseState.standstill and not ret.brakePressed and not self.CP.enableGasInterceptor: + events.add(EventName.resumeRequired) + if self.CS.low_speed_lockout: + events.add(EventName.lowSpeedLockout) + if ret.vEgo < self.CP.minEnableSpeed: + events.add(EventName.belowEngageSpeed) + if c.actuators.accel > 0.3: + # some margin on the actuator to not false trigger cancellation while stopping + events.add(EventName.speedTooLow) + if ret.vEgo < 0.001: + # while in standstill, send a user alert + events.add(EventName.manualRestart) ret.events = events.to_msg() diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 1ed2ffa865..ad10b8f0bd 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -501,7 +501,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { EventName.resumeRequired: { ET.WARNING: Alert( "STOPPED", - "Press Resume to Go", + "Press Resume to Exit Standstill", AlertStatus.userPrompt, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.none, .2), }, From 38cd262de3436a3a239210c6e8c71933e6a79871 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:55:09 -0500 Subject: [PATCH 0369/1179] VW MQB: Add FW for 2022 Volkswagen Arteon (#26603) --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index f24448adbc..5423f09658 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -280,12 +280,14 @@ FW_VERSIONS = { CAR.ARTEON_MK1: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x873G0906259F \xf1\x890004', + b'\xf1\x873G0906259N \xf1\x890004', b'\xf1\x873G0906259P \xf1\x890001', b'\xf1\x875NA907115H \xf1\x890002', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158L \xf1\x893611', b'\xf1\x870GC300011L \xf1\x891401', + b'\xf1\x870GC300014M \xf1\x892802', b'\xf1\x870GC300040P \xf1\x891401', ], (Ecu.srs, 0x715, None): [ @@ -297,8 +299,10 @@ FW_VERSIONS = { b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571B41815A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571B00817A1', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\00567B0020800', + b'\xf1\x875WA907145M \xf1\x891051\xf1\x82\x002MB4092M7N', ], (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x872Q0907572AA\xf1\x890396', b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x875Q0907572J \xf1\x890654', ], From 82158c8378a34ab0d82566d1149e1769e877c4ac Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Mon, 28 Nov 2022 17:55:57 -0500 Subject: [PATCH 0370/1179] VW PQ: Fix cruise fault detection, cleanup (#26588) --- selfdrive/car/volkswagen/carstate.py | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 7d0a3d4dca..c82dc08007 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -222,10 +222,11 @@ class CarState(CarStateBase): # Update ACC radar status. self.acc_type = 0 # TODO: this is ACC "basic" with nonzero min speed, support FtS (1) later ret.cruiseState.available = bool(pt_cp.vl["Motor_5"]["GRA_Hauptschalter"]) - ret.cruiseState.enabled = bool(pt_cp.vl["Motor_2"]["GRA_Status"]) + ret.cruiseState.enabled = pt_cp.vl["Motor_2"]["GRA_Status"] in (1, 2) if self.CP.pcmCruise: ret.accFaulted = ext_cp.vl["ACC_GRA_Anziege"]["ACA_StaACC"] in (6, 7) - # TODO: update opendbc with PQ TSK state for OP long accFaulted + else: + ret.accFaulted = pt_cp.vl["Motor_2"]["GRA_Status"] == 3 # Update ACC setpoint. When the setpoint reads as 255, the driver has not # yet established an ACC setpoint, so treat it as zero. @@ -485,15 +486,15 @@ class MqbExtraSignals: # Additional signal and message lists for optional or bus-portable controllers fwd_radar_signals = [ ("ACC_Wunschgeschw_02", "ACC_02"), # ACC set speed - ("ACC_Typ", "ACC_06"), # Basic vs F2S vs SNG + ("ACC_Typ", "ACC_06"), # Basic vs FtS vs SnG ("AWV2_Freigabe", "ACC_10"), # FCW brake jerk release ("ANB_Teilbremsung_Freigabe", "ACC_10"), # AEB partial braking release ("ANB_Zielbremsung_Freigabe", "ACC_10"), # AEB target braking release ] fwd_radar_checks = [ - ("ACC_06", 50), # From J428 ACC radar control module - ("ACC_10", 50), # From J428 ACC radar control module - ("ACC_02", 17), # From J428 ACC radar control module + ("ACC_06", 50), # From J428 ACC radar control module + ("ACC_10", 50), # From J428 ACC radar control module + ("ACC_02", 17), # From J428 ACC radar control module ] bsm_radar_signals = [ ("SWA_Infostufe_SWA_li", "SWA_01"), # Blind spot object info, left @@ -502,24 +503,24 @@ class MqbExtraSignals: ("SWA_Warnung_SWA_re", "SWA_01"), # Blind spot object warning, right ] bsm_radar_checks = [ - ("SWA_01", 20), # From J1086 Lane Change Assist + ("SWA_01", 20), # From J1086 Lane Change Assist ] class PqExtraSignals: # Additional signal and message lists for optional or bus-portable controllers fwd_radar_signals = [ - ("ACA_StaACC", "ACC_GRA_Anziege", 0), # ACC drivetrain coordinator status - ("ACA_V_Wunsch", "ACC_GRA_Anziege", 0), # ACC set speed + ("ACA_StaACC", "ACC_GRA_Anziege"), # ACC drivetrain coordinator status + ("ACA_V_Wunsch", "ACC_GRA_Anziege"), # ACC set speed ] fwd_radar_checks = [ - ("ACC_GRA_Anziege", 25), # From J428 ACC radar control module + ("ACC_GRA_Anziege", 25), # From J428 ACC radar control module ] bsm_radar_signals = [ - ("SWA_Infostufe_SWA_li", "SWA_1", 0), # Blind spot object info, left - ("SWA_Warnung_SWA_li", "SWA_1", 0), # Blind spot object warning, left - ("SWA_Infostufe_SWA_re", "SWA_1", 0), # Blind spot object info, right - ("SWA_Warnung_SWA_re", "SWA_1", 0), # Blind spot object warning, right + ("SWA_Infostufe_SWA_li", "SWA_1"), # Blind spot object info, left + ("SWA_Warnung_SWA_li", "SWA_1"), # Blind spot object warning, left + ("SWA_Infostufe_SWA_re", "SWA_1"), # Blind spot object info, right + ("SWA_Warnung_SWA_re", "SWA_1"), # Blind spot object warning, right ] bsm_radar_checks = [ - ("SWA_1", 20), # From J1086 Lane Change Assist + ("SWA_1", 20), # From J1086 Lane Change Assist ] From 08b49e5671c04aaa17d8b56e2351d1bd14195dae Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 28 Nov 2022 15:00:37 -0800 Subject: [PATCH 0371/1179] IsoTpParallelQuery: log errors in qlogs (#26609) log these in qlogs --- selfdrive/car/isotp_parallel_query.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py index 4b4bdcc0ca..d9c658a14c 100644 --- a/selfdrive/car/isotp_parallel_query.py +++ b/selfdrive/car/isotp_parallel_query.py @@ -137,17 +137,17 @@ class IsoTpParallelQuery: else: response_timeouts[tx_addr] = 0 request_done[tx_addr] = True - cloudlog.warning(f"iso-tp query bad response: {tx_addr} - 0x{dat.hex()}") + cloudlog.error(f"iso-tp query bad response: {tx_addr} - 0x{dat.hex()}") cur_time = time.monotonic() if cur_time - max(response_timeouts.values()) > 0: for tx_addr in msgs: if request_counter[tx_addr] > 0 and not request_done[tx_addr]: - cloudlog.warning(f"iso-tp query timeout after receiving response: {tx_addr}") + cloudlog.error(f"iso-tp query timeout after receiving response: {tx_addr}") break if cur_time - start_time > total_timeout: - cloudlog.warning("iso-tp query timeout while receiving data") + cloudlog.error("iso-tp query timeout while receiving data") break return results From 909a884dc5d2aaaff270e86d2707b51037c87bc4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 29 Nov 2022 07:43:27 +0800 Subject: [PATCH 0372/1179] Cabana: fix segfault in dragging zoom (#26598) fix segfault --- tools/cabana/chartswidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 6e1f2e110c..a3faab0a20 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -398,8 +398,8 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && rubber && rubber->isVisible()) { rubber->hide(); QRectF rect = rubber->geometry().normalized(); - double min = chart()->mapToValue(rect.topLeft()).x(); - double max = chart()->mapToValue(rect.bottomRight()).x(); + double min = std::floor(chart()->mapToValue(rect.topLeft()).x() * 10.0) / 10.0; + double max = std::floor(chart()->mapToValue(rect.bottomRight()).x() * 10.0) / 10.0; if (rubber->width() <= 0) { // no rubber dragged, seek to mouse position can->seekTo(min); From 12ecc7b4bc42f70d73729367c32d200cca5afcc3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 28 Nov 2022 16:01:54 -0800 Subject: [PATCH 0373/1179] Hyundai: remove custom accel limit function for default values (#26611) * Update interface.py * Update interface.py --- selfdrive/car/hyundai/interface.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 8738aabd17..3ecf5289ff 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from common.conversions import Conversions as CV -from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams +from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -17,10 +17,6 @@ BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: Bu class CarInterface(CarInterfaceBase): - @staticmethod - def get_pid_accel_limits(CP, current_speed, cruise_speed): - return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX - @staticmethod def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[], experimental_long=False): # pylint: disable=dangerous-default-value ret = CarInterfaceBase.get_std_params(candidate, fingerprint) From a48ec655ac4983145bc93c712ecabac75b886e11 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 29 Nov 2022 01:13:54 +0100 Subject: [PATCH 0374/1179] CI: gps test hackrf support (#26364) * first ignore * init gps test * make LimeGPS git clone * revert ignore * . * remove prebuilt bins * gps test v1 * add static signal gen script * update readme * remove LD_PRELOAD by using rpath, update values after testing * . * remove LD_PRELOAD * . * fix README * . * . * . * gps test v1 * cleanUp * init * update fuzzy tests * . * finalize qcom gps tests * . * . * . * add downloader * finalize unit tests * . * . * inc limeGPS startup time * tmp * loosen init time * . * . * . * add ublox warmstart test * . * improve location tests * . * . * . * . * . * . * . * . * last cleanUp * . * . * add hackrf support * hackrf support * . * . * . * . * . * . Co-authored-by: Kurt Nistelberger --- tools/gpstest/.gitignore | 4 +- tools/gpstest/patches/hackrf.patch | 44 +++++++++++ tools/gpstest/setup_hackrf.sh | 21 +++++ tools/gpstest/simulate_gps_signal.py | 110 +++++++++++++++++++-------- 4 files changed, 145 insertions(+), 34 deletions(-) create mode 100644 tools/gpstest/patches/hackrf.patch create mode 100755 tools/gpstest/setup_hackrf.sh diff --git a/tools/gpstest/.gitignore b/tools/gpstest/.gitignore index f11597286e..992088ef34 100644 --- a/tools/gpstest/.gitignore +++ b/tools/gpstest/.gitignore @@ -1,2 +1,4 @@ LimeGPS/ -LimeSuite/ \ No newline at end of file +LimeSuite/ +hackrf/ +gps-sdr-sim/ diff --git a/tools/gpstest/patches/hackrf.patch b/tools/gpstest/patches/hackrf.patch new file mode 100644 index 0000000000..afc9ac437b --- /dev/null +++ b/tools/gpstest/patches/hackrf.patch @@ -0,0 +1,44 @@ +diff --git a/host/hackrf-tools/src/CMakeLists.txt b/host/hackrf-tools/src/CMakeLists.txt +index 7115151c..a51388ba 100644 +--- a/host/hackrf-tools/src/CMakeLists.txt ++++ b/host/hackrf-tools/src/CMakeLists.txt +@@ -23,20 +23,20 @@ + + set(INSTALL_DEFAULT_BINDIR "bin" CACHE STRING "Appended to CMAKE_INSTALL_PREFIX") + +-find_package(FFTW REQUIRED) +-include_directories(${FFTW_INCLUDES}) +-get_filename_component(FFTW_LIBRARY_DIRS ${FFTW_LIBRARIES} DIRECTORY) +-link_directories(${FFTW_LIBRARY_DIRS}) ++#find_package(FFTW REQUIRED) ++#include_directories(${FFTW_INCLUDES}) ++#get_filename_component(FFTW_LIBRARY_DIRS ${FFTW_LIBRARIES} DIRECTORY) ++#link_directories(${FFTW_LIBRARY_DIRS}) + + SET(TOOLS + hackrf_transfer +- hackrf_spiflash +- hackrf_cpldjtag ++ #hackrf_spiflash ++ #hackrf_cpldjtag + hackrf_info +- hackrf_debug +- hackrf_clock +- hackrf_sweep +- hackrf_operacake ++ #hackrf_debug ++ #hackrf_clock ++ #hackrf_sweep ++ #hackrf_operacake + ) + + if(MSVC) +@@ -45,7 +45,7 @@ if(MSVC) + ) + LIST(APPEND TOOLS_LINK_LIBS ${FFTW_LIBRARIES}) + else() +- LIST(APPEND TOOLS_LINK_LIBS m fftw3f) ++ LIST(APPEND TOOLS_LINK_LIBS m)# fftw3f) + endif() + + if(NOT libhackrf_SOURCE_DIR) diff --git a/tools/gpstest/setup_hackrf.sh b/tools/gpstest/setup_hackrf.sh new file mode 100755 index 0000000000..e504ec9447 --- /dev/null +++ b/tools/gpstest/setup_hackrf.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +cd $DIR + +if [ ! -d gps-sdr-sim ]; then + git clone https://github.com/osqzss/gps-sdr-sim.git + cd gps-sdr-sim + make + cd .. +fi + +if [ ! -d hackrf ]; then + git clone https://github.com/greatscottgadgets/hackrf.git + cd hackrf/host + git apply ../../patches/hackrf.patch + cmake . + make +fi + diff --git a/tools/gpstest/simulate_gps_signal.py b/tools/gpstest/simulate_gps_signal.py index f1e5ad2028..a6aca1c404 100755 --- a/tools/gpstest/simulate_gps_signal.py +++ b/tools/gpstest/simulate_gps_signal.py @@ -36,38 +36,7 @@ def get_random_coords(lat, lon) -> Tuple[int, int]: # jump around the world return get_coords(lat, lon, 20, 20, 10, 20) -def check_availability() -> bool: - cmd = ["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"] - output = sp.check_output(cmd) - - if output.strip() == b"": - return False - - print(f"Device: {output.strip().decode('utf-8')}") - return True - -def main(lat, lon, jump_sim, contin_sim): - if not os.path.exists('LimeGPS'): - print("LimeGPS not found run 'setup.sh' first") - return - - if not os.path.exists('LimeSuite'): - print("LimeSuite not found run 'setup.sh' first") - return - - if not check_availability(): - print("No limeSDR device found!") - return - - rinex_file = download_rinex() - - if lat == 0 and lon == 0: - lat, lon = get_random_coords(47.2020, 15.7403) - - timeout = None - if jump_sim: - timeout = 30 - +def run_limeSDR_loop(lat, lon, contin_sim, rinex_file, timeout): while True: try: print(f"starting LimeGPS, Location: {lat},{lon}") @@ -86,17 +55,92 @@ def main(lat, lon, jump_sim, contin_sim): print(f"LimeGPS crashed: {str(e)}") print(f"stderr:\n{e.stderr.decode('utf-8')}")# pylint:disable=no-member + return if contin_sim: lat, lon = get_continuous_coords(lat, lon) else: lat, lon = get_random_coords(lat, lon) +def run_hackRF_loop(lat, lon, rinex_file, timeout): + + if timeout is not None: + print("no jump mode for hackrf!") + return + + try: + print(f"starting gps-sdr-sim, Location: {lat},{lon}") + # create 30second file and replay with hackrf endless + cmd = ["gps-sdr-sim/gps-sdr-sim", "-e", rinex_file, "-l", f"{lat},{lon},100", "-d", "30"] + sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) + # created in current working directory + except Exception: + print("Failed to generate gpssim.bin") + + try: + print("starting hackrf_transfer") + # create 30second file and replay with hackrf endless + cmd = ["hackrf/host/hackrf-tools/src/hackrf_transfer", "-t", "gpssim.bin", + "-f", "1575420000", "-s", "2600000", "-a", "1", "-R"] + sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) + except KeyboardInterrupt: + print("stopping hackrf_transfer") + return + except Exception as e: + print(f"hackrf_transfer crashed:{str(e)}") + + +def main(lat, lon, jump_sim, contin_sim, hackrf_mode): + + if hackrf_mode: + if not os.path.exists('hackrf'): + print("hackrf not found run 'setup_hackrf.sh' first") + return + + if not os.path.exists('gps-sdr-sim'): + print("gps-sdr-sim not found run 'setup_hackrf.sh' first") + return + + output = sp.check_output(["hackrf/host/hackrf-tools/src/hackrf_info"]) + if output.strip() == b"" or b"No HackRF boards found." in output: + print("No HackRF boards found!") + return + + else: + if not os.path.exists('LimeGPS'): + print("LimeGPS not found run 'setup.sh' first") + return + + if not os.path.exists('LimeSuite'): + print("LimeSuite not found run 'setup.sh' first") + return + + output = sp.check_output(["LimeSuite/builddir/LimeUtil/LimeUtil", "--find"]) + if output.strip() == b"": + print("No LimeSDR device found!") + return + print(f"Device: {output.strip().decode('utf-8')}") + + if lat == 0 and lon == 0: + lat, lon = get_random_coords(47.2020, 15.7403) + + rinex_file = download_rinex() + + timeout = None + if jump_sim: + timeout = 30 + + if not hackrf_mode: + run_limeSDR_loop(lat, lon, contin_sim, rinex_file, timeout) + else: + run_hackRF_loop(lat, lon, rinex_file, timeout) + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Simulate static [or random jumping] GPS signal.") parser.add_argument("lat", type=float, nargs='?', default=0) parser.add_argument("lon", type=float, nargs='?', default=0) parser.add_argument("--jump", action="store_true", help="signal that jumps around the world") parser.add_argument("--contin", action="store_true", help="continuously/slowly moving around the world") + parser.add_argument("--hackrf", action="store_true", help="hackrf mode (DEFAULT: LimeSDR)") args = parser.parse_args() - main(args.lat, args.lon, args.jump, args.contin) + main(args.lat, args.lon, args.jump, args.contin, args.hackrf) From 7b1122e831f0219c2f4c660cca6f45c1e8a3162a Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 29 Nov 2022 00:38:18 -0800 Subject: [PATCH 0375/1179] One-word grammar fix to docs/INTEGRATION.md (#26621) Grammar fix --- docs/INTEGRATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index 97b72e39d3..ba6291c1e3 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -8,4 +8,4 @@ Additionally, on specific supported cars (see ACC column in [supported cars](CAR * Stock ACC is replaced by openpilot ACC. * openpilot FCW operates in addition to stock FCW. -openpilot should preserve all other vehicle's stock features, including, but are not limited to: FCW, Automatic Emergency Braking (AEB), auto high-beam, blind spot warning, and side collision warning. +openpilot should preserve all other vehicle's stock features, including, but not limited to: FCW, Automatic Emergency Braking (AEB), auto high-beam, blind spot warning, and side collision warning. From b18dfef8a6fdd1b38be316193f704b380e8f0dd2 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Tue, 29 Nov 2022 03:03:02 -0600 Subject: [PATCH 0376/1179] Add missing RAV4_TSS2 ABS f/w (#26617) `@IDJ#0879` 2019 Toyota RAV4 (ICE) DongleID/route e7cd4ae3bee72b52|2022-11-29--14-33-40 --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 6d6c03df71..4f2ab478c7 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1326,6 +1326,7 @@ FW_VERSIONS = { b'\x01F15260R302\x00\x00\x00\x00\x00\x00', b'\x01F152642551\x00\x00\x00\x00\x00\x00', b'\x01F152642561\x00\x00\x00\x00\x00\x00', + b'\x01F152642601\x00\x00\x00\x00\x00\x00', b'\x01F152642700\x00\x00\x00\x00\x00\x00', b'\x01F152642701\x00\x00\x00\x00\x00\x00', b'\x01F152642710\x00\x00\x00\x00\x00\x00', From 67fb3441463976d016a6ca0499abdc8691238f2d Mon Sep 17 00:00:00 2001 From: James <91348155+FrogAi@users.noreply.github.com> Date: Tue, 29 Nov 2022 02:05:38 -0700 Subject: [PATCH 0377/1179] Fixed typo in CARLA README.md (#26615) --- tools/sim/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sim/README.md b/tools/sim/README.md index 40603f3f71..69a89aefab 100644 --- a/tools/sim/README.md +++ b/tools/sim/README.md @@ -6,7 +6,7 @@ openpilot implements a [bridge](bridge.py) that allows it to run in the [CARLA s ## System Requirements openpilot doesn't have any extreme hardware requirements, however CARLA requires an NVIDIA graphics card and is very resource-intensive and may not run smoothly on your system. -For this case, we have a the simulator in low quality by default. +For this case, we have the simulator in low quality by default. You can also check out the [CARLA python documentation](https://carla.readthedocs.io/en/latest/python_api/) to find more parameters to tune that might increase performance on your system. From b2fd699c21656d6cc7959c3ecd900b5a08456950 Mon Sep 17 00:00:00 2001 From: uppercaseVar <33802760+uppercaseVar@users.noreply.github.com> Date: Tue, 29 Nov 2022 01:08:58 -0800 Subject: [PATCH 0378/1179] Add ECU fw for 2016 Golf GTI (#26591) Added ECU for 2016 Golf GTI --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 5423f09658..c96f6decbf 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -377,6 +377,7 @@ FW_VERSIONS = { b'\xf1\x870EA906016Q \xf1\x895993', b'\xf1\x870EA906016S \xf1\x897207', b'\xf1\x875G0906259 \xf1\x890007', + b'\xf1\x875G0906259D \xf1\x890002', b'\xf1\x875G0906259J \xf1\x890002', b'\xf1\x875G0906259L \xf1\x890002', b'\xf1\x875G0906259N \xf1\x890003', @@ -412,6 +413,7 @@ FW_VERSIONS = { b'\xf1\x870D9300012 \xf1\x895045', b'\xf1\x870D9300014M \xf1\x895004', b'\xf1\x870D9300014Q \xf1\x895006', + b'\xf1\x870D9300020J \xf1\x894902', b'\xf1\x870D9300020Q \xf1\x895201', b'\xf1\x870D9300020S \xf1\x895201', b'\xf1\x870D9300040A \xf1\x893613', @@ -459,6 +461,7 @@ FW_VERSIONS = { b'\xf1\x873Q0909144F \xf1\x895043\xf1\x82\x0561A01612A0', b'\xf1\x873Q0909144H \xf1\x895061\xf1\x82\x0566A0J612A1', b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566A00514A1', + b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566A01613A1', b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566A0J712A1', b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571A0J714A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571A0JA15A1', From f64e69eb11e1b9efc5fb3f9b893d1e42a9809d0f Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 29 Nov 2022 01:13:43 -0800 Subject: [PATCH 0379/1179] Hyundai: add more Kia K5 FW (#26590) * add some values * consistent , * Update selfdrive/car/hyundai/values.py * Update selfdrive/car/hyundai/values.py Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index ecba7b7494..16ff68f08a 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1021,11 +1021,13 @@ FW_VERSIONS = { b'\xf1\x8799110L2000\xf1\000DL3_ SCC FHCUP 1.00 1.03 99110-L2000 ', b'\xf1\x8799110L2100\xf1\x00DL3_ SCC F-CUP 1.00 1.03 99110-L2100 ', b'\xf1\x8799110L2100\xf1\x00DL3_ SCC FHCUP 1.00 1.03 99110-L2100 ', + b'\xf1\x00DL3_ SCC F-CUP 1.00 1.03 99110-L2100 ', ], (Ecu.eps, 0x7D4, None): [ b'\xf1\x8756310-L3110\xf1\000DL3 MDPS C 1.00 1.01 56310-L3110 4DLAC101', b'\xf1\x8756310-L3220\xf1\x00DL3 MDPS C 1.00 1.01 56310-L3220 4DLAC101', b'\xf1\x8757700-L3000\xf1\x00DL3 MDPS R 1.00 1.02 57700-L3000 4DLAP102', + b'\xf1\x00DL3 MDPS C 1.00 1.01 56310-L3220 4DLAC101', ], (Ecu.fwdCamera, 0x7C4, None): [ b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.03 99210-L3000 200915', @@ -1036,6 +1038,7 @@ FW_VERSIONS = { b'\xf1\x8758910-L3200\xf1\000DL ESC \006 101 \004\002 58910-L3200', b'\xf1\x8758910-L3800\xf1\x00DL ESC \t 101 \x07\x02 58910-L3800', b'\xf1\x8758910-L3600\xf1\x00DL ESC \x03 100 \x08\x02 58910-L3600', + b'\xf1\x00DL ESC \t 100 \x06\x02 58910-L3800', ], (Ecu.engine, 0x7E0, None): [ b'\xf1\x87391212MKT0', @@ -1048,6 +1051,7 @@ FW_VERSIONS = { b'\xf1\x87SALFEA6046104GK2wvwgeTeFg\x88\x96xwwwwffvfe?\xfd\xff\x86fo\xff\x97A\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL2T16NB1ia\x0b\xb8', b'\xf1\x87SCMSAA8572454GK1\x87x\x87\x88Vf\x86hgwvwvwwgvwwgT?\xfb\xff\x97fo\xffH\xb8\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18', b'\xf1\x87954A02N300\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 WDL3T25XXX730NS2b\x1f\xb8%', + b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18', ], }, CAR.KONA_EV: { From b4da592a3ca9bfda7766ecb5021a8ce17dfd6abe Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 29 Nov 2022 01:54:59 -0800 Subject: [PATCH 0380/1179] mock: remove steering angle (#26614) * fix yaw rate in mock interface * clean that up * revert * clean up --- selfdrive/car/mock/interface.py | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index a3194cd79e..2be1bcb4a3 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -1,31 +1,22 @@ #!/usr/bin/env python3 -import math from cereal import car -from common.conversions import Conversions as CV from system.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.car import gen_empty_fingerprint, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase + # mocked car interface to work with chffrplus -TS = 0.01 # 100Hz -YAW_FR = 0.2 # ~0.8s time constant on yaw rate filter -# low pass gain -LPG = 2 * math.pi * YAW_FR * TS / (1 + 2 * math.pi * YAW_FR * TS) - - class CarInterface(CarInterfaceBase): def __init__(self, CP, CarController, CarState): super().__init__(CP, CarController, CarState) cloudlog.debug("Using Mock Car Interface") - self.sm = messaging.SubMaster(['gyroscope', 'gpsLocation', 'gpsLocationExternal']) + self.sm = messaging.SubMaster(['gpsLocation', 'gpsLocationExternal']) self.speed = 0. self.prev_speed = 0. - self.yaw_rate = 0. - self.yaw_rate_meas = 0. @staticmethod def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): @@ -45,11 +36,6 @@ class CarInterface(CarInterfaceBase): # returns a car.CarState def _update(self, c): self.sm.update(0) - - # get basic data from phone and gps since CAN isn't connected - if self.sm.updated['gyroscope']: - self.yaw_rate_meas = -self.sm['gyroscope'].gyroUncalibrated.v[0] - gps_sock = 'gpsLocationExternal' if self.sm.rcv_frame['gpsLocationExternal'] > 1 else 'gpsLocation' if self.sm.updated[gps_sock]: self.prev_speed = self.speed @@ -61,10 +47,9 @@ class CarInterface(CarInterfaceBase): # speeds ret.vEgo = self.speed ret.vEgoRaw = self.speed - a = self.speed - self.prev_speed - ret.aEgo = a - ret.brakePressed = a < -0.5 + ret.aEgo = self.speed - self.prev_speed + ret.brakePressed = ret.aEgo < -0.5 ret.standstill = self.speed < 0.01 ret.wheelSpeeds.fl = self.speed @@ -72,10 +57,6 @@ class CarInterface(CarInterfaceBase): ret.wheelSpeeds.rl = self.speed ret.wheelSpeeds.rr = self.speed - self.yawRate = LPG * self.yaw_rate_meas + (1. - LPG) * self.yaw_rate - curvature = self.yaw_rate / max(self.speed, 1.) - ret.steeringAngleDeg = curvature * self.CP.steerRatio * self.CP.wheelbase * CV.RAD_TO_DEG - return ret def apply(self, c): From 0706b03e8cf41f7d51c9a42f01bda2084bfe3be6 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 29 Nov 2022 10:47:13 -0800 Subject: [PATCH 0381/1179] [controlsd] Toyota Prius 2017 (#26455) * increase lag on prius * better offline values computation * split prius ecu more, set deadzone to 0 * add deadzone back * replace deadzone with slack * reduce deadzone to 0.2 * update refs --- selfdrive/car/interfaces.py | 4 ++-- selfdrive/car/torque_data/params.yaml | 3 ++- selfdrive/car/toyota/interface.py | 4 ++-- selfdrive/controls/lib/drive_helpers.py | 6 ++++++ selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 8e8872a539..820e429cc4 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -11,7 +11,7 @@ from common.kalman.simple_kalman import KF1D from common.numpy_fast import interp from common.realtime import DT_CTRL from selfdrive.car import apply_hysteresis, gen_empty_fingerprint -from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_deadzone +from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_slack from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.vehicle_model import VehicleModel @@ -109,7 +109,7 @@ class CarInterfaceBase(ABC): def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, friction_compensation): # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) friction_interp = interp( - apply_deadzone(lateral_accel_error, lateral_accel_deadzone), + apply_slack(lateral_accel_error, lateral_accel_deadzone), [-FRICTION_THRESHOLD, FRICTION_THRESHOLD], [-torque_params.friction, torque_params.friction] ) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index a9023b4edc..b4dbaf8564 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -77,7 +77,8 @@ TOYOTA HIGHLANDER 2020: [2.022340166827233, 1.6183134804881791, 0.14592306380054 TOYOTA HIGHLANDER HYBRID 2018: [1.752033, 1.6433903296845025, 0.144600] TOYOTA HIGHLANDER HYBRID 2020: [1.901174, 2.104015182965606, 0.14447040132184993] TOYOTA MIRAI 2021: [2.506899832157829, 1.7417213930750164, 0.20182618449440565] -TOYOTA PRIUS 2017: [1.746445, 1.5023147650693636, 0.151515] +TOYOTA PRIUS 2017: [1.60, 1.5023147650693636, 0.151515] +TOYOTA PRIUS 2017 x060: [1.746445, 1.5023147650693636, 0.17] TOYOTA PRIUS TSS2 2021: [1.972600, 1.9104337425537743, 0.170968] TOYOTA RAV4 2017: [2.085695074355425, 2.2142832316984733, 0.13339165270103975] TOYOTA RAV4 2019: [2.331293, 2.0993589721530252, 0.129822] diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 0139c692c1..7ee5ac0d0e 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -42,7 +42,8 @@ class CarInterface(CarInterfaceBase): # Only give steer angle deadzone to for bad angle sensor prius for fw in car_fw: if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00': - steering_angle_deadzone_deg = 1.0 + steering_angle_deadzone_deg = 0.2 + ret.steerActuatorDelay = 0.25 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg) elif candidate == CAR.PRIUS_V: @@ -51,7 +52,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 17.4 tire_stiffness_factor = 0.5533 ret.mass = 3340. * CV.LB_TO_KG + STD_CARGO_KG - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg) elif candidate in (CAR.RAV4, CAR.RAV4H): stop_and_go = True if (candidate in CAR.RAV4H) else False diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index f0dc2e9467..acef4bee8e 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -149,6 +149,12 @@ def apply_deadzone(error, deadzone): return error +def apply_slack(error, deadzone): + if (error > - deadzone) and (error < deadzone): + error = 0. + return error + + def rate_limit(new_value, last_value, dw_step, up_step): return clip(new_value, last_value + dw_step, last_value + up_step) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d4520d2935..71da0dff44 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -08ca448a6dcfc1edc4f9fedb2ea94ad6b2b69aa2 \ No newline at end of file +ddfaab44ae64a0d064b847e81080993b51b6b423 \ No newline at end of file From 44e9ea23bd6900d9d43216855bbc68704e4358ba Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 29 Nov 2022 14:15:16 -0500 Subject: [PATCH 0382/1179] VW PQ: Follow-to-Stop support (#26616) --- selfdrive/car/volkswagen/carstate.py | 4 +++- selfdrive/car/volkswagen/interface.py | 1 - selfdrive/car/volkswagen/pqcan.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index c82dc08007..263edbfc9d 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -220,7 +220,7 @@ class CarState(CarStateBase): ret.stockAeb = False # Update ACC radar status. - self.acc_type = 0 # TODO: this is ACC "basic" with nonzero min speed, support FtS (1) later + self.acc_type = ext_cp.vl["ACC_System"]["ACS_Typ_ACC"] ret.cruiseState.available = bool(pt_cp.vl["Motor_5"]["GRA_Hauptschalter"]) ret.cruiseState.enabled = pt_cp.vl["Motor_2"]["GRA_Status"] in (1, 2) if self.CP.pcmCruise: @@ -509,10 +509,12 @@ class MqbExtraSignals: class PqExtraSignals: # Additional signal and message lists for optional or bus-portable controllers fwd_radar_signals = [ + ("ACS_Typ_ACC", "ACC_System"), # Basic vs FtS (no SnG support on PQ) ("ACA_StaACC", "ACC_GRA_Anziege"), # ACC drivetrain coordinator status ("ACA_V_Wunsch", "ACC_GRA_Anziege"), # ACC set speed ] fwd_radar_checks = [ + ("ACC_System", 50), # From J428 ACC radar control module ("ACC_GRA_Anziege", 25), # From J428 ACC radar control module ] bsm_radar_signals = [ diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 816e7fcf34..e0bb917960 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -137,7 +137,6 @@ class CarInterface(CarInterfaceBase): elif candidate == CAR.SHARAN_MK2: ret.mass = 1639 + STD_CARGO_KG ret.wheelbase = 2.92 - ret.minEnableSpeed = 30 * CV.KPH_TO_MS ret.minSteerSpeed = 50 * CV.KPH_TO_MS ret.steerActuatorDelay = 0.2 diff --git a/selfdrive/car/volkswagen/pqcan.py b/selfdrive/car/volkswagen/pqcan.py index 0bcbf6abb3..6beb90c092 100644 --- a/selfdrive/car/volkswagen/pqcan.py +++ b/selfdrive/car/volkswagen/pqcan.py @@ -66,6 +66,7 @@ def create_acc_accel_control(packer, bus, acc_type, enabled, accel, acc_control, "ACS_Sta_ADR": acc_control, "ACS_StSt_Info": acc_control != 1, "ACS_Typ_ACC": acc_type, + "ACS_Anhaltewunsch": acc_type == 1 and stopping, "ACS_Sollbeschl": accel if acc_control == 1 else 3.01, "ACS_zul_Regelabw": 0.2 if acc_control == 1 else 1.27, "ACS_max_AendGrad": 3.0 if acc_control == 1 else 5.08, From f9bb024a464f8714a1edc7190985fcb612415eec Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 30 Nov 2022 03:42:56 +0800 Subject: [PATCH 0383/1179] Cabana: execute generate_dbc_json.py after building (#26620) * use env.command to generete json after build * Update tools/cabana/SConscript Co-authored-by: Shane Smiskol --- tools/cabana/SConscript | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 3ff4862800..52fe9e346d 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -17,10 +17,13 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_env.Execute('./generate_dbc_json.py --out car_fingerprint_to_dbc.json') cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) + +def generate_dbc_json(target, source, env): + env.Execute('tools/cabana/generate_dbc_json.py --out tools/cabana/car_fingerprint_to_dbc.json') +cabana_env.Command('generate_dbc_json', [], generate_dbc_json) From 860f441e2f122173c5034656aeed5706fd41e38f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 29 Nov 2022 11:49:13 -0800 Subject: [PATCH 0384/1179] Car interface: set common params after port (#26613) * remove pylint exception, _get_params takes no defaults * clean up * mock uses it too * unused * unused * fix that * bump * Update selfdrive/car/interfaces.py --- selfdrive/car/body/interface.py | 9 ++------- selfdrive/car/chrysler/interface.py | 10 ++-------- selfdrive/car/ford/interface.py | 14 +++----------- selfdrive/car/gm/interface.py | 9 ++------- selfdrive/car/honda/interface.py | 9 ++------- selfdrive/car/hyundai/interface.py | 10 ++-------- selfdrive/car/interfaces.py | 26 ++++++++++++++++++++++---- selfdrive/car/mazda/interface.py | 10 ++-------- selfdrive/car/mock/interface.py | 6 ++---- selfdrive/car/nissan/interface.py | 10 ++-------- selfdrive/car/subaru/interface.py | 10 ++-------- selfdrive/car/tesla/interface.py | 6 ++---- selfdrive/car/toyota/interface.py | 10 ++-------- selfdrive/car/volkswagen/interface.py | 11 +++-------- 14 files changed, 50 insertions(+), 100 deletions(-) diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index ae7ab89aab..638134be7f 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -2,16 +2,13 @@ import math from cereal import car from common.realtime import DT_CTRL -from selfdrive.car import scale_rot_inertia, scale_tire_stiffness, get_safety_config +from selfdrive.car import scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.body.values import SPEED_FROM_RPM class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=None, car_fw=None, experimental_long=False): - - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) - + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.notCar = True ret.carName = "body" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.body)] @@ -31,8 +28,6 @@ class CarInterface(CarInterfaceBase): ret.openpilotLongitudinalControl = True ret.steerControlType = car.CarParams.SteerControlType.angle - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) return ret diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 245e10650c..9b5e5a5ce5 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -1,21 +1,18 @@ #!/usr/bin/env python3 from cereal import car from panda import Panda -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.chrysler.values import CAR, DBC, RAM_HD, RAM_DT from selfdrive.car.interfaces import CarInterfaceBase class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "chrysler" - ret.dashcamOnly = candidate in RAM_HD ret.radarOffCan = DBC[candidate]['radar'] is None - ret.steerActuatorDelay = 0.1 ret.steerLimitTimer = 0.4 @@ -76,9 +73,6 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.44 - # starting with reasonable value for civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 4943db076f..913c3c926d 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from cereal import car from common.conversions import Conversions as CV -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.ford.values import CAR, Ecu, TransmissionType, GearShifter from selfdrive.car.interfaces import CarInterfaceBase @@ -10,12 +10,7 @@ CarParams = car.CarParams class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - if car_fw is None: - car_fw = [] - - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) - + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "ford" ret.dashcamOnly = True ret.safetyConfigs = [get_safety_config(CarParams.SafetyModel.ford)] @@ -24,7 +19,6 @@ class CarInterface(CarInterfaceBase): ret.steerControlType = CarParams.SteerControlType.angle ret.steerActuatorDelay = 0.4 ret.steerLimitTimer = 1.0 - tire_stiffness_factor = 1.0 if candidate == CAR.ESCAPE_MK4: ret.wheelbase = 2.71 @@ -60,10 +54,8 @@ class CarInterface(CarInterfaceBase): ret.minSteerSpeed = 0. ret.autoResumeSng = ret.minEnableSpeed == -1. - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.centerToFront = ret.wheelbase * 0.44 - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, - tire_stiffness_factor=tire_stiffness_factor) + ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) return ret def _update(self, c): diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index eb5ab7329a..7d38c60900 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -4,7 +4,7 @@ from math import fabs from panda import Panda from common.conversions import Conversions as CV -from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR from selfdrive.car.interfaces import CarInterfaceBase @@ -44,8 +44,7 @@ class CarInterface(CarInterfaceBase): return CarInterfaceBase.get_steer_feedforward_default @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "gm" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)] ret.autoResumeSng = False @@ -195,10 +194,6 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.4 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index e397f02838..990238ae5d 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -4,7 +4,7 @@ from panda import Panda from common.conversions import Conversions as CV from common.numpy_fast import interp from selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL, HONDA_BOSCH_RADARLESS -from selfdrive.car import STD_CARGO_KG, CivicParams, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, CivicParams, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.disable_ecu import disable_ecu @@ -29,8 +29,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS) @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[], experimental_long=False): # pylint: disable=dangerous-default-value - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "honda" if candidate in HONDA_BOSCH: @@ -291,10 +290,6 @@ class CarInterface(CarInterfaceBase): stop_and_go = candidate in (HONDA_BOSCH | {CAR.CIVIC}) or ret.enableGasInterceptor ret.minEnableSpeed = -1. if stop_and_go else 25.5 * CV.MPH_TO_MS - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 3ecf5289ff..c1fe8be4c2 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -4,7 +4,7 @@ from panda import Panda from common.conversions import Conversions as CV from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR -from selfdrive.car import STD_CARGO_KG, create_button_event, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.disable_ecu import disable_ecu @@ -18,9 +18,7 @@ BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: Bu class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[], experimental_long=False): # pylint: disable=dangerous-default-value - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) - + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "hyundai" ret.radarOffCan = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None @@ -267,10 +265,6 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.4 - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 820e429cc4..e03f1cfada 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -10,7 +10,7 @@ from common.conversions import Conversions as CV from common.kalman.simple_kalman import KF1D from common.numpy_fast import interp from common.realtime import DT_CTRL -from selfdrive.car import apply_hysteresis, gen_empty_fingerprint +from selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_slack from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.vehicle_model import VehicleModel @@ -87,10 +87,28 @@ class CarInterfaceBase(ABC): def get_pid_accel_limits(CP, current_speed, cruise_speed): return ACCEL_MIN, ACCEL_MAX + @classmethod + def get_params(cls, candidate: str, fingerprint: Optional[Dict[int, Dict[int, int]]] = None, car_fw: Optional[List[car.CarParams.CarFw]] = None, experimental_long: bool = False): + if fingerprint is None: + fingerprint = gen_empty_fingerprint() + + if car_fw is None: + car_fw = list() + + ret = CarInterfaceBase.get_std_params(candidate) + ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long) + + # Set common params using fields set by the car interface + # TODO: get actual value, for now starting with reasonable value for + # civic and scaling by mass and wheelbase + ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) + + return ret + @staticmethod @abstractmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - pass + def _get_params(ret: car.CarParams, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool): + raise NotImplementedError @staticmethod def init(CP, logcan, sendcan): @@ -121,7 +139,7 @@ class CarInterfaceBase(ABC): # returns a set of default params to avoid repetition in car specific params @staticmethod - def get_std_params(candidate, fingerprint): + def get_std_params(candidate): ret = car.CarParams.new_message() ret.carFingerprint = candidate diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 7c42431e33..fdd2439ff9 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -2,7 +2,7 @@ from cereal import car from common.conversions import Conversions as CV from selfdrive.car.mazda.values import CAR, LKAS_LIMITS -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase ButtonType = car.CarState.ButtonEvent.Type @@ -11,9 +11,7 @@ EventName = car.CarEvent.EventName class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) - + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "mazda" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)] ret.radarOffCan = True @@ -48,10 +46,6 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.41 - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 2be1bcb4a3..3ac487dbb7 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -2,7 +2,7 @@ from cereal import car from system.swaglog import cloudlog import cereal.messaging as messaging -from selfdrive.car import gen_empty_fingerprint, get_safety_config +from selfdrive.car import get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -19,12 +19,10 @@ class CarInterface(CarInterfaceBase): self.prev_speed = 0. @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "mock" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.noOutput)] ret.mass = 1700. - ret.rotationalInertia = 2500. ret.wheelbase = 2.70 ret.centerToFront = ret.wheelbase * 0.5 ret.steerRatio = 13. # reasonable diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index e095ceb461..194d7f06ae 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from cereal import car -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.nissan.values import CAR @@ -8,9 +8,7 @@ from selfdrive.car.nissan.values import CAR class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "nissan" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)] ret.autoResumeSng = False @@ -38,10 +36,6 @@ class CarInterface(CarInterfaceBase): ret.steerControlType = car.CarParams.SteerControlType.angle ret.radarOffCan = True - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index a920c02534..7dba8eaf23 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from cereal import car from panda import Panda -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.subaru.values import CAR, GLOBAL_GEN2, PREGLOBAL_CARS @@ -9,9 +9,7 @@ from selfdrive.car.subaru.values import CAR, GLOBAL_GEN2, PREGLOBAL_CARS class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) - + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "subaru" ret.radarOffCan = True ret.dashcamOnly = candidate in PREGLOBAL_CARS @@ -103,10 +101,6 @@ class CarInterface(CarInterfaceBase): else: raise ValueError(f"unknown car: {candidate}") - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 2eb29efb41..6573f4e4d9 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -2,14 +2,13 @@ from cereal import car from panda import Panda from selfdrive.car.tesla.values import CANBUS, CAR -from selfdrive.car import STD_CARGO_KG, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase class CarInterface(CarInterfaceBase): @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "tesla" # There is no safe way to do steer blending with user torque, @@ -51,7 +50,6 @@ class CarInterface(CarInterfaceBase): else: raise ValueError(f"Unsupported car: {candidate}") - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) return ret diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 7ee5ac0d0e..d3835d175b 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -3,7 +3,7 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams, NO_STOP_TIMER_CAR -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase EventName = car.CarEvent.EventName @@ -15,9 +15,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=[], experimental_long=False): # pylint: disable=dangerous-default-value - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) - + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "toyota" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] @@ -190,10 +188,6 @@ class CarInterface(CarInterfaceBase): ret.centerToFront = ret.wheelbase * 0.44 - # TODO: get actual value, for now starting with reasonable value for - # civic and scaling by mass and wheelbase - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by # mass and CG position, so all cars will have approximately similar dyn behaviors ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index e0bb917960..997cdfcfc1 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -1,8 +1,7 @@ from cereal import car from panda import Panda from common.conversions import Conversions as CV -from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, \ - gen_empty_fingerprint, get_safety_config +from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.volkswagen.values import CAR, PQ_CARS, CANBUS, NetworkLocation, TransmissionType, GearShifter @@ -22,8 +21,7 @@ class CarInterface(CarInterfaceBase): self.cp_ext = self.cp_cam @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, experimental_long=False): - ret = CarInterfaceBase.get_std_params(candidate, fingerprint) + def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "volkswagen" ret.radarOffCan = True @@ -74,7 +72,6 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.1 ret.steerLimitTimer = 0.4 ret.steerRatio = 15.6 # Let the params learner figure this out - tire_stiffness_factor = 1.0 # Let the params learner figure this out ret.lateralTuning.pid.kpBP = [0.] ret.lateralTuning.pid.kiBP = [0.] ret.lateralTuning.pid.kf = 0.00006 @@ -213,10 +210,8 @@ class CarInterface(CarInterfaceBase): raise ValueError(f"unsupported car {candidate}") ret.autoResumeSng = ret.minEnableSpeed == -1 - ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) ret.centerToFront = ret.wheelbase * 0.45 - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, - tire_stiffness_factor=tire_stiffness_factor) + ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) return ret # returns a car.CarState From 3a4f19f0ee454a9c8d7c55d66e794ef20c4b4f01 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 29 Nov 2022 12:46:08 -0800 Subject: [PATCH 0385/1179] [controlsd] Refactor apply_deadzone in Lateral Torque Control (#26626) rename apply_slack to apply_center_deadzone, remove unused prius offline values --- selfdrive/car/interfaces.py | 4 ++-- selfdrive/car/torque_data/params.yaml | 1 - selfdrive/controls/lib/drive_helpers.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index e03f1cfada..e062e783e5 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -11,7 +11,7 @@ from common.kalman.simple_kalman import KF1D from common.numpy_fast import interp from common.realtime import DT_CTRL from selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia -from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_slack +from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_center_deadzone from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.vehicle_model import VehicleModel @@ -127,7 +127,7 @@ class CarInterfaceBase(ABC): def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, friction_compensation): # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) friction_interp = interp( - apply_slack(lateral_accel_error, lateral_accel_deadzone), + apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), [-FRICTION_THRESHOLD, FRICTION_THRESHOLD], [-torque_params.friction, torque_params.friction] ) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index b4dbaf8564..124cf3d3b9 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -78,7 +78,6 @@ TOYOTA HIGHLANDER HYBRID 2018: [1.752033, 1.6433903296845025, 0.144600] TOYOTA HIGHLANDER HYBRID 2020: [1.901174, 2.104015182965606, 0.14447040132184993] TOYOTA MIRAI 2021: [2.506899832157829, 1.7417213930750164, 0.20182618449440565] TOYOTA PRIUS 2017: [1.60, 1.5023147650693636, 0.151515] -TOYOTA PRIUS 2017 x060: [1.746445, 1.5023147650693636, 0.17] TOYOTA PRIUS TSS2 2021: [1.972600, 1.9104337425537743, 0.170968] TOYOTA RAV4 2017: [2.085695074355425, 2.2142832316984733, 0.13339165270103975] TOYOTA RAV4 2019: [2.331293, 2.0993589721530252, 0.129822] diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index acef4bee8e..3d5ec8ac1d 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -149,7 +149,7 @@ def apply_deadzone(error, deadzone): return error -def apply_slack(error, deadzone): +def apply_center_deadzone(error, deadzone): if (error > - deadzone) and (error < deadzone): error = 0. return error From 712b9014d708ce77e87e2d1bb4dfe2d7665a8414 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 29 Nov 2022 12:50:27 -0800 Subject: [PATCH 0386/1179] Car interface: set tire stiffness in common function (#26625) * common stiffness * GM uses factors --- selfdrive/car/body/interface.py | 4 +--- selfdrive/car/chrysler/interface.py | 7 +------ selfdrive/car/ford/interface.py | 3 +-- selfdrive/car/interfaces.py | 8 +++++++- selfdrive/car/nissan/interface.py | 12 ++++-------- selfdrive/car/subaru/interface.py | 6 +----- selfdrive/car/tesla/interface.py | 4 +--- selfdrive/car/tests/test_car_interfaces.py | 2 ++ selfdrive/car/volkswagen/interface.py | 3 +-- 9 files changed, 19 insertions(+), 30 deletions(-) diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index 638134be7f..bc5b36e2ee 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -2,7 +2,7 @@ import math from cereal import car from common.realtime import DT_CTRL -from selfdrive.car import scale_tire_stiffness, get_safety_config +from selfdrive.car import get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.body.values import SPEED_FROM_RPM @@ -28,8 +28,6 @@ class CarInterface(CarInterfaceBase): ret.openpilotLongitudinalControl = True ret.steerControlType = car.CarParams.SteerControlType.angle - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) - return ret def _update(self, c): diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 9b5e5a5ce5..5e8fe3c44e 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from cereal import car from panda import Panda -from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.chrysler.values import CAR, DBC, RAM_HD, RAM_DT from selfdrive.car.interfaces import CarInterfaceBase @@ -72,11 +72,6 @@ class CarInterface(CarInterfaceBase): raise ValueError(f"Unsupported car: {candidate}") ret.centerToFront = ret.wheelbase * 0.44 - - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by - # mass and CG position, so all cars will have approximately similar dyn behaviors - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) - ret.enableBsm = 720 in fingerprint[0] return ret diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 913c3c926d..f3d77bc05a 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from cereal import car from common.conversions import Conversions as CV -from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.ford.values import CAR, Ecu, TransmissionType, GearShifter from selfdrive.car.interfaces import CarInterfaceBase @@ -55,7 +55,6 @@ class CarInterface(CarInterfaceBase): ret.autoResumeSng = ret.minEnableSpeed == -1. ret.centerToFront = ret.wheelbase * 0.44 - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) return ret def _update(self, c): diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index e062e783e5..0458178ee3 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -10,7 +10,7 @@ from common.conversions import Conversions as CV from common.kalman.simple_kalman import KF1D from common.numpy_fast import interp from common.realtime import DT_CTRL -from selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia +from selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_center_deadzone from selfdrive.controls.lib.events import Events from selfdrive.controls.lib.vehicle_model import VehicleModel @@ -103,6 +103,12 @@ class CarInterfaceBase(ABC): # civic and scaling by mass and wheelbase ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase) + # TODO: some car interfaces set stiffness factor + if ret.tireStiffnessFront == 0 or ret.tireStiffnessRear == 0: + # TODO: start from empirically derived lateral slip stiffness for the civic and scale by + # mass and CG position, so all cars will have approximately similar dyn behaviors + ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) + return ret @staticmethod diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 194d7f06ae..386e859089 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from cereal import car -from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.nissan.values import CAR @@ -18,6 +18,9 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.1 ret.steerRatio = 17 + ret.steerControlType = car.CarParams.SteerControlType.angle + ret.radarOffCan = True + if candidate in (CAR.ROGUE, CAR.XTRAIL): ret.mass = 1610 + STD_CARGO_KG ret.wheelbase = 2.705 @@ -33,13 +36,6 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.824 ret.centerToFront = ret.wheelbase * 0.44 - ret.steerControlType = car.CarParams.SteerControlType.angle - ret.radarOffCan = True - - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by - # mass and CG position, so all cars will have approximately similar dyn behaviors - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) - return ret # returns a car.CarState diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 7dba8eaf23..22468801ec 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from cereal import car from panda import Panda -from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.subaru.values import CAR, GLOBAL_GEN2, PREGLOBAL_CARS @@ -101,10 +101,6 @@ class CarInterface(CarInterfaceBase): else: raise ValueError(f"unknown car: {candidate}") - # TODO: start from empirically derived lateral slip stiffness for the civic and scale by - # mass and CG position, so all cars will have approximately similar dyn behaviors - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) - return ret # returns a car.CarState diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 6573f4e4d9..49e06d8923 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from selfdrive.car.tesla.values import CANBUS, CAR -from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -50,8 +50,6 @@ class CarInterface(CarInterfaceBase): else: raise ValueError(f"Unsupported car: {candidate}") - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) - return ret def _update(self, c): diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 8d22173671..48d85584b3 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -31,6 +31,8 @@ class TestCarInterfaces(unittest.TestCase): assert car_interface self.assertGreater(car_params.mass, 1) + self.assertGreater(car_params.wheelbase, 0) + self.assertGreater(car_params.centerToFront, 0) self.assertGreater(car_params.maxLateralAccel, 0) if car_params.steerControlType != car.CarParams.SteerControlType.angle: diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 997cdfcfc1..d90a36ed3e 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -1,7 +1,7 @@ from cereal import car from panda import Panda from common.conversions import Conversions as CV -from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config +from selfdrive.car import STD_CARGO_KG, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase from selfdrive.car.volkswagen.values import CAR, PQ_CARS, CANBUS, NetworkLocation, TransmissionType, GearShifter @@ -211,7 +211,6 @@ class CarInterface(CarInterfaceBase): ret.autoResumeSng = ret.minEnableSpeed == -1 ret.centerToFront = ret.wheelbase * 0.45 - ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront) return ret # returns a car.CarState From 8ad8d4e1c2887bcd22ab7048960ed6a1a7f8e3f6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 29 Nov 2022 13:11:03 -0800 Subject: [PATCH 0387/1179] controls: preEnabled doesn't consider noEntry (#26627) preEnabled doesn't consider noEntry --- selfdrive/controls/controlsd.py | 5 +---- selfdrive/controls/tests/test_state_machine.py | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 76f049ddd2..d99357fbb6 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -518,10 +518,7 @@ class Controls: # PRE ENABLING elif self.state == State.preEnabled: - if self.events.any(ET.NO_ENTRY): - self.state = State.disabled - self.current_alert_types.append(ET.NO_ENTRY) - elif not self.events.any(ET.PRE_ENABLE): + if not self.events.any(ET.PRE_ENABLE): self.state = State.enabled else: self.current_alert_types.append(ET.PRE_ENABLE) diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index 36535dfdaf..8f263a98e7 100755 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -79,7 +79,7 @@ class TestStateMachine(unittest.TestCase): self.assertEqual(self.controlsd.state, State.disabled) def test_no_entry(self): - # disabled with enable events + # Make sure noEntry keeps us disabled for et in ENABLE_EVENT_TYPES: self.controlsd.events.add(make_event([ET.NO_ENTRY, et])) self.controlsd.state_transition(self.CS) @@ -87,11 +87,11 @@ class TestStateMachine(unittest.TestCase): self.controlsd.events.clear() def test_no_entry_pre_enable(self): - # preEnabled with preEnabled event + # preEnabled with noEntry event self.controlsd.state = State.preEnabled self.controlsd.events.add(make_event([ET.NO_ENTRY, ET.PRE_ENABLE])) self.controlsd.state_transition(self.CS) - self.assertEqual(self.controlsd.state, State.disabled) + self.assertEqual(self.controlsd.state, State.preEnabled) def test_maintain_states(self): # Given current state's event type, we should maintain state From c3e3047080cdcfd5fbe275534fdf6980903aebdf Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 29 Nov 2022 16:05:46 -0800 Subject: [PATCH 0388/1179] boardd: cleanup defs from panda (#26628) * more stuff * bump pnada --- panda | 2 +- selfdrive/boardd/panda.cc | 9 ++++++--- selfdrive/boardd/panda.h | 12 ++++-------- selfdrive/boardd/tests/test_boardd_usbprotocol.cc | 2 -- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/panda b/panda index e4c4253964..80dac4cd94 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e4c4253964a25ff980520b70ea9f50aede4a1db6 +Subproject commit 80dac4cd94de8711304b2695b4d348d2152a8e3e diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index b82de593c8..788cdf5cf1 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -6,7 +6,6 @@ #include #include "cereal/messaging/messaging.h" -#include "panda/board/dlc_to_len.h" #include "common/swaglog.h" #include "common/util.h" @@ -255,8 +254,12 @@ bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &o canData.busTime = 0; canData.address = header.addr; canData.src = header.bus + bus_offset; - if (header.rejected) { canData.src += CANPACKET_REJECTED; } - if (header.returned) { canData.src += CANPACKET_RETURNED; } + if (header.rejected) { + canData.src += CAN_REJECTED_BUS_OFFSET; + } + if (header.returned) { + canData.src += CAN_RETURNED_BUS_OFFSET; + } const uint8_t data_len = dlc_to_len[header.data_len_code]; canData.dat.assign((char *)&recv_buf[pos + CANPACKET_HEAD_SIZE], data_len); diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index 5b3cbb9a3e..b20d8f0afa 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -11,20 +11,16 @@ #include "cereal/gen/cpp/car.capnp.h" #include "cereal/gen/cpp/log.capnp.h" #include "panda/board/health.h" +#include "panda/board/can_definitions.h" #include "selfdrive/boardd/panda_comms.h" - -#define PANDA_CAN_CNT 3 -#define PANDA_BUS_CNT 4 - #define USB_TX_SOFT_LIMIT (0x100U) #define USBPACKET_MAX_SIZE (0x40) #define RECV_SIZE (0x4000U) -#define CANPACKET_HEAD_SIZE 5U -#define CANPACKET_MAX_SIZE 72U -#define CANPACKET_REJECTED (0xC0U) -#define CANPACKET_RETURNED (0x80U) + +#define CAN_REJECTED_BUS_OFFSET 0xC0U +#define CAN_RETURNED_BUS_OFFSET 0x80U struct __attribute__((packed)) can_header { uint8_t reserved : 1; diff --git a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc b/selfdrive/boardd/tests/test_boardd_usbprotocol.cc index 6a13cbd71f..c7d14fb0ef 100644 --- a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc +++ b/selfdrive/boardd/tests/test_boardd_usbprotocol.cc @@ -6,8 +6,6 @@ #include "cereal/messaging/messaging.h" #include "selfdrive/boardd/panda.h" -const unsigned char dlc_to_len[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U}; - int random_int(int min, int max) { std::random_device dev; std::mt19937 rng(dev()); From dbe512d167a51f02fe276e17a8794de2137d0e14 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 29 Nov 2022 17:34:10 -0800 Subject: [PATCH 0389/1179] controlsd: preEnable on brake at a standstill (#26273) * pre-enable on brake at standstill * test by getting rid of noTarget * Update events.py * rename * stash what we got so far * cmt * not sure if best way to fix, but enabled with current states defs is fine * no noEntry in preEnabled * bumpcereal * uncomment * Update ref_commit Co-authored-by: Adeeb Shihadeh --- cereal | 2 +- selfdrive/controls/controlsd.py | 5 ++++- selfdrive/controls/lib/events.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cereal b/cereal index 3bae09cf65..7f55399fde 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 3bae09cf6527674d7eda3a9956242aad94a8f3d2 +Subproject commit 7f55399fde0b6a70c1bf7df4f86b90b0060e31ac diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index d99357fbb6..e5c981aa6b 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -249,6 +249,9 @@ class Controls: (CS.regenBraking and (not self.CS_prev.regenBraking or not CS.standstill)): self.events.add(EventName.pedalPressed) + if CS.brakePressed and CS.standstill: + self.events.add(EventName.preEnableStandstill) + if CS.gasPressed: self.events.add(EventName.gasPressedOverride) @@ -579,7 +582,7 @@ class Controls: # Check which actuators can be enabled CC.latActive = self.active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \ CS.vEgo > self.CP.minSteerSpeed and not CS.standstill - CC.longActive = self.active and not self.events.any(ET.OVERRIDE_LONGITUDINAL) and self.CP.openpilotLongitudinalControl + CC.longActive = self.enabled and not self.events.any(ET.OVERRIDE_LONGITUDINAL) and self.CP.openpilotLongitudinalControl actuators = CC.actuators actuators.longControlState = self.LoC.long_control_state diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index ad10b8f0bd..5d5000ff54 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -615,9 +615,9 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { visual_alert=VisualAlert.brakePressed), }, - EventName.pedalPressedPreEnable: { + EventName.preEnableStandstill: { ET.PRE_ENABLE: Alert( - "Release Pedal to Engage", + "Release Brake to Engage", "", AlertStatus.normal, AlertSize.small, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1, creation_delay=1.), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 71da0dff44..4641299458 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -ddfaab44ae64a0d064b847e81080993b51b6b423 \ No newline at end of file +f17412941a0e8229eea308c33189a5bdb1a17ae8 From 41610fe8ae7019264f09fbbb5db64e48b45b7ca0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 29 Nov 2022 23:12:58 -0800 Subject: [PATCH 0390/1179] controls: remove noTarget event (#26632) remove noTarget alert --- selfdrive/controls/controlsd.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index e5c981aa6b..342ecc52fe 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -420,16 +420,6 @@ class Controls: if self.sm['liveLocationKalman'].excessiveResets: self.events.add(EventName.localizerMalfunction) - # Only allow engagement with brake pressed when stopped behind another stopped car - speeds = self.sm['longitudinalPlan'].speeds - if len(speeds) > 1: - v_future = speeds[-1] - else: - v_future = 100.0 - if CS.brakePressed and v_future >= self.CP.vEgoStarting \ - and self.CP.openpilotLongitudinalControl and CS.vEgo < 0.3: - self.events.add(EventName.noTarget) - def data_sample(self): """Receive data from sockets and update carState""" From bea73943733a2a38a8cacd7de25d78b067460f2b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 30 Nov 2022 00:08:55 -0800 Subject: [PATCH 0391/1179] bump panda (#26637) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 80dac4cd94..e8bd1df511 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 80dac4cd94de8711304b2695b4d348d2152a8e3e +Subproject commit e8bd1df5119e457ed2162ea36777bf47a99527f2 From 5409895ab2668284df7b688ce513fa0ef1e57be2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 30 Nov 2022 02:32:47 -0800 Subject: [PATCH 0392/1179] Deprecate noTarget event (#26638) deprecate notarget --- cereal | 2 +- selfdrive/controls/lib/events.py | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/cereal b/cereal index 7f55399fde..19a0c46b71 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7f55399fde0b6a70c1bf7df4f86b90b0060e31ac +Subproject commit 19a0c46b71150a8dabc5644eb24f261feee45b9c diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 5d5000ff54..5578a83a23 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -916,15 +916,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { ET.NO_ENTRY: NoEntryAlert("Harness Relay Malfunction"), }, - EventName.noTarget: { - ET.IMMEDIATE_DISABLE: Alert( - "openpilot Canceled", - "No close lead car", - AlertStatus.normal, AlertSize.mid, - Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.), - ET.NO_ENTRY: NoEntryAlert("No Close Lead Car"), - }, - EventName.speedTooLow: { ET.IMMEDIATE_DISABLE: Alert( "openpilot Canceled", From 2b916044f5e7e6466709bd45301765d0b7599eec Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 1 Dec 2022 04:40:36 +0800 Subject: [PATCH 0393/1179] Cabana: sort signals by address in logs view (#26639) cleanup --- tools/cabana/historylog.cc | 48 +++++++++++++++++--------------------- tools/cabana/historylog.h | 13 ++++------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 65fea3361e..5457555db4 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -5,20 +5,15 @@ // HistoryLogModel -inline const Signal &get_signal(const DBCMsg *m, int index) { - return std::next(m->sigs.begin(), index)->second; -} - QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { - bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); if (role == Qt::DisplayRole) { const auto &m = messages[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(), get_signal(dbc_msg, index.column() - 1))) - : toHex(m.dat); - } else if (role == Qt::FontRole && index.column() == 1 && !has_signal) { + return !sigs.empty() ? QString::number(get_raw_value((uint8_t *)m.dat.data(), m.dat.size(), *sigs[index.column() - 1])) + : toHex(m.dat); + } else if (role == Qt::FontRole && index.column() == 1 && sigs.empty()) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); } return {}; @@ -27,25 +22,25 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { void HistoryLogModel::setMessage(const QString &message_id) { beginResetModel(); msg_id = message_id; - dbc_msg = dbc()->msg(message_id); - column_count = (dbc_msg && !dbc_msg->sigs.empty() ? dbc_msg->sigs.size() : 1) + 1; - row_count = 0; + sigs.clear(); + messages.clear(); + if (auto dbc_msg = dbc()->msg(message_id)) { + sigs = dbc_msg->getSignals(); + } endResetModel(); - updateState(); } QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { - bool has_signal = dbc_msg && !dbc_msg->sigs.empty(); if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { if (section == 0) { return "Time"; } - return has_signal ? QString::fromStdString(get_signal(dbc_msg, section - 1).name).replace('_', ' ') : "Data"; - } else if (role == Qt::BackgroundRole && section > 0 && has_signal) { + return !sigs.empty() ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; + } else if (role == Qt::BackgroundRole && section > 0 && !sigs.empty()) { return QBrush(QColor(getColor(section - 1))); - } else if (role == Qt::ForegroundRole && section > 0 && has_signal) { + } else if (role == Qt::ForegroundRole && section > 0 && !sigs.empty()) { return QBrush(Qt::black); } } @@ -53,21 +48,20 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i } void HistoryLogModel::updateState() { - if (msg_id.isEmpty()) return; - - int prev_row_count = row_count; - messages = can->messages(msg_id); - row_count = messages.size(); - int delta = row_count - prev_row_count; + int prev_row_count = messages.size(); + if (!msg_id.isEmpty()) { + messages = can->messages(msg_id); + } + int delta = messages.size() - prev_row_count; if (delta > 0) { - beginInsertRows({}, prev_row_count, row_count - 1); + beginInsertRows({}, prev_row_count, messages.size() - 1); endInsertRows(); } else if (delta < 0) { - beginRemoveRows({}, row_count, prev_row_count - 1); + beginRemoveRows({}, messages.size(), prev_row_count - 1); endRemoveRows(); } - if (row_count > 0) { - emit dataChanged(index(0, 0), index(row_count - 1, column_count - 1), {Qt::DisplayRole}); + if (!messages.empty()) { + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), {Qt::DisplayRole}); } } @@ -106,5 +100,5 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { int HistoryLog::sizeHintForColumn(int column) const { // sizeHintForColumn is only called for column 0 (ResizeToContents) - return itemDelegate()->sizeHint(viewOptions(), model->index(0, 0)).width() + 1; // +1 for grid + return itemDelegate()->sizeHint(viewOptions(), model->index(0, 0)).width() + 5; } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index dfe037c13f..9ca6f427c7 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -14,32 +14,27 @@ public: }; class HistoryLogModel : public QAbstractTableModel { - 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; 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; } + int rowCount(const QModelIndex &parent = QModelIndex()) const override { return messages.size(); } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return std::max(1ul, sigs.size()) + 1; } private: QString msg_id; - int row_count = 0; - int column_count = 2; - const DBCMsg *dbc_msg = nullptr; std::deque messages; + std::vector sigs; }; class HistoryLog : public QTableView { - Q_OBJECT - public: HistoryLog(QWidget *parent); void setMessage(const QString &message_id) { model->setMessage(message_id); } void updateState() { model->updateState(); } + private: int sizeHintForColumn(int column) const override; HistoryLogModel *model; From 553da4ef30b709d754fb89b5519ce182a9ace3e2 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 30 Nov 2022 13:00:36 -0800 Subject: [PATCH 0394/1179] DM: no reset on steer if distracted (#26567) * only for attentive fast resets * oops wheeltouch * update test --- selfdrive/monitoring/driver_monitor.py | 15 ++++++++++----- selfdrive/monitoring/test_monitoring.py | 8 +++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py index e3f6a5094d..a2cddc2462 100644 --- a/selfdrive/monitoring/driver_monitor.py +++ b/selfdrive/monitoring/driver_monitor.py @@ -156,6 +156,11 @@ class DriverStatus(): self._set_timers(active_monitoring=True) + def _reset_awareness(self): + self.awareness = 1. + self.awareness_active = 1. + self.awareness_passive = 1. + def _set_timers(self, active_monitoring): if self.active_monitoring_mode and self.awareness <= self.threshold_prompt: if active_monitoring: @@ -289,17 +294,17 @@ class DriverStatus(): self.hi_stds = 0 def update_events(self, events, driver_engaged, ctrl_active, standstill): - if (driver_engaged and self.awareness > 0) or not ctrl_active: - # reset only when on disengagement if red reached - self.awareness = 1. - self.awareness_active = 1. - self.awareness_passive = 1. + if (driver_engaged and self.awareness > 0 and not self.active_monitoring_mode) or not ctrl_active: # reset only when on disengagement if red reached + self._reset_awareness() return driver_attentive = self.driver_distraction_filter.x < 0.37 awareness_prev = self.awareness if (driver_attentive and self.face_detected and self.pose.low_std and self.awareness > 0): + if driver_engaged: + self._reset_awareness() + return # only restore awareness when paying attention and alert is not red self.awareness = min(self.awareness + ((self.settings._RECOVERY_FACTOR_MAX-self.settings._RECOVERY_FACTOR_MIN)*(1.-self.awareness)+self.settings._RECOVERY_FACTOR_MIN)*self.step_change, 1.) if self.awareness == 1.: diff --git a/selfdrive/monitoring/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py index 43b5e7747e..f72b4a3aaa 100755 --- a/selfdrive/monitoring/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -101,11 +101,12 @@ class TestMonitoring(unittest.TestCase): ((TEST_TIMESPAN-10-d_status.settings._AWARENESS_TIME)/2))/DT_DMON)].names[0], EventName.driverUnresponsive) # engaged, down to orange, driver pays attention, back to normal; then down to orange, driver touches wheel - # - should have short orange recovery time and no green afterwards; should recover rightaway on wheel touch + # - should have short orange recovery time and no green afterwards; wheel touch only recovers when paying attention def test_normal_driver(self): ds_vector = [msg_DISTRACTED] * int(DISTRACTED_SECONDS_TO_ORANGE/DT_DMON) + \ [msg_ATTENTIVE] * int(DISTRACTED_SECONDS_TO_ORANGE/DT_DMON) + \ - [msg_DISTRACTED] * (int(TEST_TIMESPAN/DT_DMON)-int(DISTRACTED_SECONDS_TO_ORANGE*2/DT_DMON)) + [msg_DISTRACTED] * int((DISTRACTED_SECONDS_TO_ORANGE+2)/DT_DMON) + \ + [msg_ATTENTIVE] * (int(TEST_TIMESPAN/DT_DMON)-int((DISTRACTED_SECONDS_TO_ORANGE*3+2)/DT_DMON)) interaction_vector = [car_interaction_NOT_DETECTED] * int(DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON) + \ [car_interaction_DETECTED] * (int(TEST_TIMESPAN/DT_DMON)-int(DISTRACTED_SECONDS_TO_ORANGE*3/DT_DMON)) events, _ = self._run_seq(ds_vector, interaction_vector, always_true, always_false) @@ -113,7 +114,8 @@ class TestMonitoring(unittest.TestCase): self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE-0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) self.assertEqual(len(events[int(DISTRACTED_SECONDS_TO_ORANGE*1.5/DT_DMON)]), 0) self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE*3-0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) - self.assertEqual(len(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)]), 0) + self.assertEqual(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+0.1)/DT_DMON)].names[0], EventName.promptDriverDistracted) + self.assertEqual(len(events[int((DISTRACTED_SECONDS_TO_ORANGE*3+2.5)/DT_DMON)]), 0) # engaged, down to orange, driver dodges camera, then comes back still distracted, down to red, \ # driver dodges, and then touches wheel to no avail, disengages and reengages From cb4fef580c8c71744b9b5b91be17f73b6fcdd097 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 30 Nov 2022 13:11:50 -0800 Subject: [PATCH 0395/1179] Update RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 97c92dfa47..e1051acd9a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,7 +1,7 @@ Version 0.9.1 (2022-12-XX) ======================== * New driving model - +* Removed driver monitoring timer resetting on interaction if face detected and distracted Version 0.9.0 (2022-11-21) ======================== From 821d8ff12f3b9c9c9ba852dd7160f5a72d3d761d Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 30 Nov 2022 15:11:26 -0800 Subject: [PATCH 0396/1179] tools: pyenv setup fix (#26601) * setup pyenv immediately * sudo * fix --- tools/ubuntu_setup.sh | 18 ++++++++++++++---- update_requirements.sh | 9 +++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 7e021bcc23..403437bfb3 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -4,13 +4,23 @@ set -e DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" ROOT="$(cd $DIR/../ && pwd)" +SUDO="" # NOTE: this is used in a docker build, so do not run any scripts here. +# Use sudo if not root +if [[ ! $(id -u) -eq 0 ]]; then + if [[ -z $(which sudo) ]]; then + echo "Please install sudo or run as root" + exit 1 + fi + SUDO="sudo" +fi + # Install packages present in all supported versions of Ubuntu function install_ubuntu_common_requirements() { - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ + $SUDO apt-get update + $SUDO apt-get install -y --no-install-recommends \ autoconf \ build-essential \ ca-certificates \ @@ -74,7 +84,7 @@ function install_ubuntu_common_requirements() { function install_ubuntu_jammy_requirements() { install_ubuntu_common_requirements - sudo apt-get install -y --no-install-recommends \ + $SUDO apt-get install -y --no-install-recommends \ qtbase5-dev \ qtchooser \ qt5-qmake \ @@ -86,7 +96,7 @@ function install_ubuntu_jammy_requirements() { function install_ubuntu_focal_requirements() { install_ubuntu_common_requirements - sudo apt-get install -y --no-install-recommends \ + $SUDO apt-get install -y --no-install-recommends \ libavresample-dev \ qt5-default \ python-dev diff --git a/update_requirements.sh b/update_requirements.sh index 8511a0a4d6..9195799ca3 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" @@ -22,8 +22,13 @@ if [ -z "\$PYENV_ROOT" ]; then eval "\$(pyenv virtualenv-init -)" fi EOF + + # setup now without restarting shell + export PATH=$HOME/.pyenv/bin:$HOME/.pyenv/shims:$PATH + export PYENV_ROOT="$HOME/.pyenv" + eval "$(pyenv init -)" + eval "$(pyenv virtualenv-init -)" fi -source $RC_FILE export MAKEFLAGS="-j$(nproc)" From 02b5b6fe1f9f919f0cafea3efc6be2403a3f7139 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 30 Nov 2022 15:36:25 -0800 Subject: [PATCH 0397/1179] soundd: change system sound mixer volume (#26633) * test changing sound volume * create system/hardware/pc/hardware.h * soundd: use Hardware::set_volume * implement Hardware::set_volume using pactl * Revert "test changing sound volume" This reverts commit 4bbd870746ec86d1c9871a6175def96cf7f751a6. * don't run command in background * pactl: use default sink --- release/files_common | 1 + selfdrive/ui/soundd/sound.cc | 8 ++------ system/hardware/base.h | 1 + system/hardware/hw.h | 10 +--------- system/hardware/pc/hardware.h | 21 +++++++++++++++++++++ system/hardware/tici/hardware.h | 7 +++++++ 6 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 system/hardware/pc/hardware.h diff --git a/release/files_common b/release/files_common index a294e1e5b5..2400c3c0dc 100644 --- a/release/files_common +++ b/release/files_common @@ -216,6 +216,7 @@ system/hardware/tici/amplifier.py system/hardware/tici/updater system/hardware/tici/iwlist.py system/hardware/pc/__init__.py +system/hardware/pc/hardware.h system/hardware/pc/hardware.py selfdrive/locationd/__init__.py diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index 6830450d8f..841bea3b8b 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -20,7 +20,6 @@ Sound::Sound(QObject *parent) : sm({"carState", "controlsState", "deviceState"}) QObject::connect(s, &QSoundEffect::statusChanged, [=]() { assert(s->status() != QSoundEffect::Error); }); - s->setVolume(Hardware::MIN_VOLUME); s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn)); sounds[alert] = {s, loops}; } @@ -49,12 +48,9 @@ void Sound::update() { // scale volume with speed if (sm.updated("carState")) { - float volume = util::map_val(sm["carState"].getCarState().getVEgo(), 11.f, 20.f, 0.f, 1.0f); + float volume = util::map_val(sm["carState"].getCarState().getVEgo(), 11.f, 20.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); - volume = util::map_val(volume, 0.f, 1.f, Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); - for (auto &[s, loops] : sounds) { - s->setVolume(std::round(100 * volume) / 100); - } + Hardware::set_volume(volume); } setAlert(Alert::get(sm, started_frame)); diff --git a/system/hardware/base.h b/system/hardware/base.h index b70948d482..f6e0b42d73 100644 --- a/system/hardware/base.h +++ b/system/hardware/base.h @@ -20,6 +20,7 @@ public: static void poweroff() {} static void set_brightness(int percent) {} static void set_display_power(bool on) {} + static void set_volume(float volume) {} static bool get_ssh_enabled() { return false; } static void set_ssh_enabled(bool enabled) {} diff --git a/system/hardware/hw.h b/system/hardware/hw.h index f50e94abe1..5599e79186 100644 --- a/system/hardware/hw.h +++ b/system/hardware/hw.h @@ -7,15 +7,7 @@ #include "system/hardware/tici/hardware.h" #define Hardware HardwareTici #else -class HardwarePC : public HardwareNone { -public: - static std::string get_os_version() { return "openpilot for PC"; } - static std::string get_name() { return "pc"; }; - static cereal::InitData::DeviceType get_device_type() { return cereal::InitData::DeviceType::PC; }; - static bool PC() { return true; } - static bool TICI() { return util::getenv("TICI", 0) == 1; } - static bool AGNOS() { return util::getenv("TICI", 0) == 1; } -}; +#include "system/hardware/pc/hardware.h" #define Hardware HardwarePC #endif diff --git a/system/hardware/pc/hardware.h b/system/hardware/pc/hardware.h new file mode 100644 index 0000000000..529b4bfe9d --- /dev/null +++ b/system/hardware/pc/hardware.h @@ -0,0 +1,21 @@ +#pragma once + +#include "system/hardware/base.h" + +class HardwarePC : public HardwareNone { +public: + static std::string get_os_version() { return "openpilot for PC"; } + static std::string get_name() { return "pc"; }; + static cereal::InitData::DeviceType get_device_type() { return cereal::InitData::DeviceType::PC; }; + static bool PC() { return true; } + static bool TICI() { return util::getenv("TICI", 0) == 1; } + static bool AGNOS() { return util::getenv("TICI", 0) == 1; } + + static void set_volume(float volume) { + volume = util::map_val(volume, 0.f, 1.f, MIN_VOLUME, MAX_VOLUME); + + char volume_str[6]; + snprintf(volume_str, sizeof(volume_str), "%.3f", volume); + std::system(("pactl set-sink-volume @DEFAULT_SINK@ " + std::string(volume_str)).c_str()); + } +}; diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index dcccb9f3d1..02becb76e4 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -38,6 +38,13 @@ public: bl_power_control.close(); } }; + static void set_volume(float volume) { + volume = util::map_val(volume, 0.f, 1.f, MIN_VOLUME, MAX_VOLUME); + + char volume_str[6]; + snprintf(volume_str, sizeof(volume_str), "%.3f", volume); + std::system(("pactl set-sink-volume @DEFAULT_SINK@ " + std::string(volume_str)).c_str()); + } static bool get_ssh_enabled() { return Params().getBool("SshEnabled"); }; static void set_ssh_enabled(bool enabled) { Params().putBool("SshEnabled", enabled); }; From 01dac5d06bcd518e6c2daab8c41979b0553b73a6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 30 Nov 2022 20:27:55 -0800 Subject: [PATCH 0398/1179] Build panda/SConscript (#26646) * panda/SConscript * think this is right? * bump panda * fix test_models * use a filter * bump panda to mater * more aesthetic ordering * alphabetical :( * alphabetical :( --- SConstruct | 9 +++------ panda | 2 +- selfdrive/car/tests/test_models.py | 18 +++++++----------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/SConstruct b/SConstruct index 033e10a1f0..54b008004e 100644 --- a/SConstruct +++ b/SConstruct @@ -300,7 +300,7 @@ if arch == "Darwin": else: 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"{qt_install_headers}", @@ -409,10 +409,10 @@ if arch != "Darwin": # build submodules SConscript([ - 'cereal/SConscript', 'body/board/SConscript', - 'panda/board/SConscript', + 'cereal/SConscript', 'opendbc/can/SConscript', + 'panda/SConscript', ]) SConscript(['third_party/SConscript']) @@ -442,9 +442,6 @@ if arch in ['x86_64', 'Darwin'] or GetOption('extras'): Export('opendbc') SConscript(['tools/cabana/SConscript']) -if GetOption('test'): - SConscript('panda/tests/safety/SConscript') - external_sconscript = GetOption('external_sconscript') if external_sconscript: SConscript([external_sconscript]) diff --git a/panda b/panda index e8bd1df511..2ae7b9a4d5 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e8bd1df5119e457ed2162ea36777bf47a99527f2 +Subproject commit 2ae7b9a4d59101c0a1a9015feb3e835763db5686 diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 56530dd738..641c109316 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -9,7 +9,6 @@ from parameterized import parameterized_class from cereal import log, car from common.realtime import DT_CTRL -from selfdrive.boardd.boardd import can_capnp_to_can_list from selfdrive.car.fingerprints import all_known_cars from selfdrive.car.car_helpers import interfaces from selfdrive.car.gm.values import CAR as GM @@ -20,8 +19,7 @@ from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader from tools.lib.route import Route -from panda.tests.safety import libpandasafety_py -from panda.tests.safety.common import package_can_msg +from panda.tests.libpanda import libpanda_py PandaType = log.PandaState.PandaType @@ -118,7 +116,7 @@ class TestCarModelBase(unittest.TestCase): assert self.CI # TODO: check safetyModel is in release panda build - self.safety = libpandasafety_py.libpandasafety + self.safety = libpanda_py.libpanda cfg = self.CP.safetyConfigs[-1] set_status = self.safety.set_safety_hooks(cfg.safetyModel.raw, cfg.safetyParam) @@ -192,7 +190,7 @@ class TestCarModelBase(unittest.TestCase): if msg.src >= 64: continue - to_send = package_can_msg([msg.address, 0, msg.dat, msg.src % 4]) + to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) if self.safety.safety_rx_hook(to_send) != 1: failed_addrs[hex(msg.address)] += 1 @@ -215,8 +213,8 @@ class TestCarModelBase(unittest.TestCase): # warm up pass, as initial states may be different for can in self.can_msgs[:300]: self.CI.update(CC, (can.as_builder().to_bytes(), )) - for msg in can_capnp_to_can_list(can.can, src_filter=range(64)): - to_send = package_can_msg(msg) + for msg in filter(lambda m: m.src in range(64), can.can): + to_send = libpanda_py.make_CANPacket(msg.address, msg.src, msg.dat) self.safety.safety_rx_hook(to_send) controls_allowed_prev = False @@ -224,10 +222,8 @@ class TestCarModelBase(unittest.TestCase): checks = defaultdict(lambda: 0) for idx, can in enumerate(self.can_msgs): CS = self.CI.update(CC, (can.as_builder().to_bytes(), )) - for msg in can_capnp_to_can_list(can.can, src_filter=range(64)): - msg = list(msg) - msg[3] %= 4 - to_send = package_can_msg(msg) + for msg in filter(lambda m: m.src in range(64), can.can): + to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) ret = self.safety.safety_rx_hook(to_send) self.assertEqual(1, ret, f"safety rx failed ({ret=}): {to_send}") From 997b2e11aef4ccc801a075dea13ed4aa9a5de27c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 30 Nov 2022 20:36:19 -0800 Subject: [PATCH 0399/1179] Honda Nidec: put max PCM gas into CarControllerParams (#26645) * limit gas * bump panda * not sure why it was represented like this --- selfdrive/car/honda/carcontroller.py | 6 +++--- selfdrive/car/honda/values.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 790dce1810..66a1485dc6 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -189,14 +189,14 @@ class CarController: clip(CS.out.vEgo + 0.0, 0.0, 100.0), clip(CS.out.vEgo + 5.0, 0.0, 100.0)] pcm_speed = interp(gas - brake, pcm_speed_BP, pcm_speed_V) - pcm_accel = int(1.0 * 0xc6) + pcm_accel = int(1.0 * self.params.NIDEC_GAS_MAX) else: pcm_speed_V = [0.0, clip(CS.out.vEgo - 2.0, 0.0, 100.0), clip(CS.out.vEgo + 2.0, 0.0, 100.0), clip(CS.out.vEgo + 5.0, 0.0, 100.0)] pcm_speed = interp(gas - brake, pcm_speed_BP, pcm_speed_V) - pcm_accel = int(clip((accel / 1.44) / max_accel, 0.0, 1.0) * 0xc6) + pcm_accel = int(clip((accel / 1.44) / max_accel, 0.0, 1.0) * self.params.NIDEC_GAS_MAX) if not self.CP.openpilotLongitudinalControl: if self.frame % 2 == 0 and self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS: # radarless cars don't have supplemental message @@ -254,7 +254,7 @@ class CarController: self.speed = pcm_speed if not self.CP.enableGasInterceptor: - self.gas = pcm_accel / 0xc6 + self.gas = pcm_accel / self.params.NIDEC_GAS_MAX new_actuators = actuators.copy() new_actuators.speed = self.speed diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 151c2140f5..f32e7bef2f 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -27,6 +27,7 @@ class CarControllerParams: NIDEC_MAX_ACCEL_V = [0.5, 2.4, 1.4, 0.6] NIDEC_MAX_ACCEL_BP = [0.0, 4.0, 10., 20.] + NIDEC_GAS_MAX = 198 # 0xc6 NIDEC_BRAKE_MAX = 1024 // 4 BOSCH_ACCEL_MIN = -3.5 # m/s^2 From 470fe9ce34eeccc8cb0ab27f7b8cee603904d5a1 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 30 Nov 2022 23:57:05 -0500 Subject: [PATCH 0400/1179] Hyundai: Add FW for 2022 Tucson Hybrid (#26647) --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 16ff68f08a..81cc4bb54f 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1421,6 +1421,7 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q', b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9220 14K', + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ', From 3d2f6c1dc05c716acb40ed612719f7d0ba3d2a8f Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 30 Nov 2022 21:45:44 -0800 Subject: [PATCH 0401/1179] Fix OpenCL driver URL (#26650) --- Dockerfile.openpilot_base_cl | 2 +- tools/webcam/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.openpilot_base_cl b/Dockerfile.openpilot_base_cl index 7652b7e4e6..4c8ecfc78d 100644 --- a/Dockerfile.openpilot_base_cl +++ b/Dockerfile.openpilot_base_cl @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends\ # Intel OpenCL driver ARG INTEL_DRIVER=l_opencl_p_18.1.0.015.tgz -ARG INTEL_DRIVER_URL=http://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532 +ARG INTEL_DRIVER_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532 RUN mkdir -p /tmp/opencl-driver-intel WORKDIR /tmp/opencl-driver-intel RUN echo INTEL_DRIVER is $INTEL_DRIVER && \ diff --git a/tools/webcam/README.md b/tools/webcam/README.md index f896e19b86..237e07cdb6 100644 --- a/tools/webcam/README.md +++ b/tools/webcam/README.md @@ -18,7 +18,7 @@ git clone https://github.com/commaai/openpilot.git - Follow [this readme](https://github.com/commaai/openpilot/tree/master/tools) to install the requirements - Add line "export PYTHONPATH=$HOME/openpilot" to your ~/.bashrc - Install tensorflow 2.2 and nvidia drivers: nvidia-xxx/cuda10.0/cudnn7.6.5 -- Install [OpenCL Driver](http://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532/l_opencl_p_18.1.0.015.tgz) +- Install [OpenCL Driver](https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532/l_opencl_p_18.1.0.015.tgz) - Install [OpenCV4](https://www.pyimagesearch.com/2018/08/15/how-to-install-opencv-4-on-ubuntu/) (ignore the Python part) ## Build openpilot for webcam From 108ff15f5dc16f79a36a2d33397b36dba42d70cf Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 30 Nov 2022 21:56:03 -0800 Subject: [PATCH 0402/1179] micd: scale sound volume with ambient noise level (#26399) * test changing sound volume * test changing sound volume * create system/hardware/pc/hardware.h * implement Hardware::set_volume using pactl * soundd: use Hardware::set_volume * add sounddevice dependency * sounddevice example * simple micd * cleanup * remove this * fix process config * add to release files * hardware: get sound input device * no more offroad * debug * calculate volume from all measurements since last update * use microphone noise level to update sound volume * fix scale * mute microphone during alerts * log raw noise level * hardware: reduce tici min volume * improve scale * add package * clear measurements on muted * change default to min volume and respond quicker * fixes Co-authored-by: Shane Smiskol * logarithmic scaling * fix * respond quicker * fixes * tweak scaling * specify default device * Revert "hardware: get sound input device" This reverts commit 50f594f7a3bab005023482bc793147a8c8dae5d7. * tuning * forgot to update submaster * tuning * don't mute microphone, and clip measurement * remove submaster * fixes * tuning * implement Hardware::set_volume using pactl * Revert "test changing sound volume" This reverts commit 4bbd870746ec86d1c9871a6175def96cf7f751a6. * draft * draft * calculate sound pressure level in dB * fix setting * faster filter * start at initial value * don't run command in background * pactl: use default sink * use sound pressure db * tuning * bump up max volume threshold * update filter slower * fix divide by zero * bump cereal Co-authored-by: Shane Smiskol --- cereal | 2 +- poetry.lock | 32 +++++++++----- pyproject.toml | 1 + release/files_common | 1 + selfdrive/manager/process_config.py | 1 + selfdrive/ui/soundd/sound.cc | 6 +-- system/hardware/tici/hardware.h | 2 +- system/micd.py | 67 +++++++++++++++++++++++++++++ tools/ubuntu_setup.sh | 1 + 9 files changed, 98 insertions(+), 15 deletions(-) create mode 100755 system/micd.py diff --git a/cereal b/cereal index 19a0c46b71..dbc9846ac9 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 19a0c46b71150a8dabc5644eb24f261feee45b9c +Subproject commit dbc9846ac9c9e735ee2f4a281ce079cfff7ea285 diff --git a/poetry.lock b/poetry.lock index d79a3f035f..fbe0009a26 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3696,6 +3696,20 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "sounddevice" +version = "0.4.5" +description = "Play and Record Sound with Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +CFFI = ">=1.0" + +[package.extras] +numpy = ["NumPy"] + [[package]] name = "soupsieve" version = "2.3.2.post1" @@ -4386,7 +4400,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "d2854112975a9d83a9540175b2d430487e40e0292d48a1ba6c591db60a08c136" +content-hash = "a41b1d669ec4f0a94abe12af8a9a7d709b2bb56e9c83aa87801cdf5d9af074f8" [metadata.files] adal = [ @@ -5392,7 +5406,6 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, - {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6563,11 +6576,6 @@ pillow-avif-plugin = [ {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017e5e52cb4320414e8ce3e2089eae2cb87c22c73ff6012b17ae326fc5753b20"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a57136d4866de5dc80cfb24d66655955fbdd87acf1d11d88c8dc2ab41023e46"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:f339511d0fccb69e3a5e3af39f8fe6700b0a07279015006ea56f8f49e7fecff4"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05e821ecd90bb0b8d2dc7610625372cc47de9cb893d09662528bad572f669d1c"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33886a5f9796fe9a8a3bc25ccfdeba7db119adb50b7004f1928a14b07d0213a"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75b7ed186c2f740dd26e556f6a966c59a170b70263e429a2c81920fe444da8a7"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11aef6b79078b8dad25c928e5871c146ab94424472851d5bf539ba62abde9ac"}, - {file = "pillow_avif_plugin-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10696c536d68a14cefea3b98edb8d5a7ae29e8e07458f1d59c5d1cd780a8bf2a"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1a7291d6a5fb7336e72685a31d193e0b3a6bee9986c9ac4d8bd4b68dbe6d4f7f"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:14b9c5dbf237e7dc12f69819ea181a457b3bd4f59f8cd71d028d3635fd3bcab4"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:799cbfbeee831332d280c80df9ce16b5c3b1224c318264e97e89df8da32e870e"}, @@ -6956,13 +6964,11 @@ pyprof2calltree = [ ] pyproj = [ {file = "pyproj-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f343725566267a296b09ee7e591894f1fdc90f84f8ad5ec476aeb53bd4479c07"}, - {file = "pyproj-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5816807ca0bdc7256558770c6206a6783a3f02bcf844f94ee245f197bb5f7285"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e609903572a56cca758bbaee5c1663c3e829ddce5eec4f368e68277e37022b"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fd425ee8b6781c249c7adb7daa2e6c41ce573afabe4f380f5eecd913b56a3be"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954b068136518b3174d0a99448056e97af62b63392a95c420894f7de2229dae6"}, {file = "pyproj-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:4a23d84c5ffc383c7d9f0bde3a06fc1f6697b1b96725597f8f01e7b4bef0a2b5"}, {file = "pyproj-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f9c100fd0fd80edbc7e4daa303600a8cbef6f0de43d005617acb38276b88dc0"}, - {file = "pyproj-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa5171f700f174777a9e9ed8f4655583243967c0f9cf2c90e3f54e54ff740134"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a496d9057b2128db9d733e66b206f2d5954bbae6b800d412f562d780561478c"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52e54796e2d9554a5eb8f11df4748af1fbbc47f76aa234d6faf09216a84554c5"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a454a7c4423faa2a14e939d08ef293ee347fa529c9df79022b0585a6e1d8310c"}, @@ -6973,7 +6979,6 @@ pyproj = [ {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f80adda8c54b84271a93829477a01aa57bc178c834362e9f74e1de1b5033c74c"}, {file = "pyproj-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:221d8939685e0c43ee594c9f04b6a73a10e8e1cc0e85f28be0b4eb2f1bc8777d"}, {file = "pyproj-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d94afed99f31673d3d19fe750283621e193e2a53ca9e0443bf9d092c3905833b"}, - {file = "pyproj-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fff9c3a991508f16027be27d153f6c5583d03799443639d13c681e60f49e2d7"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85acf09e5a9e35cd9ee72989793adb7089b4e611be02a43d3d0bda50ad116b"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45554f47d1a12a84b0620e4abc08a2a1b5d9f273a4759eaef75e74788ec7162a"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f62c20656ac9b6076ebb213e9a635d52f4f01fef95310121d337e62e910cb6"}, @@ -7515,6 +7520,13 @@ sortedcontainers = [ {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +sounddevice = [ + {file = "sounddevice-0.4.5-py3-none-any.whl", hash = "sha256:5cea4afd9412e731f50ae09a54d68b10628a604cfd56b42a976c54d424c6c39d"}, + {file = "sounddevice-0.4.5-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:0875173595a8bd5a66b5a03a3d958e7b89c3b956b8befbe4491a24a3ce7784c0"}, + {file = "sounddevice-0.4.5-py3-none-win32.whl", hash = "sha256:442adf53850916374a58f902200aaf9412227378181264e60c966da64be47d41"}, + {file = "sounddevice-0.4.5-py3-none-win_amd64.whl", hash = "sha256:d3216c5d3d678c3301058e9aac7000879e255140c524c9ef98730091b67ea676"}, + {file = "sounddevice-0.4.5.tar.gz", hash = "sha256:2fe0d41299e4f3037dad2acede4eff0666b34a1fa3da5335e47120373964bef5"}, +] soupsieve = [ {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"}, {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, diff --git a/pyproject.toml b/pyproject.toml index 7e76b9cdfc..c890b78875 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ sentry-sdk = "^1.6.0" setproctitle = "^1.2.3" six = "^1.16.0" smbus2 = "^0.4.2" +sounddevice = "^0.4.5" sympy = "^1.10.1" timezonefinder = "^6.0.1" tqdm = "^4.64.0" diff --git a/release/files_common b/release/files_common index 2400c3c0dc..aa6c0ac55c 100644 --- a/release/files_common +++ b/release/files_common @@ -71,6 +71,7 @@ selfdrive/rtshield.py selfdrive/statsd.py system/logmessaged.py +system/micd.py system/swaglog.py system/version.py diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index dbccb8d4a9..50c19610ed 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -24,6 +24,7 @@ procs = [ NativeProcess("logcatd", "system/logcatd", ["./logcatd"]), NativeProcess("proclogd", "system/proclogd", ["./proclogd"]), PythonProcess("logmessaged", "system.logmessaged", offroad=True), + PythonProcess("micd", "system.micd"), PythonProcess("timezoned", "system.timezoned", enabled=not PC, offroad=True), DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"), diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index 841bea3b8b..3deb6ceca0 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -12,7 +12,7 @@ // TODO: detect when we can't play sounds // TODO: detect when we can't display the UI -Sound::Sound(QObject *parent) : sm({"carState", "controlsState", "deviceState"}) { +Sound::Sound(QObject *parent) : sm({"controlsState", "deviceState", "microphone"}) { qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName(); for (auto &[alert, fn, loops] : sound_list) { @@ -47,8 +47,8 @@ void Sound::update() { } // scale volume with speed - if (sm.updated("carState")) { - float volume = util::map_val(sm["carState"].getCarState().getVEgo(), 11.f, 20.f, 0.f, 1.f); + if (sm.updated("microphone")) { + float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureDb(), 58.f, 77.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); Hardware::set_volume(volume); } diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index 02becb76e4..d388f9c48a 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -10,7 +10,7 @@ class HardwareTici : public HardwareNone { public: static constexpr float MAX_VOLUME = 0.9; - static constexpr float MIN_VOLUME = 0.2; + static constexpr float MIN_VOLUME = 0.1; static bool TICI() { return true; } static bool AGNOS() { return true; } static std::string get_os_version() { diff --git a/system/micd.py b/system/micd.py new file mode 100755 index 0000000000..d2a5a2849f --- /dev/null +++ b/system/micd.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +import sounddevice as sd +import numpy as np + +from cereal import messaging +from common.filter_simple import FirstOrderFilter +from common.realtime import Ratekeeper +from system.swaglog import cloudlog + +RATE = 10 +DT_MIC = 1. / RATE +REFERENCE_SPL = 2 * 10 ** -5 # newtons/m^2 + + +class Mic: + def __init__(self, pm): + self.pm = pm + self.rk = Ratekeeper(RATE) + + self.measurements = np.empty(0) + self.spl_filter = FirstOrderFilter(0, 4, DT_MIC, initialized=False) + + def update(self): + # self.measurements contains amplitudes from -1 to 1 which we use to + # calculate an uncalibrated sound pressure level + if len(self.measurements) > 0: + # https://www.engineeringtoolbox.com/sound-pressure-d_711.html + sound_pressure = np.sqrt(np.mean(self.measurements ** 2)) # RMS of amplitudes + sound_pressure_level = 20 * np.log10(sound_pressure / REFERENCE_SPL) if sound_pressure > 0 else 0 # dB + self.spl_filter.update(sound_pressure_level) + else: + sound_pressure = 0 + sound_pressure_level = 0 + + self.measurements = np.empty(0) + + msg = messaging.new_message('microphone') + msg.microphone.soundPressure = float(sound_pressure) + msg.microphone.soundPressureDb = float(sound_pressure_level) + msg.microphone.filteredSoundPressureDb = float(self.spl_filter.x) + + self.pm.send('microphone', msg) + self.rk.keep_time() + + def callback(self, indata, frames, time, status): + self.measurements = np.concatenate((self.measurements, indata[:, 0])) + + def micd_thread(self, device=None): + if device is None: + device = "sysdefault" + + with sd.InputStream(device=device, channels=1, samplerate=44100, callback=self.callback) as stream: + cloudlog.info(f"micd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}") + while True: + self.update() + + +def main(pm=None, sm=None): + if pm is None: + pm = messaging.PubMaster(['microphone']) + + mic = Mic(pm) + mic.micd_thread() + + +if __name__ == "__main__": + main() diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 403437bfb3..89d33a6127 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -56,6 +56,7 @@ function install_ubuntu_common_requirements() { libomp-dev \ libopencv-dev \ libpng16-16 \ + libportaudio2 \ libssl-dev \ libsqlite3-dev \ libusb-1.0-0-dev \ From 17e06bdc93c2fac37e72eec5ac569307023cfb29 Mon Sep 17 00:00:00 2001 From: royjr Date: Thu, 1 Dec 2022 01:21:48 -0500 Subject: [PATCH 0403/1179] Honda: Add missing modified firmware comment (#26648) Update values.py --- selfdrive/car/honda/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index f32e7bef2f..905c9f4b4f 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -243,7 +243,7 @@ FW_VERSIONS = { b'39990-TVA-A340\x00\x00', b'39990-TVA-X030\x00\x00', b'39990-TVA-X040\x00\x00', - b'39990-TVA,A150\x00\x00', + b'39990-TVA,A150\x00\x00', # modified firmware b'39990-TVE-H130\x00\x00', ], (Ecu.unknown, 0x18da3af1, None): [ From 996a6c06d4522100357e04fea0182d33dc6e7f23 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 30 Nov 2022 23:12:35 -0800 Subject: [PATCH 0404/1179] sim: disable micd (#26653) --- tools/sim/launch_openpilot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sim/launch_openpilot.sh b/tools/sim/launch_openpilot.sh index adabc40c2e..2100f05b67 100755 --- a/tools/sim/launch_openpilot.sh +++ b/tools/sim/launch_openpilot.sh @@ -6,7 +6,7 @@ export SIMULATION="1" export SKIP_FW_QUERY="1" export FINGERPRINT="HONDA CIVIC 2016" -export BLOCK="camerad,loggerd,encoderd" +export BLOCK="camerad,loggerd,encoderd,micd" if [[ "$CI" ]]; then # TODO: offscreen UI should work export BLOCK="${BLOCK},ui" From 50f4328b904cf4debd278834adcf83107a3d4e5c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 30 Nov 2022 23:16:48 -0800 Subject: [PATCH 0405/1179] Update RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index e1051acd9a..1ae4a233be 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,6 @@ Version 0.9.1 (2022-12-XX) ======================== -* New driving model +* Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted Version 0.9.0 (2022-11-21) From 9e0607806fcb5d1a5a00eb8ec0a0ef05fb6fd7f3 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 30 Nov 2022 23:27:02 -0800 Subject: [PATCH 0406/1179] [torqued] Set Hyundai Ioniq 5 2022 values (#26554) set ioniq values, different from ev6, from offline data --- selfdrive/car/torque_data/params.yaml | 1 + selfdrive/car/torque_data/substitute.yaml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 124cf3d3b9..7901972fc2 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -27,6 +27,7 @@ HONDA PILOT 2017: [1.7262026201812795, 0.9470005614967523, 0.21351430733218763] HONDA RIDGELINE 2017: [1.4146525028237624, 0.7356572861629564, 0.23307177552211328] HYUNDAI ELANTRA 2021: [3.169, 2.1259108157250735, 0.0819] HYUNDAI GENESIS 2015-2016: [1.8466226943929824, 1.5552063647830634, 0.0984484465421171] +HYUNDAI IONIQ 5 2022: [3.172929, 3.0, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] HYUNDAI IONIQ PLUG-IN HYBRID 2019: [2.970807902012267, 1.6312321830002083, 0.1088964990357482] diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 77236e393e..df696bc0fc 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -29,7 +29,6 @@ HYUNDAI VELOSTER 2019: HYUNDAI SONATA 2019 HYUNDAI KONA 2020: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA HYBRID 2020: HYUNDAI KONA ELECTRIC 2019 HYUNDAI KONA ELECTRIC 2022: HYUNDAI KONA ELECTRIC 2019 -HYUNDAI IONIQ 5 2022: KIA EV6 2022 HYUNDAI IONIQ HYBRID 2017-2019: HYUNDAI IONIQ PLUG-IN HYBRID 2019 HYUNDAI IONIQ HYBRID 2020-2022: HYUNDAI IONIQ PLUG-IN HYBRID 2019 HYUNDAI IONIQ ELECTRIC 2020: HYUNDAI IONIQ PLUG-IN HYBRID 2019 From 92ddd3c57e03f2ba602b147790eed4bb7b97a24c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Dec 2022 00:28:40 -0800 Subject: [PATCH 0407/1179] add new panda SConscript to release files --- release/files_common | 1 + 1 file changed, 1 insertion(+) diff --git a/release/files_common b/release/files_common index aa6c0ac55c..2f7f2d4d61 100644 --- a/release/files_common +++ b/release/files_common @@ -486,6 +486,7 @@ cereal/visionipc/*.pxd panda/.gitignore panda/__init__.py +panda/SConscript panda/board/** panda/certs/** panda/crypto/** From fee6f2efacf41d2bd964754d0e5e193e18e16f16 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Thu, 1 Dec 2022 18:12:16 +0100 Subject: [PATCH 0408/1179] Simple CAN chunks (#25373) * simple chunks * more sizeofs * fix unit tests * bump panda * bump panda * don't fail for too little data * bump panda * bump panda * bump panda Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/boardd/panda.cc | 55 +++++++++---------- .../boardd/tests/test_boardd_usbprotocol.cc | 17 +++--- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/panda b/panda index 2ae7b9a4d5..288e14cde9 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 2ae7b9a4d59101c0a1a9015feb3e835763db5686 +Subproject commit 288e14cde904a5755ebb32b0853631ac7fbf5968 diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 788cdf5cf1..db9bcbab51 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -169,22 +169,15 @@ static uint8_t len_to_dlc(uint8_t len) { } } -static void write_packet(uint8_t *dest, int *write_pos, const uint8_t *src, size_t size) { - for (int i = 0, &pos = *write_pos; i < size; ++i, ++pos) { - // Insert counter every 64 bytes (first byte of 64 bytes USB packet) - if (pos % USBPACKET_MAX_SIZE == 0) { - dest[pos] = pos / USBPACKET_MAX_SIZE; - pos++; - } - dest[pos] = src[i]; - } -} - void Panda::pack_can_buffer(const capnp::List::Reader &can_data_list, std::function write_func) { int32_t pos = 0; uint8_t send_buf[2 * USB_TX_SOFT_LIMIT]; + uint32_t magic = CAN_TRANSACTION_MAGIC; + memcpy(&send_buf[0], &magic, sizeof(uint32_t)); + pos += sizeof(uint32_t); + for (auto cmsg : can_data_list) { // check if the message is intended for this panda uint8_t bus = cmsg.getSrc(); @@ -202,16 +195,19 @@ void Panda::pack_can_buffer(const capnp::List::Reader &can_data header.data_len_code = data_len_code; header.bus = bus - bus_offset; - write_packet(send_buf, &pos, (uint8_t *)&header, sizeof(can_header)); - write_packet(send_buf, &pos, (uint8_t *)can_data.begin(), can_data.size()); + memcpy(&send_buf[pos], (uint8_t *)&header, sizeof(can_header)); + pos += sizeof(can_header); + memcpy(&send_buf[pos], (uint8_t *)can_data.begin(), can_data.size()); + pos += can_data.size(); + if (pos >= USB_TX_SOFT_LIMIT) { write_func(send_buf, pos); - pos = 0; + pos = sizeof(uint32_t); } } // send remaining packets - if (pos > 0) write_func(send_buf, pos); + if (pos > sizeof(uint32_t)) write_func(send_buf, pos); } void Panda::can_send(capnp::List::Reader can_data_list) { @@ -235,20 +231,23 @@ bool Panda::can_receive(std::vector& out_vec) { bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &out_vec) { recv_buf.clear(); - for (int i = 0; i < size; i += USBPACKET_MAX_SIZE) { - if (data[i] != i / USBPACKET_MAX_SIZE) { - LOGE("CAN: MALFORMED USB RECV PACKET"); - handle->comms_healthy = false; - return false; - } - int chunk_len = std::min(USBPACKET_MAX_SIZE, (size - i)); - recv_buf.insert(recv_buf.end(), &data[i + 1], &data[i + chunk_len]); + + if (size < sizeof(uint32_t)) { + return true; } - int pos = 0; - while (pos < recv_buf.size()) { + uint32_t magic; + memcpy(&magic, &data[0], sizeof(uint32_t)); + if (magic != CAN_TRANSACTION_MAGIC) { + LOGE("CAN: MALFORMED CAN RECV PACKET"); + handle->comms_healthy = false; + return false; + } + + int pos = sizeof(uint32_t); + while (pos < size) { can_header header; - memcpy(&header, &recv_buf[pos], CANPACKET_HEAD_SIZE); + memcpy(&header, &data[pos], sizeof(can_header)); can_frame &canData = out_vec.emplace_back(); canData.busTime = 0; @@ -262,9 +261,9 @@ bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &o } const uint8_t data_len = dlc_to_len[header.data_len_code]; - canData.dat.assign((char *)&recv_buf[pos + CANPACKET_HEAD_SIZE], data_len); + canData.dat.assign((char *)&data[pos + sizeof(can_header)], data_len); - pos += CANPACKET_HEAD_SIZE + data_len; + pos += sizeof(can_header) + data_len; } return true; } diff --git a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc b/selfdrive/boardd/tests/test_boardd_usbprotocol.cc index c7d14fb0ef..cc3b4bce9a 100644 --- a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc +++ b/selfdrive/boardd/tests/test_boardd_usbprotocol.cc @@ -48,7 +48,7 @@ PandaTest::PandaTest(uint32_t bus_offset_, int can_list_size, cereal::PandaState can.setAddress(i); can.setSrc(random_int(0, 3) + bus_offset); can.setDat(kj::ArrayPtr((uint8_t *)dat.data(), dat.size())); - total_pakets_size += CANPACKET_HEAD_SIZE + dat.size(); + total_pakets_size += sizeof(can_header) + dat.size(); } can_data_list = can_list.asReader(); @@ -58,14 +58,11 @@ PandaTest::PandaTest(uint32_t bus_offset_, int can_list_size, cereal::PandaState void PandaTest::test_can_send() { std::vector unpacked_data; this->pack_can_buffer(can_data_list, [&](uint8_t *chunk, size_t size) { - int size_left = size; - for (int i = 0, counter = 0; i < size; i += USBPACKET_MAX_SIZE, counter++) { - REQUIRE(chunk[i] == counter); + uint32_t magic; + memcpy(&magic, &chunk[0], sizeof(uint32_t)); - const int len = std::min(USBPACKET_MAX_SIZE, size_left); - unpacked_data.insert(unpacked_data.end(), &chunk[i + 1], &chunk[i + len]); - size_left -= len; - } + REQUIRE(magic == CAN_TRANSACTION_MAGIC); + unpacked_data.insert(unpacked_data.end(), &chunk[sizeof(uint32_t)], &chunk[size]); }); REQUIRE(unpacked_data.size() == total_pakets_size); @@ -73,9 +70,9 @@ void PandaTest::test_can_send() { INFO("test can message integrity"); for (int pos = 0, pckt_len = 0; pos < unpacked_data.size(); pos += pckt_len) { can_header header; - memcpy(&header, &unpacked_data[pos], CANPACKET_HEAD_SIZE); + memcpy(&header, &unpacked_data[pos], sizeof(can_header)); const uint8_t data_len = dlc_to_len[header.data_len_code]; - pckt_len = CANPACKET_HEAD_SIZE + data_len; + pckt_len = sizeof(can_header) + data_len; REQUIRE(header.addr == cnt); REQUIRE(test_data.find(data_len) != test_data.end()); From 74c0ac3deced5ac85b72ec1a4e51dae851cdb440 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 2 Dec 2022 01:17:02 +0800 Subject: [PATCH 0409/1179] Cabana: setSectionResizeMode to QHeaderView::Fixed (#26655) fixed header --- tools/cabana/binaryview.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 6a4f66dcd4..e655bf0c04 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -23,6 +23,7 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { setItemDelegate(delegate); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); verticalHeader()->setSectionsClickable(false); + verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); horizontalHeader()->hide(); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); From 92e985c583bfb23c569008157037e77b6080a6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 1 Dec 2022 11:56:25 -0800 Subject: [PATCH 0410/1179] voltage cleanup thermald (#26658) --- selfdrive/thermald/power_monitoring.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index e62f0f97c3..b748064d2b 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -18,6 +18,7 @@ VBATT_PAUSE_CHARGING = 11.0 # Lower limit on the LPF car battery volta VBATT_INSTANT_PAUSE_CHARGING = 7.0 # Lower limit on the instant car battery voltage measurements to avoid triggering on instant power loss MAX_TIME_OFFROAD_S = 30*3600 MIN_ON_TIME_S = 3600 +VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S = 60 class PowerMonitoring: def __init__(self): @@ -114,8 +115,12 @@ class PowerMonitoring: now = sec_since_boot() should_shutdown = False - should_shutdown |= (now - offroad_timestamp) > MAX_TIME_OFFROAD_S - should_shutdown |= (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3)) and (self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3)) + offroad_time = (now - offroad_timestamp) + low_voltage_shutdown = (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3) and + self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3) and + offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S) + should_shutdown |= offroad_time > MAX_TIME_OFFROAD_S + should_shutdown |= low_voltage_shutdown should_shutdown |= (self.car_battery_capacity_uWh <= 0) should_shutdown &= not ignition should_shutdown &= (not self.params.get_bool("DisablePowerDown")) From 86cd919a57be22fa0ccf324a8767999309df60e4 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 1 Dec 2022 12:52:06 -0800 Subject: [PATCH 0411/1179] micd: don't update filtered sound level if playing sound (#26652) * add is_sound_playing to hardware.py * micd: don't update filtered sound level if playing sound --- system/hardware/base.py | 4 ++++ system/hardware/pc/hardware.py | 4 ++++ system/hardware/tici/hardware.py | 3 +++ system/micd.py | 4 +++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/system/hardware/base.py b/system/hardware/base.py index 31df1babe0..16ed9621c1 100644 --- a/system/hardware/base.py +++ b/system/hardware/base.py @@ -43,6 +43,10 @@ class HardwareBase(ABC): def get_sound_card_online(self): pass + @abstractmethod + def is_sound_playing(self): + pass + @abstractmethod def get_imei(self, slot) -> str: pass diff --git a/system/hardware/pc/hardware.py b/system/hardware/pc/hardware.py index 564f9e483a..2c83eb35f4 100644 --- a/system/hardware/pc/hardware.py +++ b/system/hardware/pc/hardware.py @@ -1,4 +1,5 @@ import random +import subprocess from cereal import log from system.hardware.base import HardwareBase, ThermalConfig @@ -17,6 +18,9 @@ class Pc(HardwareBase): def get_sound_card_online(self): return True + def is_sound_playing(self): + return "RUNNING" in subprocess.check_output(["pactl", "list", "short", "sinks"]).decode('utf8') + def reboot(self, reason=None): print("REBOOT!") diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index b5f5e00410..8371d6ef70 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -96,6 +96,9 @@ class Tici(HardwareBase): return (os.path.isfile('/proc/asound/card0/state') and open('/proc/asound/card0/state').read().strip() == 'ONLINE') + def is_sound_playing(self): + return "RUNNING" in subprocess.check_output(["pactl", "list", "short", "sinks"]).decode('utf8') + def reboot(self, reason=None): subprocess.check_output(["sudo", "reboot"]) diff --git a/system/micd.py b/system/micd.py index d2a5a2849f..27b6cb5f19 100755 --- a/system/micd.py +++ b/system/micd.py @@ -5,6 +5,7 @@ import numpy as np from cereal import messaging from common.filter_simple import FirstOrderFilter from common.realtime import Ratekeeper +from system.hardware import HARDWARE from system.swaglog import cloudlog RATE = 10 @@ -27,7 +28,8 @@ class Mic: # https://www.engineeringtoolbox.com/sound-pressure-d_711.html sound_pressure = np.sqrt(np.mean(self.measurements ** 2)) # RMS of amplitudes sound_pressure_level = 20 * np.log10(sound_pressure / REFERENCE_SPL) if sound_pressure > 0 else 0 # dB - self.spl_filter.update(sound_pressure_level) + if not HARDWARE.is_sound_playing(): + self.spl_filter.update(sound_pressure_level) else: sound_pressure = 0 sound_pressure_level = 0 From 7a9d96759d3a4db277edcce2d5e3ffda9c6823d5 Mon Sep 17 00:00:00 2001 From: Bruce Wayne Date: Thu, 1 Dec 2022 13:11:31 -0800 Subject: [PATCH 0412/1179] Revert "voltage cleanup thermald (#26658)" This reverts commit 92e985c583bfb23c569008157037e77b6080a6f6. --- selfdrive/thermald/power_monitoring.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index b748064d2b..e62f0f97c3 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -18,7 +18,6 @@ VBATT_PAUSE_CHARGING = 11.0 # Lower limit on the LPF car battery volta VBATT_INSTANT_PAUSE_CHARGING = 7.0 # Lower limit on the instant car battery voltage measurements to avoid triggering on instant power loss MAX_TIME_OFFROAD_S = 30*3600 MIN_ON_TIME_S = 3600 -VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S = 60 class PowerMonitoring: def __init__(self): @@ -115,12 +114,8 @@ class PowerMonitoring: now = sec_since_boot() should_shutdown = False - offroad_time = (now - offroad_timestamp) - low_voltage_shutdown = (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3) and - self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3) and - offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S) - should_shutdown |= offroad_time > MAX_TIME_OFFROAD_S - should_shutdown |= low_voltage_shutdown + should_shutdown |= (now - offroad_timestamp) > MAX_TIME_OFFROAD_S + should_shutdown |= (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3)) and (self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3)) should_shutdown |= (self.car_battery_capacity_uWh <= 0) should_shutdown &= not ignition should_shutdown &= (not self.params.get_bool("DisablePowerDown")) From 196caa095b1c028926e580bb9c671338d08d3fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 1 Dec 2022 13:57:11 -0800 Subject: [PATCH 0413/1179] thermald: add minimum offroad time to low voltage shutdown (#26660) * voltage cleanup thermald * Fix voltage shutdown test --- selfdrive/thermald/power_monitoring.py | 9 +++++++-- selfdrive/thermald/tests/test_power_monitoring.py | 10 +++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index e62f0f97c3..b748064d2b 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -18,6 +18,7 @@ VBATT_PAUSE_CHARGING = 11.0 # Lower limit on the LPF car battery volta VBATT_INSTANT_PAUSE_CHARGING = 7.0 # Lower limit on the instant car battery voltage measurements to avoid triggering on instant power loss MAX_TIME_OFFROAD_S = 30*3600 MIN_ON_TIME_S = 3600 +VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S = 60 class PowerMonitoring: def __init__(self): @@ -114,8 +115,12 @@ class PowerMonitoring: now = sec_since_boot() should_shutdown = False - should_shutdown |= (now - offroad_timestamp) > MAX_TIME_OFFROAD_S - should_shutdown |= (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3)) and (self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3)) + offroad_time = (now - offroad_timestamp) + low_voltage_shutdown = (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3) and + self.car_voltage_instant_mV > (VBATT_INSTANT_PAUSE_CHARGING * 1e3) and + offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S) + should_shutdown |= offroad_time > MAX_TIME_OFFROAD_S + should_shutdown |= low_voltage_shutdown should_shutdown |= (self.car_battery_capacity_uWh <= 0) should_shutdown &= not ignition should_shutdown &= (not self.params.get_bool("DisablePowerDown")) diff --git a/selfdrive/thermald/tests/test_power_monitoring.py b/selfdrive/thermald/tests/test_power_monitoring.py index 4a5def7740..d41e92454b 100755 --- a/selfdrive/thermald/tests/test_power_monitoring.py +++ b/selfdrive/thermald/tests/test_power_monitoring.py @@ -120,15 +120,19 @@ class TestPowerMonitoring(unittest.TestCase): def test_car_voltage(self): POWER_DRAW = 0 # To stop shutting down for other reasons TEST_TIME = 100 - with pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): + VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S = 50 + with pm_patch("VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S", VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S, constant=True), pm_patch("HARDWARE.get_current_power_draw", POWER_DRAW): pm = PowerMonitoring() pm.car_battery_capacity_uWh = CAR_BATTERY_CAPACITY_uWh ignition = False + start_time = ssb for i in range(TEST_TIME): pm.calculate(VOLTAGE_BELOW_PAUSE_CHARGING, ignition) if i % 10 == 0: - self.assertEqual(pm.should_shutdown(ignition, True, ssb, True), (pm.car_voltage_mV < VBATT_PAUSE_CHARGING*1e3)) - self.assertTrue(pm.should_shutdown(ignition, True, ssb, True)) + self.assertEqual(pm.should_shutdown(ignition, True, start_time, True), + (pm.car_voltage_mV < VBATT_PAUSE_CHARGING*1e3 and + (ssb - start_time) > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S)) + self.assertTrue(pm.should_shutdown(ignition, True, start_time, True)) # Test to check policy of not stopping charging when DisablePowerDown is set def test_disable_power_down(self): From 1adf106da69c7d73d465f41ad2836a562ca64f9c Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Thu, 1 Dec 2022 17:11:12 -0500 Subject: [PATCH 0414/1179] HKG: Car Port for Kia Sorento Plug-in Hybrid 2022 (#26635) * HKG: Car Port for Kia Sorento Plug-in Hybrid 2022 * Add torque params * Typo * This car has SCC on bus 4, needs radar disable to use openpilot longitudinal :/ * Need to check on bus 4 as well * Different unit signal * Unit signal cleanup * Add test route * Regenerate car docs * Different logic * 2023 should be the same * Fix 0x1a0 check race condition * Update RELEASES.md Co-authored-by: Adeeb Shihadeh --- RELEASES.md | 1 + docs/CARS.md | 3 ++- opendbc | 2 +- selfdrive/car/hyundai/carstate.py | 10 +++++++--- selfdrive/car/hyundai/interface.py | 4 ++++ selfdrive/car/hyundai/values.py | 17 ++++++++++++++--- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 8 files changed, 31 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 1ae4a233be..7b51e6dff3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,6 +2,7 @@ Version 0.9.1 (2022-12-XX) ======================== * Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted +* Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! Version 0.9.0 (2022-11-21) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index a0d22a3d27..f8455b25ea 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 215 Supported Cars +# 216 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -104,6 +104,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Kia|Sorento Plug-in Hybrid 2022-23|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sportage 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| diff --git a/opendbc b/opendbc index 871e054d9a..18bff2369b 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 871e054d9a94629d92c22fe89cae71af5b0d3823 +Subproject commit 18bff2369b44ecb36638885c974aae1891616ae5 diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 2c309fa0df..dfb33f2eb4 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -6,7 +6,7 @@ from cereal import car from common.conversions import Conversions as CV from opendbc.can.parser import CANParser from opendbc.can.can_define import CANDefine -from selfdrive.car.hyundai.values import HyundaiFlags, DBC, FEATURES, CAMERA_SCC_CAR, CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams +from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, FEATURES, CAMERA_SCC_CAR, CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams from selfdrive.car.interfaces import CarStateBase PREV_BUTTON_SAMPLES = 8 @@ -197,7 +197,9 @@ class CarState(CarStateBase): ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0 ret.cruiseState.available = True - self.is_metric = cp.vl["CLUSTER_INFO"]["DISTANCE_UNIT"] != 1 + cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" + distance_unit_msg = cruise_btn_msg if self.CP.carFingerprint == CAR.KIA_SORENTO_PHEV_4TH_GEN else "CLUSTER_INFO" + self.is_metric = cp.vl[distance_unit_msg]["DISTANCE_UNIT"] != 1 if not self.CP.openpilotLongitudinalControl: speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp @@ -206,7 +208,6 @@ class CarState(CarStateBase): ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"]) - cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" self.prev_cruise_buttons = self.cruise_buttons[-1] self.cruise_buttons.extend(cp.vl_all[cruise_btn_msg]["CRUISE_BUTTONS"]) self.main_buttons.extend(cp.vl_all[cruise_btn_msg]["ADAPTIVE_CRUISE_MAIN_BTN"]) @@ -446,6 +447,9 @@ class CarState(CarStateBase): ("DRIVER_SEATBELT_LATCHED", "DOORS_SEATBELTS"), ] + if CP.carFingerprint == CAR.KIA_SORENTO_PHEV_4TH_GEN: + signals.append(("DISTANCE_UNIT", cruise_btn_msg)) + checks = [ ("WHEEL_SPEEDS", 100), (gear_msg, 100), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index c1fe8be4c2..cb4d9a9688 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -185,6 +185,10 @@ class CarInterface(CarInterfaceBase): ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only ret.wheelbase = 2.756 ret.steerRatio = 13.6 + elif candidate == CAR.KIA_SORENTO_PHEV_4TH_GEN: + ret.mass = 4095.8 * CV.LB_TO_KG + STD_CARGO_KG # weight from EX and above trims, average of FWD and AWD versions (EX, X-Line EX AWD, SX, SX Pestige, X-Line SX Prestige AWD) + ret.wheelbase = 2.81 + ret.steerRatio = 13.27 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sorento-phev/2022/specifications # Genesis elif candidate == CAR.GENESIS_G70: diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 81cc4bb54f..7ecb07e7d7 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -93,6 +93,7 @@ class CAR: KIA_SELTOS = "KIA SELTOS 2021" KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN" KIA_SORENTO = "KIA SORENTO GT LINE 2018" + KIA_SORENTO_PHEV_4TH_GEN = "KIA SORENTO PLUG-IN HYBRID 4TH GEN" KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN" KIA_STINGER = "KIA STINGER GT2 2018" KIA_STINGER_2022 = "KIA STINGER 2022" @@ -180,6 +181,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), ], + CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness=Harness.hyundai_k), @@ -1394,6 +1396,14 @@ FW_VERSIONS = { b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00' ], }, + CAR.KIA_SORENTO_PHEV_4TH_GEN: { + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00MQhe SCC FHCUP 1.00 1.06 99110-P4000 ', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.11 99210-P2000 211217', + ] + }, CAR.KIA_EV6: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ', @@ -1478,15 +1488,15 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # The radar does SCC on these cars when HDA I, rather than the camera -CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, } +CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } -HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN} # these cars use a different gas signal +HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # these cars use a different gas signal EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5} # these cars require a special panda safety mode due to missing counters and checksums in the messages @@ -1543,4 +1553,5 @@ DBC = { CAR.KIA_SPORTAGE_5TH_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None), CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None), + CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index cd61528439..da19e1f367 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -98,6 +98,7 @@ routes = [ CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON), CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), + CarTestRoute("628935d7d3e5f4f7|2022-11-30--01-12-46", HYUNDAI.KIA_SORENTO_PHEV_4TH_GEN), CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.IONIQ_5), # HDA2 CarTestRoute("3f29334d6134fcd4|2022-03-30--22-00-50", HYUNDAI.IONIQ_PHEV_2019), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 6ec782444c..1eda931e3e 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -34,6 +34,7 @@ HYUNDAI SANTA CRUZ 1ST GEN: [2.7, 2.7, 0.1] KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.1] KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.1] GENESIS GV70 1ST GEN: [2.42, 2.42, 0.1] +KIA SORENTO PLUG-IN HYBRID 4TH GEN: [2.5, 2.5, 0.1] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From 30165134e8963e260245c1b6596ca3ae3cc08fea Mon Sep 17 00:00:00 2001 From: EdwardApollo <51210836+EdwardApollo@users.noreply.github.com> Date: Thu, 1 Dec 2022 17:18:32 -0500 Subject: [PATCH 0415/1179] Increase Minimum Offroad Battery Voltage (#26661) * Reduce Min Idle Battery Voltage and Idle Time Updated minimum offroad battery voltage to reduce wear on car batteries and updated max offroad time to reflect the increased power consumption at idle based on EPHOT hardware power draw (this may have changed). Most vehicles make use of lead acid batteries which during normal use shouldn't ever decrease below ~12V (sources give a range of 11.8-12V). Increasing this limit will prevent premature battery failure by preventing sulfation of the cells. * Voltage cutoff to 11.8V, max offroad to 30h Changed lower voltage limit to 11.8V, removed power usage comment entirely, reverted change to max offroad time to 30 hours * Added Offroad Shutdown conditional Added IsOffroad Shutdown conditional statement to prevent shutting down due to voltage floor. * LPF Gain: Tau = 45s Tau modified to 45s to result in a LPF gain of ~0.011. Assuming a dT of 0.5s: (0.5/45)/((0.5/45)+1) * Revert IsOffroad check Removed due to unnecessary redundancy. --- selfdrive/thermald/power_monitoring.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/thermald/power_monitoring.py b/selfdrive/thermald/power_monitoring.py index b748064d2b..85e9510eb7 100644 --- a/selfdrive/thermald/power_monitoring.py +++ b/selfdrive/thermald/power_monitoring.py @@ -7,14 +7,13 @@ from system.hardware import HARDWARE from system.swaglog import cloudlog from selfdrive.statsd import statlog -CAR_VOLTAGE_LOW_PASS_K = 0.091 # LPF gain for 5s tau (dt/tau / (dt/tau + 1)) +CAR_VOLTAGE_LOW_PASS_K = 0.011 # LPF gain for 45s tau (dt/tau / (dt/tau + 1)) -# A C2 uses about 1W while idling, and 30h seens like a good shutoff for most cars # While driving, a battery charges completely in about 30-60 minutes CAR_BATTERY_CAPACITY_uWh = 30e6 CAR_CHARGING_RATE_W = 45 -VBATT_PAUSE_CHARGING = 11.0 # Lower limit on the LPF car battery voltage +VBATT_PAUSE_CHARGING = 11.8 # Lower limit on the LPF car battery voltage VBATT_INSTANT_PAUSE_CHARGING = 7.0 # Lower limit on the instant car battery voltage measurements to avoid triggering on instant power loss MAX_TIME_OFFROAD_S = 30*3600 MIN_ON_TIME_S = 3600 From c210640b7cc42b18efd27ce4f0bd7c7328674ade Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Dec 2022 14:21:57 -0800 Subject: [PATCH 0416/1179] bump opendbc --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index 18bff2369b..3737675445 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 18bff2369b44ecb36638885c974aae1891616ae5 +Subproject commit 373767544559718d74bff58dd23890eea1d38a29 From 753c3d5897d46f9c070f9267d7385b3578185b2e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Dec 2022 15:32:59 -0800 Subject: [PATCH 0417/1179] jenkins: move test_manager to common devices (#26663) --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index c34d253585..e8323bca7d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -115,7 +115,6 @@ pipeline { ["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR EXTRA_FILES='tools/' ./build_devel.sh"], ["build openpilot", "cd selfdrive/manager && ./build.py"], ["check dirty", "release/check-dirty.sh"], - ["test manager", "python selfdrive/manager/test/test_manager.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], ]) @@ -141,6 +140,7 @@ pipeline { ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], ["test pigeond", "python selfdrive/sensord/tests/test_pigeond.py"], + ["test manager", "python selfdrive/manager/test/test_manager.py"], ]) } } From dad438158ec60df10dc7e4b4fb8f225af190defd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 1 Dec 2022 20:14:10 -0800 Subject: [PATCH 0418/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 288e14cde9..616450c525 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 288e14cde904a5755ebb32b0853631ac7fbf5968 +Subproject commit 616450c525a7c1ef508f70f30e29547a606139aa From 1f4554b0c030cfc2623d7c7db413e9c61dabaef4 Mon Sep 17 00:00:00 2001 From: Vybhav Date: Thu, 1 Dec 2022 22:03:15 -0800 Subject: [PATCH 0419/1179] Toyota: Add FW for 2023 Toyota Camry Hybrid (#26654) * Toyota: Add FW for 2023 Toyota Camry Hybrid Toyota: Updating CAR_INFO list to show 2023 for Camry * Update CARS.md for 2023 Toyota Camry * remove duplicate fw, sort alphabetically Co-authored-by: Vybhav Achar Bhargav Co-authored-by: Vybhav Achar Bhargav Co-authored-by: Cameron Clough --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index f8455b25ea..df0dda742c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -166,7 +166,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Camry 2018-20|All|Stock|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Camry 2021-22|All|openpilot|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry Hybrid 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 4f2ab478c7..e112ebdb80 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -113,7 +113,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CAMRY: ToyotaCarInfo("Toyota Camry 2018-20", video_link="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), CAR.CAMRYH: ToyotaCarInfo("Toyota Camry Hybrid 2018-20", video_link="https://www.youtube.com/watch?v=Q2DYY0AWKgk"), CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-22", footnotes=[Footnote.CAMRY]), - CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-22"), + CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-23"), CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-21"), CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), @@ -551,10 +551,12 @@ FW_VERSIONS = { (Ecu.abs, 0x7b0, None): [ b'F152633D00\x00\x00\x00\x00\x00\x00', b'F152633D60\x00\x00\x00\x00\x00\x00', + b'F152633310\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x018966306Q6000\x00\x00\x00\x00', b'\x018966306Q7000\x00\x00\x00\x00', + b'\x018966306V1000\x00\x00\x00\x00', b'\x01896633T20000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 15): [ @@ -565,6 +567,7 @@ FW_VERSIONS = { b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', + b'\x028646F3305500\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.CHR: { From d087fab2c0af6baf104591dade313311aeed1e4b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Dec 2022 00:11:29 -0800 Subject: [PATCH 0420/1179] micd: apply A-weighting to the sound pressure level (#26668) * record * record * draft * some clean up * some clean up * wishful tuning * log pressure level (db) for debugging * fix * tuning * ignore complex to real warning * remove this * Update selfdrive/ui/soundd/sound.cc * Update system/micd.py * remove warning supp * bump cereal to master Co-authored-by: Cameron Clough --- cereal | 2 +- selfdrive/ui/soundd/sound.cc | 2 +- system/micd.py | 62 ++++++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/cereal b/cereal index dbc9846ac9..7765176413 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit dbc9846ac9c9e735ee2f4a281ce079cfff7ea285 +Subproject commit 7765176413c0bb14143fe2469d5390ea0ea61a1e diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index 3deb6ceca0..73d65eb1f7 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -48,7 +48,7 @@ void Sound::update() { // scale volume with speed if (sm.updated("microphone")) { - float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureDb(), 58.f, 77.f, 0.f, 1.f); + float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 55.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); Hardware::set_volume(volume); } diff --git a/system/micd.py b/system/micd.py index 27b6cb5f19..150dcb9cbe 100755 --- a/system/micd.py +++ b/system/micd.py @@ -10,7 +10,35 @@ from system.swaglog import cloudlog RATE = 10 DT_MIC = 1. / RATE -REFERENCE_SPL = 2 * 10 ** -5 # newtons/m^2 +REFERENCE_SPL = 2e-5 # newtons/m^2 +SAMPLE_RATE = 44100 + + +def calculate_spl(measurements): + # https://www.engineeringtoolbox.com/sound-pressure-d_711.html + sound_pressure = np.sqrt(np.mean(measurements ** 2)) # RMS of amplitudes + if sound_pressure > 0: + sound_pressure_level = 20 * np.log10(sound_pressure / REFERENCE_SPL) # dB + else: + sound_pressure_level = 0 + return sound_pressure, sound_pressure_level + + +def apply_a_weighting(measurements: np.ndarray) -> np.ndarray: + # Generate a Hanning window of the same length as the audio measurements + hanning_window = np.hanning(len(measurements)) + measurements_windowed = measurements * hanning_window + + # Calculate the frequency axis for the signal + freqs = np.fft.fftfreq(measurements_windowed.size, d=1 / SAMPLE_RATE) + + # Calculate the A-weighting filter + # https://en.wikipedia.org/wiki/A-weighting + A = 12194 ** 2 * freqs ** 4 / ((freqs ** 2 + 20.6 ** 2) * (freqs ** 2 + 12194 ** 2) * np.sqrt((freqs ** 2 + 107.7 ** 2) * (freqs ** 2 + 737.9 ** 2))) + A /= np.max(A) # Normalize the filter + + # Apply the A-weighting filter to the signal + return np.abs(np.fft.ifft(np.fft.fft(measurements_windowed) * A)) class Mic: @@ -19,27 +47,35 @@ class Mic: self.rk = Ratekeeper(RATE) self.measurements = np.empty(0) - self.spl_filter = FirstOrderFilter(0, 4, DT_MIC, initialized=False) + self.spl_filter_weighted = FirstOrderFilter(0, 2.5, DT_MIC, initialized=False) def update(self): - # self.measurements contains amplitudes from -1 to 1 which we use to - # calculate an uncalibrated sound pressure level + """ + Using amplitude measurements, calculate an uncalibrated sound pressure and sound pressure level. + Then apply A-weighting to the raw amplitudes and run the same calculations again. + + Logged A-weighted equivalents are rough approximations of the human-perceived loudness. + """ + if len(self.measurements) > 0: - # https://www.engineeringtoolbox.com/sound-pressure-d_711.html - sound_pressure = np.sqrt(np.mean(self.measurements ** 2)) # RMS of amplitudes - sound_pressure_level = 20 * np.log10(sound_pressure / REFERENCE_SPL) if sound_pressure > 0 else 0 # dB + sound_pressure, _ = calculate_spl(self.measurements) + measurements_weighted = apply_a_weighting(self.measurements) + sound_pressure_weighted, sound_pressure_level_weighted = calculate_spl(measurements_weighted) if not HARDWARE.is_sound_playing(): - self.spl_filter.update(sound_pressure_level) + self.spl_filter_weighted.update(sound_pressure_level_weighted) else: sound_pressure = 0 - sound_pressure_level = 0 + sound_pressure_weighted = 0 + sound_pressure_level_weighted = 0 self.measurements = np.empty(0) msg = messaging.new_message('microphone') msg.microphone.soundPressure = float(sound_pressure) - msg.microphone.soundPressureDb = float(sound_pressure_level) - msg.microphone.filteredSoundPressureDb = float(self.spl_filter.x) + msg.microphone.soundPressureWeighted = float(sound_pressure_weighted) + + msg.microphone.soundPressureWeightedDb = float(sound_pressure_level_weighted) + msg.microphone.filteredSoundPressureWeightedDb = float(self.spl_filter_weighted.x) self.pm.send('microphone', msg) self.rk.keep_time() @@ -51,13 +87,13 @@ class Mic: if device is None: device = "sysdefault" - with sd.InputStream(device=device, channels=1, samplerate=44100, callback=self.callback) as stream: + with sd.InputStream(device=device, channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream: cloudlog.info(f"micd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}") while True: self.update() -def main(pm=None, sm=None): +def main(pm=None): if pm is None: pm = messaging.PubMaster(['microphone']) From de061eacbe772b1a9be73d4a3864fad6e05037ac Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Dec 2022 02:23:51 -0800 Subject: [PATCH 0421/1179] soundd: lower max volume breakpoint (#26673) * revert tune * remove hanning window * retune from hanning window * add hanning back * update once reached 4096 * Revert "update once reached 4096" This reverts commit 0898cbeec736916ffaee5e963df048b48636ece5. --- selfdrive/ui/soundd/sound.cc | 2 +- system/micd.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index 73d65eb1f7..f039511ff8 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -48,7 +48,7 @@ void Sound::update() { // scale volume with speed if (sm.updated("microphone")) { - float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 55.f, 0.f, 1.f); + float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 52.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); Hardware::set_volume(volume); } diff --git a/system/micd.py b/system/micd.py index 150dcb9cbe..57700e5927 100755 --- a/system/micd.py +++ b/system/micd.py @@ -26,8 +26,7 @@ def calculate_spl(measurements): def apply_a_weighting(measurements: np.ndarray) -> np.ndarray: # Generate a Hanning window of the same length as the audio measurements - hanning_window = np.hanning(len(measurements)) - measurements_windowed = measurements * hanning_window + measurements_windowed = measurements * np.hanning(len(measurements)) # Calculate the frequency axis for the signal freqs = np.fft.fftfreq(measurements_windowed.size, d=1 / SAMPLE_RATE) From 9cc06e9ea658b74bf1504fa35c6c8729fb1f550f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 2 Dec 2022 11:51:25 -0800 Subject: [PATCH 0422/1179] boardd: misc spi fixes (#26670) --- selfdrive/boardd/panda.cc | 4 +--- selfdrive/boardd/panda.h | 1 - selfdrive/boardd/panda_comms.h | 3 --- selfdrive/boardd/spi.cc | 25 +++++++++++++++++-------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index db9bcbab51..3e447c830e 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -230,8 +230,6 @@ bool Panda::can_receive(std::vector& out_vec) { } bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &out_vec) { - recv_buf.clear(); - if (size < sizeof(uint32_t)) { return true; } @@ -239,7 +237,7 @@ bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &o uint32_t magic; memcpy(&magic, &data[0], sizeof(uint32_t)); if (magic != CAN_TRANSACTION_MAGIC) { - LOGE("CAN: MALFORMED CAN RECV PACKET"); + LOGE("CAN recv: buffer didn't start with magic"); handle->comms_healthy = false; return false; } diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index b20d8f0afa..75fec57a3e 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -43,7 +43,6 @@ struct can_frame { class Panda { private: std::unique_ptr handle; - std::vector recv_buf; public: Panda(std::string serial="", uint32_t bus_offset=0); diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index f42eadc5b2..bd262dfa0e 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -13,8 +13,6 @@ #define TIMEOUT 0 #define SPI_BUF_SIZE 1024 -const bool PANDA_NO_RETRY = getenv("PANDA_NO_RETRY"); - // comms base class class PandaCommsHandle { @@ -52,7 +50,6 @@ public: private: libusb_context *ctx = NULL; libusb_device_handle *dev_handle = NULL; - std::vector recv_buf; void handle_usb_issue(int err, const char func[]); }; diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 2803f58db0..717b6ce820 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -6,6 +6,7 @@ #include #include "common/util.h" +#include "common/timing.h" #include "common/swaglog.h" #include "panda/board/comms_definitions.h" #include "selfdrive/boardd/panda_comms.h" @@ -24,6 +25,9 @@ struct __attribute__((packed)) spi_header { uint16_t max_rx_len; }; +const int SPI_MAX_RETRIES = 5; +const int SPI_ACK_TIMEOUT = 50; // milliseconds + PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { LOGD("opening SPI panda: %s", serial.c_str()); @@ -109,7 +113,7 @@ int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int l int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len) { std::lock_guard lk(hw_lock); - const int xfer_size = 0x40; + const int xfer_size = 0x40 * 15; int ret = 0; uint16_t length = (tx_data != NULL) ? tx_len : rx_len; @@ -119,7 +123,8 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t int len = std::min(xfer_size, tx_len - (xfer_size * i)); d = spi_transfer_retry(endpoint, tx_data + (xfer_size * i), len, NULL, 0); } else { - d = spi_transfer_retry(endpoint, NULL, 0, rx_data + (xfer_size * i), xfer_size); + uint16_t to_read = std::min(xfer_size, rx_len - ret); + d = spi_transfer_retry(endpoint, NULL, 0, rx_data + (xfer_size * i), to_read); } if (d < 0) { @@ -137,15 +142,11 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t return ret; } - - std::vector PandaSpiHandle::list() { // TODO: list all pandas available over SPI return {}; } - - void add_checksum(uint8_t *data, int data_len) { data[data_len] = SPI_CHECKSUM_START; for (int i=0; i < data_len; i++) { @@ -165,17 +166,19 @@ bool check_checksum(uint8_t *data, int data_len) { int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len) { int ret; + int count = SPI_MAX_RETRIES; std::lock_guard lk(hw_lock); do { // TODO: handle error ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); - } while (ret < 0 && connected && !PANDA_NO_RETRY); + count--; + } while (ret < 0 && connected && count > 0); return ret; } int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { - // TODO: add timeout? + double start_millis = millis_since_boot(); while (true) { int ret = util::safe_ioctl(spi_fd, SPI_IOC_MESSAGE(1), &transfer); if (ret < 0) { @@ -189,6 +192,12 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { LOGW("SPI: got NACK"); return -1; } + + // handle timeout + if (millis_since_boot() - start_millis > SPI_ACK_TIMEOUT) { + LOGE("SPI: timed out waiting for ACK"); + return -1; + } } return 0; From bb8a38a0508c764c8340e7b16968b06a8367ab7a Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Fri, 2 Dec 2022 13:14:30 -0800 Subject: [PATCH 0423/1179] navmodeld (#26665) * Added navmodeld * New nav model: 7c306685-5476-4bd4-ab65-105b01b6bca8/300, feats only * little cleanup * Remove NAV flag * Moved to_kj_array_ptr to commonmodel.h * Switch from decimation to last_frame_id check * add to release files Co-authored-by: Adeeb Shihadeh --- .gitignore | 1 + release/files_common | 10 +++- selfdrive/manager/process_config.py | 3 +- selfdrive/modeld/SConscript | 5 ++ selfdrive/modeld/models/commonmodel.h | 6 +++ selfdrive/modeld/models/driving.cc | 5 -- selfdrive/modeld/models/nav.cc | 66 +++++++++++++++++++++++ selfdrive/modeld/models/nav.h | 73 ++++++++++++++++++++++++++ selfdrive/modeld/models/navmodel.onnx | 3 ++ selfdrive/modeld/models/navmodel_q.dlc | 3 ++ selfdrive/modeld/navmodeld | 12 +++++ selfdrive/modeld/navmodeld.cc | 60 +++++++++++++++++++++ 12 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 selfdrive/modeld/models/nav.cc create mode 100644 selfdrive/modeld/models/nav.h create mode 100644 selfdrive/modeld/models/navmodel.onnx create mode 100644 selfdrive/modeld/models/navmodel_q.dlc create mode 100755 selfdrive/modeld/navmodeld create mode 100644 selfdrive/modeld/navmodeld.cc diff --git a/.gitignore b/.gitignore index 31cef94222..2b283d3b11 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ selfdrive/sensord/_sensord system/camerad/camerad system/camerad/test/ae_gray_test selfdrive/modeld/_modeld +selfdrive/modeld/_navmodeld selfdrive/modeld/_dmonitoringmodeld /src/ diff --git a/release/files_common b/release/files_common index 2f7f2d4d61..297a7a808e 100644 --- a/release/files_common +++ b/release/files_common @@ -350,20 +350,28 @@ selfdrive/manager/test/test_manager.py selfdrive/modeld/__init__.py selfdrive/modeld/SConscript selfdrive/modeld/modeld.cc +selfdrive/modeld/navmodeld.cc selfdrive/modeld/dmonitoringmodeld.cc selfdrive/modeld/constants.py selfdrive/modeld/modeld +selfdrive/modeld/navmodeld selfdrive/modeld/dmonitoringmodeld selfdrive/modeld/models/commonmodel.cc selfdrive/modeld/models/commonmodel.h + selfdrive/modeld/models/driving.cc selfdrive/modeld/models/driving.h +selfdrive/modeld/models/supercombo.onnx + selfdrive/modeld/models/dmonitoring.cc selfdrive/modeld/models/dmonitoring.h -selfdrive/modeld/models/supercombo.onnx selfdrive/modeld/models/dmonitoring_model_q.dlc +selfdrive/modeld/models/nav.cc +selfdrive/modeld/models/nav.h +selfdrive/modeld/models/navmodel_q.dlc + selfdrive/modeld/transforms/loadyuv.cc selfdrive/modeld/transforms/loadyuv.h selfdrive/modeld/transforms/loadyuv.cl diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 50c19610ed..c03e995497 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -32,7 +32,8 @@ procs = [ NativeProcess("encoderd", "selfdrive/loggerd", ["./encoderd"]), NativeProcess("loggerd", "selfdrive/loggerd", ["./loggerd"], onroad=False, callback=logging), NativeProcess("modeld", "selfdrive/modeld", ["./modeld"]), - # NativeProcess("mapsd", "selfdrive/navd", ["./map_renderer"]), + NativeProcess("mapsd", "selfdrive/navd", ["./map_renderer"], enabled=False), + NativeProcess("navmodeld", "selfdrive/modeld", ["./navmodeld"], enabled=False), NativeProcess("sensord", "selfdrive/sensord", ["./sensord"], enabled=not PC), NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=(not PC or WEBCAM)), NativeProcess("ui", "selfdrive/ui", ["./ui"], offroad=True, watchdog_max_dt=(5 if not PC else None)), diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index f1a8d71881..82338e456b 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -112,3 +112,8 @@ llenv.Program('_modeld', [ "modeld.cc", "models/driving.cc", ]+common_model, LIBS=libs + transformations) + +lenv.Program('_navmodeld', [ + "navmodeld.cc", + "models/nav.cc", + ]+common_model, LIBS=libs + transformations) \ No newline at end of file diff --git a/selfdrive/modeld/models/commonmodel.h b/selfdrive/modeld/models/commonmodel.h index 40c82a8c21..1a079da055 100644 --- a/selfdrive/modeld/models/commonmodel.h +++ b/selfdrive/modeld/models/commonmodel.h @@ -13,6 +13,7 @@ #endif #include "common/mat.h" +#include "cereal/messaging/messaging.h" #include "selfdrive/modeld/transforms/loadyuv.h" #include "selfdrive/modeld/transforms/transform.h" @@ -21,6 +22,11 @@ const bool send_raw_pred = getenv("SEND_RAW_PRED") != NULL; void softmax(const float* input, float* output, size_t len); float sigmoid(float input); +template +constexpr const kj::ArrayPtr to_kj_array_ptr(const std::array &arr) { + return kj::ArrayPtr(arr.data(), arr.size()); +} + class ModelFrame { public: ModelFrame(cl_device_id device_id, cl_context context); diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 4015731c42..9cb216ff19 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -22,11 +22,6 @@ std::array prev_brake_3ms2_probs = {0,0,0}; // #define DUMP_YUV -template -constexpr const kj::ArrayPtr to_kj_array_ptr(const std::array &arr) { - return kj::ArrayPtr(arr.data(), arr.size()); -} - void model_init(ModelState* s, cl_device_id device_id, cl_context context) { s->frame = new ModelFrame(device_id, context); s->wide_frame = new ModelFrame(device_id, context); diff --git a/selfdrive/modeld/models/nav.cc b/selfdrive/modeld/models/nav.cc new file mode 100644 index 0000000000..dae87c7ce5 --- /dev/null +++ b/selfdrive/modeld/models/nav.cc @@ -0,0 +1,66 @@ +#include "selfdrive/modeld/models/nav.h" + +#include +#include + +#include "common/mat.h" +#include "common/modeldata.h" +#include "common/timing.h" + + +void navmodel_init(NavModelState* s) { +#ifdef USE_ONNX_MODEL + s->m = new ONNXModel("models/navmodel.onnx", &s->output[0], NAV_NET_OUTPUT_SIZE, USE_DSP_RUNTIME, false, true); +#else + s->m = new SNPEModel("models/navmodel_q.dlc", &s->output[0], NAV_NET_OUTPUT_SIZE, USE_DSP_RUNTIME, false, true); +#endif +} + +NavModelResult* navmodel_eval_frame(NavModelState* s, VisionBuf* buf) { + memcpy(s->net_input_buf, buf->addr, NAV_INPUT_SIZE); + + double t1 = millis_since_boot(); + s->m->addImage((float*)s->net_input_buf, NAV_INPUT_SIZE/sizeof(float)); + s->m->execute(); + double t2 = millis_since_boot(); + + NavModelResult *model_res = (NavModelResult*)&s->output; + model_res->dsp_execution_time = (t2 - t1) / 1000.; + return model_res; +} + +void fill_plan(cereal::NavModelData::Builder &framed, const NavModelOutputPlan &plan) { + std::array pos_x, pos_y; + std::array pos_x_std, pos_y_std; + + for (int i=0; im; +} diff --git a/selfdrive/modeld/models/nav.h b/selfdrive/modeld/models/nav.h new file mode 100644 index 0000000000..b469f75987 --- /dev/null +++ b/selfdrive/modeld/models/nav.h @@ -0,0 +1,73 @@ +#pragma once + +#include "cereal/messaging/messaging.h" +#include "cereal/visionipc/visionipc_client.h" +#include "common/util.h" +#include "common/modeldata.h" +#include "selfdrive/modeld/models/commonmodel.h" +#include "selfdrive/modeld/runners/run.h" + +constexpr int NAV_INPUT_SIZE = 256*256; +constexpr int NAV_FEATURE_LEN = 64; +constexpr int NAV_DESIRE_LEN = 32; +constexpr int NAV_PLAN_MHP_N = 5; + +struct NavModelOutputXY { + float x; + float y; +}; +static_assert(sizeof(NavModelOutputXY) == sizeof(float)*2); + +struct NavModelOutputPlan { + std::array mean; + std::array std; + float prob; +}; +static_assert(sizeof(NavModelOutputPlan) == sizeof(NavModelOutputXY)*TRAJECTORY_SIZE*2 + sizeof(float)); + +struct NavModelOutputPlans { + std::array predictions; + + constexpr const NavModelOutputPlan &get_best_prediction() const { + int max_idx = 0; + for (int i = 1; i < predictions.size(); i++) { + if (predictions[i].prob > predictions[max_idx].prob) { + max_idx = i; + } + } + return predictions[max_idx]; + } +}; +static_assert(sizeof(NavModelOutputPlans) == sizeof(NavModelOutputPlan)*NAV_PLAN_MHP_N); + +struct NavModelOutputDesirePrediction { + std::array values; +}; +static_assert(sizeof(NavModelOutputDesirePrediction) == sizeof(float)*NAV_DESIRE_LEN); + +struct NavModelOutputFeatures { + std::array values; +}; +static_assert(sizeof(NavModelOutputFeatures) == sizeof(float)*NAV_FEATURE_LEN); + +struct NavModelResult { + const NavModelOutputPlans plans; + const NavModelOutputDesirePrediction desire_pred; + const NavModelOutputFeatures features; + float dsp_execution_time; +}; +static_assert(sizeof(NavModelResult) == sizeof(NavModelOutputPlans) + sizeof(NavModelOutputDesirePrediction) + sizeof(NavModelOutputFeatures) + sizeof(float)); + +constexpr int NAV_OUTPUT_SIZE = sizeof(NavModelResult) / sizeof(float); +constexpr int NAV_NET_OUTPUT_SIZE = NAV_OUTPUT_SIZE - 1; + +struct NavModelState { + RunModel *m; + uint8_t net_input_buf[NAV_INPUT_SIZE]; + float output[NAV_OUTPUT_SIZE]; +}; + +void navmodel_init(NavModelState* s); +NavModelResult* navmodel_eval_frame(NavModelState* s, VisionBuf* buf); +void navmodel_publish(PubMaster &pm, uint32_t frame_id, const NavModelResult &model_res, float execution_time); +void navmodel_free(NavModelState* s); diff --git a/selfdrive/modeld/models/navmodel.onnx b/selfdrive/modeld/models/navmodel.onnx new file mode 100644 index 0000000000..60dd8c0e7f --- /dev/null +++ b/selfdrive/modeld/models/navmodel.onnx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eab4b986e14d7d842d6d5487011c329d356fb56995b2ae7dc7188aefe6df9d97 +size 12285002 diff --git a/selfdrive/modeld/models/navmodel_q.dlc b/selfdrive/modeld/models/navmodel_q.dlc new file mode 100644 index 0000000000..7d9b36ed4d --- /dev/null +++ b/selfdrive/modeld/models/navmodel_q.dlc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:83d53efc40053b02fe7d3da4ef6213a4a5a1ae4d1bd49c121b9beb6a54ea1148 +size 3154868 diff --git a/selfdrive/modeld/navmodeld b/selfdrive/modeld/navmodeld new file mode 100755 index 0000000000..079afd9677 --- /dev/null +++ b/selfdrive/modeld/navmodeld @@ -0,0 +1,12 @@ +#!/bin/sh + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd $DIR + +if [ -f /TICI ]; then + export LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu:/data/pythonpath/third_party/snpe/larch64:$LD_LIBRARY_PATH" + export ADSP_LIBRARY_PATH="/data/pythonpath/third_party/snpe/dsp/" +else + export LD_LIBRARY_PATH="$DIR/../../third_party/snpe/x86_64-linux-clang:$DIR/../../openpilot/third_party/snpe/x86_64:$LD_LIBRARY_PATH" +fi +exec ./_navmodeld diff --git a/selfdrive/modeld/navmodeld.cc b/selfdrive/modeld/navmodeld.cc new file mode 100644 index 0000000000..57ef7cf0e0 --- /dev/null +++ b/selfdrive/modeld/navmodeld.cc @@ -0,0 +1,60 @@ +#include +#include + +#include +#include + +#include "cereal/visionipc/visionipc_client.h" +#include "common/swaglog.h" +#include "common/util.h" +#include "selfdrive/modeld/models/nav.h" + +ExitHandler do_exit; + +void run_model(NavModelState &model, VisionIpcClient &vipc_client) { + PubMaster pm({"navModel"}); + + double last_ts = 0; + uint32_t last_frame_id = 0; + VisionIpcBufExtra extra = {}; + + while (!do_exit) { + VisionBuf *buf = vipc_client.recv(&extra); + if (buf == nullptr) continue; + if (extra.frame_id < last_frame_id + 10) continue; // Run at 2Hz + + double t1 = millis_since_boot(); + NavModelResult *model_res = navmodel_eval_frame(&model, buf); + double t2 = millis_since_boot(); + + // send navmodel packet + navmodel_publish(pm, extra.frame_id, *model_res, (t2 - t1) / 1000.0); + + //printf("navmodel process: %.2fms, from last %.2fms\n", t2 - t1, t1 - last_ts); + last_ts = t1; + last_frame_id = extra.frame_id; + } +} + +int main(int argc, char **argv) { + setpriority(PRIO_PROCESS, 0, -15); + + // init the models + NavModelState model; + navmodel_init(&model); + LOGW("models loaded, navmodeld starting"); + + VisionIpcClient vipc_client = VisionIpcClient("navd", VISION_STREAM_MAP, true); + while (!do_exit && !vipc_client.connect(false)) { + util::sleep_for(100); + } + + // run the models + if (vipc_client.connected) { + LOGW("connected with buffer size: %d", vipc_client.buffers[0].len); + run_model(model, vipc_client); + } + + navmodel_free(&model); + return 0; +} From daea877c07a51d82903880e9464eace38ef9a95d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Dec 2022 05:15:14 +0800 Subject: [PATCH 0424/1179] Cabana: add shortcuts (#26528) add shortcuts --- tools/cabana/detailwidget.cc | 4 ++-- tools/cabana/mainwin.cc | 11 ++++++++++- tools/cabana/mainwin.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index c20e2b672e..5035bf49b4 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -85,9 +85,9 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget = new QTabWidget(this); tab_widget->setTabPosition(QTabWidget::South); - tab_widget->addTab(scroll, "Msg"); + tab_widget->addTab(scroll, "&Msg"); history_log = new HistoryLog(this); - tab_widget->addTab(history_log, "Logs"); + tab_widget->addTab(history_log, "&Logs"); main_layout->addWidget(tab_widget); QObject::connect(binary_view, &BinaryView::signalClicked, this, &DetailWidget::showForm); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 324323ac44..6a298bc228 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,7 @@ MainWindow::MainWindow() : QMainWindow() { setCentralWidget(central_widget); createActions(); createStatusBar(); + createShortcuts(); qRegisterMetaType("uint64_t"); qRegisterMetaType("ReplyMsgType"); @@ -156,6 +158,12 @@ void MainWindow::createStatusBar() { statusBar()->addPermanentWidget(progress_bar); } +void MainWindow::createShortcuts() { + auto shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this, nullptr, nullptr, Qt::ApplicationShortcut); + QObject::connect(shortcut, &QShortcut::activated, []() { can->pause(!can->isPaused()); }); + // TODO: add more shortcuts here. +} + void MainWindow::loadDBCFromName(const QString &name) { if (name != dbc()->name()) dbc()->open(name); @@ -225,7 +233,8 @@ void MainWindow::dockCharts(bool dock) { floating_window->deleteLater(); floating_window = nullptr; } else if (!dock && !floating_window) { - floating_window = new QWidget(nullptr); + floating_window = new QWidget(this); + floating_window->setWindowFlags(Qt::Window); floating_window->setWindowTitle("Charts - Cabana"); floating_window->setLayout(new QVBoxLayout()); floating_window->layout()->addWidget(charts_widget); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index bb9280c3ea..5d377c44ca 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -35,6 +35,7 @@ signals: protected: void createActions(); void createStatusBar(); + void createShortcuts(); void closeEvent(QCloseEvent *event) override; void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); From 59ed74ae4a7a51fcfa673393947b755d7b29c323 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 3 Dec 2022 05:15:32 +0800 Subject: [PATCH 0425/1179] Cabanba: new dialog to manage chart series (#26675) * New dialog to manage chart series * connect to signal currentIndexChanged * cleanup use cbegin/cend --- tools/cabana/chartswidget.cc | 133 ++++++++++++++++++++++++++++++++++- tools/cabana/chartswidget.h | 23 ++++++ tools/cabana/dbcmanager.h | 1 + 3 files changed, 156 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index a3faab0a20..79b40133a5 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -196,6 +196,14 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { close_btn_proxy->setWidget(remove_btn); close_btn_proxy->setZValue(chart->zValue() + 11); + QToolButton *manage_btn = new QToolButton(); + manage_btn->setText("🔧"); + manage_btn->setAutoRaise(true); + manage_btn->setToolTip(tr("Manage series")); + manage_btn_proxy = new QGraphicsProxyWidget(chart); + manage_btn_proxy->setWidget(manage_btn); + manage_btn_proxy->setZValue(chart->zValue() + 11); + setChart(chart); setRenderHint(QPainter::Antialiasing); setRubberBand(QChartView::HorizontalRubberBand); @@ -207,6 +215,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated); QObject::connect(&settings, &Settings::changed, this, &ChartView::updateFromSettings); QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); + QObject::connect(manage_btn, &QToolButton::clicked, this, &ChartView::manageSeries); } ChartView::~ChartView() { @@ -278,9 +287,41 @@ void ChartView::msgRemoved(uint32_t address) { } } +void ChartView::manageSeries() { + SeriesSelector dlg(this); + for (auto &s : sigs) { + dlg.addSeries(s.msg_id, msgName(s.msg_id), QString::fromStdString(s.sig->name)); + } + + int ret = dlg.exec(); + if (ret == QDialog::Accepted) { + QList series_list = dlg.series(); + if (series_list.isEmpty()) { + emit remove(); + } else { + for (auto &s : series_list) { + if (auto m = dbc()->msg(s[0])) { + auto it = m->sigs.find(s[2]); + if (it != m->sigs.end() && !hasSeries(s[0], &(it->second))) { + addSeries(s[0], &(it->second)); + } + } + } + for (auto it = sigs.begin(); it != sigs.end(); /**/) { + bool exists = std::any_of(series_list.cbegin(), series_list.cend(), [&](auto &s) { + return s[0] == it->msg_id && s[2] == it->sig->name.c_str(); + }); + it = exists ? ++it : removeSeries(it); + } + } + } +} + void ChartView::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); - close_btn_proxy->setPos(event->size().width() - close_btn_proxy->size().width() - 11, 8); + int x = event->size().width() - close_btn_proxy->size().width() - 11; + close_btn_proxy->setPos(x, 8); + manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); } void ChartView::updateTitle() { @@ -462,3 +503,93 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(QPen(chart()->titleBrush().color(), 2)); painter->drawLine(QPointF{x, chart()->plotArea().top() - 2}, QPointF{x, chart()->plotArea().bottom() + 2}); } + +// SeriesSelector + +SeriesSelector::SeriesSelector(QWidget *parent) { + setWindowTitle(tr("Manage Chart Series")); + QHBoxLayout *contents_layout = new QHBoxLayout(); + + QVBoxLayout *left_layout = new QVBoxLayout(); + left_layout->addWidget(new QLabel(tr("Select Signals:"))); + msgs_combo = new QComboBox(this); + left_layout->addWidget(msgs_combo); + sig_list = new QListWidget(this); + sig_list->setSortingEnabled(true); + sig_list->setToolTip(tr("Double click on an item to add signal to chart")); + left_layout->addWidget(sig_list); + + QVBoxLayout *right_layout = new QVBoxLayout(); + right_layout->addWidget(new QLabel(tr("Chart Signals:"))); + chart_series = new QListWidget(this); + chart_series->setSortingEnabled(true); + chart_series->setToolTip(tr("Double click on an item to remove signal from chart")); + right_layout->addWidget(chart_series); + contents_layout->addLayout(left_layout); + contents_layout->addLayout(right_layout); + + auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->addLayout(contents_layout); + main_layout->addWidget(buttonBox); + + for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) { + if (auto m = dbc()->msg(it.key())) { + msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key()), it.key()); + } + } + msgs_combo->model()->sort(0); + + QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + QObject::connect(msgs_combo, SIGNAL(currentIndexChanged(int)), SLOT(msgSelected(int))); + QObject::connect(sig_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::addSignal); + QObject::connect(chart_series, &QListWidget::itemDoubleClicked, [](QListWidgetItem *item) { delete item; }); + + if (int index = msgs_combo->currentIndex(); index >= 0) { + msgSelected(index); + } +} + +void SeriesSelector::msgSelected(int index) { + QString msg_id = msgs_combo->itemData(index).toString(); + sig_list->clear(); + if (auto m = dbc()->msg(msg_id)) { + for (auto &[name, s] : m->sigs) { + QStringList data({msg_id, m->name, name}); + QListWidgetItem *item = new QListWidgetItem(name, sig_list); + item->setData(Qt::UserRole, data); + sig_list->addItem(item); + } + } +} + +void SeriesSelector::addSignal(QListWidgetItem *item) { + QStringList data = item->data(Qt::UserRole).toStringList(); + addSeries(data[0], data[1], data[2]); +} + +void SeriesSelector::addSeries(const QString &id, const QString& msg_name, const QString &sig_name) { + QStringList data({id, msg_name, sig_name}); + for (int i = 0; i < chart_series->count(); ++i) { + if (chart_series->item(i)->data(Qt::UserRole).toStringList() == data) { + return; + } + } + QListWidgetItem *new_item = new QListWidgetItem(chart_series); + new_item->setData(Qt::UserRole, data); + chart_series->addItem(new_item); + QLabel *label = new QLabel(QString("%0 %1 %2").arg(data[2]).arg(data[1]).arg(data[0]), chart_series); + label->setContentsMargins(5, 0, 5, 0); + new_item->setSizeHint(label->sizeHint()); + chart_series->setItemWidget(new_item, label); +} + +QList SeriesSelector::series() { + QList ret; + for (int i = 0; i < chart_series->count(); ++i) { + ret.push_back(chart_series->item(i)->data(Qt::UserRole).toStringList()); + } + return ret; +} diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index c3fa931e6e..3e3277c5b8 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -1,6 +1,9 @@ #pragma once +#include +#include #include +#include #include #include #include @@ -50,6 +53,7 @@ private slots: void msgUpdated(uint32_t address); void signalUpdated(const Signal *sig); void signalRemoved(const Signal *sig); + void manageSeries(); private: QList::iterator removeSeries(const QList::iterator &it); @@ -70,6 +74,7 @@ private: QGraphicsEllipseItem *track_ellipse; QGraphicsTextItem *value_text; QGraphicsProxyWidget *close_btn_proxy; + QGraphicsProxyWidget *manage_btn_proxy; std::pair events_range = {0, 0}; QList sigs; }; @@ -114,3 +119,21 @@ private: std::pair zoomed_range; bool use_dark_theme = false; }; + +class SeriesSelector : public QDialog { + Q_OBJECT + +public: + SeriesSelector(QWidget *parent); + void addSeries(const QString &id, const QString& msg_name, const QString &sig_name); + QList series(); + +private slots: + void msgSelected(int index); + void addSignal(QListWidgetItem *item); + +private: + QComboBox *msgs_combo; + QListWidget *sig_list; + QListWidget *chart_series; +}; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 4e0bc91069..c7675121bb 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -28,6 +28,7 @@ public: static std::pair parseId(const QString &id); inline static std::vector allDBCNames() { return get_dbc_names(); } + inline std::map &allMsgs() { return msgs; } inline QString name() const { return dbc ? dbc->name.c_str() : ""; } void updateMsg(const QString &id, const QString &name, uint32_t size); From c0d545523e48464acdd6a356d505e0e81266582d Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Fri, 2 Dec 2022 15:36:48 -0600 Subject: [PATCH 0426/1179] Add missing COROLLA_TSS2 EPS, ABS, and engine f/w (#26669) * Add missing COROLLA_TSS2 EPS, ABS, and engine f/w. `@Yin#7979` 2020 Lexus UX 200 DongleID/route ced26c79125dd3e3|2022-12-02--06-03-06 * revert Co-authored-by: Cameron Clough --- selfdrive/car/toyota/values.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index e112ebdb80..98e1f0e99d 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -551,12 +551,10 @@ FW_VERSIONS = { (Ecu.abs, 0x7b0, None): [ b'F152633D00\x00\x00\x00\x00\x00\x00', b'F152633D60\x00\x00\x00\x00\x00\x00', - b'F152633310\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x018966306Q6000\x00\x00\x00\x00', b'\x018966306Q7000\x00\x00\x00\x00', - b'\x018966306V1000\x00\x00\x00\x00', b'\x01896633T20000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 15): [ @@ -567,7 +565,6 @@ FW_VERSIONS = { b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', - b'\x028646F3305500\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.CHR: { @@ -748,6 +745,7 @@ FW_VERSIONS = { b'\x018966312S7000\x00\x00\x00\x00', b'\x018966312W3000\x00\x00\x00\x00', b'\x018966312W9000\x00\x00\x00\x00', + b'\x01896637644000\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'\x0230A10000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', @@ -775,6 +773,7 @@ FW_VERSIONS = { b'\x018965B1255000\x00\x00\x00\x00', b'8965B12361\x00\x00\x00\x00\x00\x00', b'8965B16011\x00\x00\x00\x00\x00\x00', + b'8965B76012\x00\x00\x00\x00\x00\x00', b'\x018965B12510\x00\x00\x00\x00\x00\x00', b'\x018965B1256000\x00\x00\x00\x00', ], @@ -800,6 +799,7 @@ FW_VERSIONS = { b'\x01F152612862\x00\x00\x00\x00\x00\x00', b'\x01F152612B91\x00\x00\x00\x00\x00\x00', b'\x01F15260A070\x00\x00\x00\x00\x00\x00', + b'\x01F152676250\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301100\x00\x00\x00\x00', From 060b69ee2f5148140ec696cbc950b83f700fd671 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Dec 2022 15:25:34 -0800 Subject: [PATCH 0427/1179] micd: revert check playing sound (high cpu usage) (#26672) * don't use hardware * check micd proc * use pactl package * cleanup * Revert "cleanup" This reverts commit baf9887e2d3e7dce8c24a93e970bb5a2d3609d50. * Revert "use pactl package" This reverts commit 0c1f3a4b865e44052affa57323ae4a21d274d6e3. * Revert "micd: don't update filtered sound level if playing sound (#26652)" This reverts commit 86cd919a57be22fa0ccf324a8767999309df60e4. * Revert "check micd proc" This reverts commit 9ebbe2aa42bdfd2f7f8bf226978a518d984fb154. Co-authored-by: Cameron Clough --- system/hardware/base.py | 4 ---- system/hardware/pc/hardware.py | 4 ---- system/hardware/tici/hardware.py | 3 --- system/micd.py | 4 +--- 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/system/hardware/base.py b/system/hardware/base.py index 16ed9621c1..31df1babe0 100644 --- a/system/hardware/base.py +++ b/system/hardware/base.py @@ -43,10 +43,6 @@ class HardwareBase(ABC): def get_sound_card_online(self): pass - @abstractmethod - def is_sound_playing(self): - pass - @abstractmethod def get_imei(self, slot) -> str: pass diff --git a/system/hardware/pc/hardware.py b/system/hardware/pc/hardware.py index 2c83eb35f4..564f9e483a 100644 --- a/system/hardware/pc/hardware.py +++ b/system/hardware/pc/hardware.py @@ -1,5 +1,4 @@ import random -import subprocess from cereal import log from system.hardware.base import HardwareBase, ThermalConfig @@ -18,9 +17,6 @@ class Pc(HardwareBase): def get_sound_card_online(self): return True - def is_sound_playing(self): - return "RUNNING" in subprocess.check_output(["pactl", "list", "short", "sinks"]).decode('utf8') - def reboot(self, reason=None): print("REBOOT!") diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 8371d6ef70..b5f5e00410 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -96,9 +96,6 @@ class Tici(HardwareBase): return (os.path.isfile('/proc/asound/card0/state') and open('/proc/asound/card0/state').read().strip() == 'ONLINE') - def is_sound_playing(self): - return "RUNNING" in subprocess.check_output(["pactl", "list", "short", "sinks"]).decode('utf8') - def reboot(self, reason=None): subprocess.check_output(["sudo", "reboot"]) diff --git a/system/micd.py b/system/micd.py index 57700e5927..d0c661ee0d 100755 --- a/system/micd.py +++ b/system/micd.py @@ -5,7 +5,6 @@ import numpy as np from cereal import messaging from common.filter_simple import FirstOrderFilter from common.realtime import Ratekeeper -from system.hardware import HARDWARE from system.swaglog import cloudlog RATE = 10 @@ -60,8 +59,7 @@ class Mic: sound_pressure, _ = calculate_spl(self.measurements) measurements_weighted = apply_a_weighting(self.measurements) sound_pressure_weighted, sound_pressure_level_weighted = calculate_spl(measurements_weighted) - if not HARDWARE.is_sound_playing(): - self.spl_filter_weighted.update(sound_pressure_level_weighted) + self.spl_filter_weighted.update(sound_pressure_level_weighted) else: sound_pressure = 0 sound_pressure_weighted = 0 From 10085d1e3f61b472c4f25cd3e98d5ee83b40d4eb Mon Sep 17 00:00:00 2001 From: martinl Date: Sat, 3 Dec 2022 01:35:44 +0200 Subject: [PATCH 0428/1179] Subaru: add missing fw values for 2023 Crosstrek Limited (#26678) * Add FPv2: 2023 Crosstrek Limited / @JWynegar * update docs Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/subaru/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index df0dda742c..79e176d4d4 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -138,7 +138,7 @@ A supported vehicle is one that just works when you install a comma three. All s |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Crosstrek 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 9975e495dd..6ac2637fa2 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -63,7 +63,7 @@ CAR_INFO: Dict[str, Union[SubaruCarInfo, List[SubaruCarInfo]]] = { ], CAR.IMPREZA_2020: [ SubaruCarInfo("Subaru Impreza 2020-22"), - SubaruCarInfo("Subaru Crosstrek 2020-21"), + SubaruCarInfo("Subaru Crosstrek 2020-23"), SubaruCarInfo("Subaru XV 2020-21"), ], CAR.FORESTER: SubaruCarInfo("Subaru Forester 2019-21", "All"), @@ -235,12 +235,14 @@ FW_VERSIONS = { b'\x9a\xc0\000\000', b'\n\xc0\004\000', b'\x9a\xc0\x04\x00', + b'\n\xc0\x04\x01', ], (Ecu.fwdCamera, 0x787, None): [ b'\000\000eb\037@ \"', b'\000\000e\x8f\037@ )', b'\x00\x00eq\x1f@ "', b'\x00\x00eq\x00\x00\x00\x00', + b'\x00\x00e\x8f\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ b'\xca!ap\a', @@ -250,6 +252,7 @@ FW_VERSIONS = { b'\xcc!fp\a', b'\xca!f@\x07', b'\xca!fp\x07', + b'\xf3"f@\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xe6\xf5\004\000\000', @@ -258,6 +261,7 @@ FW_VERSIONS = { b'\xe7\xf5D0\000', b'\xf1\x00\xd7\x10@', b'\xe6\xf5D0\x00', + b'\xe9\xf6F0\x00', ], }, CAR.FORESTER: { From 20dba2f33d870d81347ff7045911797a286c9128 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Dec 2022 18:38:04 -0800 Subject: [PATCH 0429/1179] Micd: update sound levels in callback (#26674) * update once reached 4096 * update once reached 4096 * reduce * debug & cmt * fix * fifo again * fix * clean that up * update filter on demand Co-authored-by: Cameron Clough --- system/micd.py | 54 +++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/system/micd.py b/system/micd.py index d0c661ee0d..a56140e3b9 100755 --- a/system/micd.py +++ b/system/micd.py @@ -8,9 +8,10 @@ from common.realtime import Ratekeeper from system.swaglog import cloudlog RATE = 10 -DT_MIC = 1. / RATE +FFT_SAMPLES = 4096 REFERENCE_SPL = 2e-5 # newtons/m^2 SAMPLE_RATE = 44100 +FILTER_DT = 1. / (SAMPLE_RATE / FFT_SAMPLES) def calculate_spl(measurements): @@ -45,9 +46,25 @@ class Mic: self.rk = Ratekeeper(RATE) self.measurements = np.empty(0) - self.spl_filter_weighted = FirstOrderFilter(0, 2.5, DT_MIC, initialized=False) + + self.sound_pressure = 0 + self.sound_pressure_weighted = 0 + self.sound_pressure_level_weighted = 0 + + self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) def update(self): + msg = messaging.new_message('microphone') + msg.microphone.soundPressure = float(self.sound_pressure) + msg.microphone.soundPressureWeighted = float(self.sound_pressure_weighted) + + msg.microphone.soundPressureWeightedDb = float(self.sound_pressure_level_weighted) + msg.microphone.filteredSoundPressureWeightedDb = float(self.spl_filter_weighted.x) + + self.pm.send('microphone', msg) + self.rk.keep_time() + + def callback(self, indata, frames, time, status): """ Using amplitude measurements, calculate an uncalibrated sound pressure and sound pressure level. Then apply A-weighting to the raw amplitudes and run the same calculations again. @@ -55,31 +72,18 @@ class Mic: Logged A-weighted equivalents are rough approximations of the human-perceived loudness. """ - if len(self.measurements) > 0: - sound_pressure, _ = calculate_spl(self.measurements) - measurements_weighted = apply_a_weighting(self.measurements) - sound_pressure_weighted, sound_pressure_level_weighted = calculate_spl(measurements_weighted) - self.spl_filter_weighted.update(sound_pressure_level_weighted) - else: - sound_pressure = 0 - sound_pressure_weighted = 0 - sound_pressure_level_weighted = 0 - - self.measurements = np.empty(0) - - msg = messaging.new_message('microphone') - msg.microphone.soundPressure = float(sound_pressure) - msg.microphone.soundPressureWeighted = float(sound_pressure_weighted) - - msg.microphone.soundPressureWeightedDb = float(sound_pressure_level_weighted) - msg.microphone.filteredSoundPressureWeightedDb = float(self.spl_filter_weighted.x) - - self.pm.send('microphone', msg) - self.rk.keep_time() - - def callback(self, indata, frames, time, status): self.measurements = np.concatenate((self.measurements, indata[:, 0])) + while self.measurements.size >= FFT_SAMPLES: + measurements = self.measurements[:FFT_SAMPLES] + + self.sound_pressure, _ = calculate_spl(measurements) + measurements_weighted = apply_a_weighting(measurements) + self.sound_pressure_weighted, self.sound_pressure_level_weighted = calculate_spl(measurements_weighted) + self.spl_filter_weighted.update(self.sound_pressure_level_weighted) + + self.measurements = self.measurements[FFT_SAMPLES:] + def micd_thread(self, device=None): if device is None: device = "sysdefault" From 92296ce55d7e910c809658ad8f7eeaab6ded875c Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Sat, 3 Dec 2022 11:53:50 +0900 Subject: [PATCH 0430/1179] remove unused space (#26680) --- selfdrive/ui/qt/onroad.cc | 2 +- selfdrive/ui/ui.cc | 3 +-- selfdrive/ui/ui.h | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 50f891dd56..fed59ef123 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -204,7 +204,7 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { v_ego_cluster_seen = true; } float cur_speed = cs_alive ? std::max(0.0, v_ego) : 0.0; - cur_speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; + cur_speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; auto speed_limit_sign = sm["navInstruction"].getNavInstruction().getSpeedLimitSign(); float speed_limit = nav_alive ? sm["navInstruction"].getNavInstruction().getSpeedLimit() : 0.0; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 2d4533afe1..c62d737481 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -55,9 +55,8 @@ void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, con } void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, - float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) { + float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) { const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); - QPolygonF left_points, right_points; left_points.reserve(max_idx + 1); right_points.reserve(max_idx + 1); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index d6f5c3e2e0..9e1c54948b 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -20,7 +20,7 @@ const int bdr_s = 30; const int header_h = 420; const int footer_h = 280; -const int UI_FREQ = 20; // Hz +const int UI_FREQ = 20; // Hz typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; const mat3 DEFAULT_CALIBRATION = {{ 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0 }}; @@ -78,7 +78,7 @@ typedef enum UIStatus { } UIStatus; const QColor bg_colors [] = { - [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8), + [STATUS_DISENGAGED] = QColor(0x17, 0x33, 0x49, 0xc8), [STATUS_OVERRIDE] = QColor(0x91, 0x9b, 0x95, 0xf1), [STATUS_ENGAGED] = QColor(0x17, 0x86, 0x44, 0xf1), [STATUS_WARNING] = QColor(0xDA, 0x6F, 0x25, 0xf1), @@ -152,7 +152,6 @@ private: UIState *uiState(); // device management class - class Device : public QObject { Q_OBJECT From ea857b0f71c5bb981b209ac35e63fcbdb1ecf5d4 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 2 Dec 2022 22:26:04 -0500 Subject: [PATCH 0431/1179] VW MQB: Engage at standstill with OP longitudinal (#26656) * VW MQB: Allow engage at standstill * retry CI * Update selfdrive/car/volkswagen/interface.py Co-authored-by: Shane Smiskol * Revert "Update selfdrive/car/volkswagen/interface.py" This reverts commit 14c7412bf74b23ae88c05cad40aafd4605a63c29. Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index d90a36ed3e..da0ce25afa 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -230,7 +230,7 @@ class CarInterface(CarInterfaceBase): events.add(EventName.belowSteerSpeed) if self.CS.CP.openpilotLongitudinalControl: - if ret.vEgo < self.CP.minEnableSpeed + 2.: + if ret.vEgo < self.CP.minEnableSpeed + 0.5: events.add(EventName.belowEngageSpeed) if c.enabled and ret.vEgo < self.CP.minEnableSpeed: events.add(EventName.speedTooLow) From 3e2a49c6e5a526c7af5667ea7bd62f91b20ab0a9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 2 Dec 2022 22:09:42 -0800 Subject: [PATCH 0432/1179] GM: add Bolt EV test route (#26681) * bolt ev! * releases * it's a trim --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/gm/interface.py | 4 ++-- selfdrive/car/gm/values.py | 11 ++++++----- selfdrive/car/tests/routes.py | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 7b51e6dff3..c41b3ed0f7 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3,6 +3,7 @@ Version 0.9.1 (2022-12-XX) * Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! +* Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! Version 0.9.0 (2022-11-21) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index 79e176d4d4..30411adc23 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 216 Supported Cars +# 217 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -19,6 +19,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 7d38c60900..195df36a7f 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -97,7 +97,7 @@ class CarInterface(CarInterfaceBase): # These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars likely still work fine. Once a user confirms each car works and a test route is # added to selfdrive/car/tests/routes.py, we can remove it from this list. - ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX, CAR.BOLT_EV} + ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below. # Some GMs need some tolerance above 10 kph to avoid a fault @@ -170,7 +170,7 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 0.000045 tire_stiffness_factor = 1.0 - elif candidate in (CAR.BOLT_EV, CAR.BOLT_EUV): + elif candidate == CAR.BOLT_EUV: ret.mass = 1669. + STD_CARGO_KG ret.wheelbase = 2.63779 ret.steerRatio = 16.8 diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 0a8cdc6dbb..84fa36a994 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -68,7 +68,6 @@ class CAR: ACADIA = "GMC ACADIA DENALI 2018" BUICK_REGAL = "BUICK REGAL ESSENCE 2018" ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016" - BOLT_EV = "CHEVROLET BOLT EV 2022" BOLT_EUV = "CHEVROLET BOLT EUV 2022" SILVERADO = "CHEVROLET SILVERADO 1500 2020" EQUINOX = "CHEVROLET EQUINOX 2019" @@ -101,8 +100,10 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), - CAR.BOLT_EV: GMCarInfo("Chevrolet Bolt EV 2022-23"), - CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210"), + CAR.BOLT_EUV: [ + GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210"), + GMCarInfo("Chevrolet Bolt EV 2022-23", "2LT Trim with Adaptive Cruise Control Package"), + ], CAR.SILVERADO: [ GMCarInfo("Chevrolet Silverado 1500 2020-21", "Safety Package II"), GMCarInfo("GMC Sierra 1500 2020-21", "Driver Alert Package II", "https://youtu.be/5HbNoBLzRwE"), @@ -193,9 +194,9 @@ FINGERPRINTS = { DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict('gm_global_a_powertrain_generated', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis')) -EV_CAR = {CAR.VOLT, CAR.BOLT_EV, CAR.BOLT_EUV} +EV_CAR = {CAR.VOLT, CAR.BOLT_EUV} # We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness) -CAMERA_ACC_CAR = {CAR.BOLT_EV, CAR.BOLT_EUV, CAR.SILVERADO, CAR.EQUINOX} +CAMERA_ACC_CAR = {CAR.BOLT_EUV, CAR.SILVERADO, CAR.EQUINOX} STEER_THRESHOLD = 1.0 diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index da19e1f367..a20616de43 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -22,7 +22,6 @@ non_tested_cars = [ GM.HOLDEN_ASTRA, GM.MALIBU, GM.EQUINOX, - GM.BOLT_EV, HYUNDAI.GENESIS_G90, HYUNDAI.KIA_OPTIMA_H, HONDA.ODYSSEY_CHN, @@ -51,6 +50,7 @@ routes = [ CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV), CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT), CarTestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.BOLT_EUV, segment=1), + CarTestRoute("555d4087cf86aa91|2022-12-02--12-15-07", GM.BOLT_EUV, segment=14), # Bolt EV CarTestRoute("38aa7da107d5d252|2022-08-15--16-01-12", GM.SILVERADO), CarTestRoute("0e7a2ba168465df5|2020-10-18--14-14-22", HONDA.ACURA_RDX_3G), From 122c3143589418b74dd6b658607ac5c8d43fb4af Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 2 Dec 2022 23:46:26 -0800 Subject: [PATCH 0433/1179] Hyundai: setup alt steering limits (#26685) * Hyundai: setup alt steering limits * value * bump panda --- panda | 2 +- selfdrive/car/hyundai/carcontroller.py | 3 --- selfdrive/car/hyundai/interface.py | 4 ++++ selfdrive/car/hyundai/values.py | 8 ++++++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/panda b/panda index 616450c525..4edd1a6021 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 616450c525a7c1ef508f70f30e29547a606139aa +Subproject commit 4edd1a602131ec2f09a604a4bd28e7d00e334458 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index e5fdbfd57a..3f128b1598 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -60,9 +60,6 @@ class CarController: # steering torque steer = actuators.steer - if self.CP.carFingerprint in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022): - # these cars have significantly more torque than most HKG; limit to 70% of max - steer = clip(steer, -0.7, 0.7) new_steer = int(round(steer * self.params.STEER_MAX)) apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index cb4d9a9688..7b157d048b 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -267,6 +267,10 @@ class CarInterface(CarInterfaceBase): elif candidate in EV_CAR: ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_EV_GAS + if candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022): + ret.flags |= HyundaiFlags.ALT_LIMITS.value + ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_ALT_LIMITS + ret.centerToFront = ret.wheelbase * 0.4 # TODO: start from empirically derived lateral slip stiffness for the civic and scale by diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 7ecb07e7d7..e5f180a510 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -39,6 +39,12 @@ class CarControllerParams: CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO): self.STEER_MAX = 255 + # these cars have significantly more torque than most HKG; limit to 70% of max + elif CP.flags & HyundaiFlags.ALT_LIMITS: + self.STEER_MAX = 270 + self.STEER_DELTA_UP = 2 + self.STEER_DELTA_DOWN = 3 + # Default for most HKG else: self.STEER_MAX = 384 @@ -50,6 +56,8 @@ class HyundaiFlags(IntFlag): CANFD_ALT_GEARS = 4 CANFD_CAMERA_SCC = 8 + ALT_LIMITS = 16 + class CAR: # Hyundai From d3a66015ad99c54b03bc3693857fbea825122208 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 3 Dec 2022 02:05:24 -0800 Subject: [PATCH 0434/1179] Toyota: log EPS fault from LKA cmd message drop out (#26687) * log additional faults * bump opendbc --- opendbc | 2 +- selfdrive/car/toyota/carstate.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/opendbc b/opendbc index 3737675445..94fff4782b 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 373767544559718d74bff58dd23890eea1d38a29 +Subproject commit 94fff4782be263efad10032a612b3c96a120c0b7 diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index dbbb8a6f04..250c6b65ae 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -85,10 +85,12 @@ class CarState(CarStateBase): ret.steeringTorqueEps = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_EPS"] * self.eps_torque_scale # we could use the override bit from dbc, but it's triggered at too high torque values ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD - # steer rate fault, goes to 21 or 25 for 1 frame, then 9 for ~2 seconds - ret.steerFaultTemporary = cp.vl["EPS_STATUS"]["LKA_STATE"] in (0, 9, 21, 25) + # steer rate fault: goes to 21 or 25 for 1 frame, then 9 for 2 seconds + # lka msg drop out: goes to 9 then 11 for a combined total of 2 seconds + ret.steerFaultTemporary = cp.vl["EPS_STATUS"]["LKA_STATE"] in (0, 9, 11, 21, 25) # 17 is a fault from a prolonged high torque delta between cmd and user - ret.steerFaultPermanent = cp.vl["EPS_STATUS"]["LKA_STATE"] == 17 + # 3 is a fault from the lka command message not being received by the EPS + ret.steerFaultPermanent = cp.vl["EPS_STATUS"]["LKA_STATE"] in (3, 17) if self.CP.carFingerprint in UNSUPPORTED_DSU_CAR: ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0 From 5b10deba2ed2a70524d47435640f37655fc593bd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 3 Dec 2022 03:02:57 -0800 Subject: [PATCH 0435/1179] Toyota: log ACC faults (#26682) * add acc faulted * use faster signal * bump * we know PCM_CRUISE_SM is not what we want --- selfdrive/car/toyota/carstate.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 250c6b65ae..fec006fbb4 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -93,10 +93,12 @@ class CarState(CarStateBase): ret.steerFaultPermanent = cp.vl["EPS_STATUS"]["LKA_STATE"] in (3, 17) if self.CP.carFingerprint in UNSUPPORTED_DSU_CAR: + # TODO: find the bit likely in DSU_CRUISE that describes an ACC fault. one may also exist in CLUTCH ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0 ret.cruiseState.speed = cp.vl["DSU_CRUISE"]["SET_SPEED"] * CV.KPH_TO_MS cluster_set_speed = cp.vl["PCM_CRUISE_ALT"]["UI_SET_SPEED"] else: + ret.accFaulted = cp.vl["PCM_CRUISE_2"]["ACC_FAULTED"] != 0 ret.cruiseState.available = cp.vl["PCM_CRUISE_2"]["MAIN_ON"] != 0 ret.cruiseState.speed = cp.vl["PCM_CRUISE_2"]["SET_SPEED"] * CV.KPH_TO_MS cluster_set_speed = cp.vl["PCM_CRUISE_SM"]["UI_SET_SPEED"] @@ -205,6 +207,7 @@ class CarState(CarStateBase): else: signals.append(("MAIN_ON", "PCM_CRUISE_2")) signals.append(("SET_SPEED", "PCM_CRUISE_2")) + signals.append(("ACC_FAULTED", "PCM_CRUISE_2")) signals.append(("LOW_SPEED_LOCKOUT", "PCM_CRUISE_2")) checks.append(("PCM_CRUISE_2", 33)) From 7b0bfabb95ecb39487d311ba6ccc6b4c4e11ff08 Mon Sep 17 00:00:00 2001 From: cydia2020 <12470297+cydia2020@users.noreply.github.com> Date: Sat, 3 Dec 2022 23:31:31 +1100 Subject: [PATCH 0436/1179] Toyota: Don't Set Standstill Bit on TSS-P Prius (#26671) * Toyota: set TSS-P Prius as NO_STOP_TIMER_CAR * reflect in docs * also the PHV --- docs/CARS.md | 6 +++--- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 30411adc23..580e2ad461 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -179,10 +179,10 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 98e1f0e99d..04ffc79f4f 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -2053,4 +2053,4 @@ EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2 CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} # no resume button press required -NO_STOP_TIMER_CAR = TSS2_CAR | {CAR.PRIUS_V, CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_ESH} +NO_STOP_TIMER_CAR = TSS2_CAR | {CAR.PRIUS, CAR.PRIUS_V, CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_ESH} From 0ff703d82fd6d93f8d260d7aa40e24c5146a0775 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 5 Dec 2022 03:28:40 +0800 Subject: [PATCH 0437/1179] Replay: fix SEGFAULT in buildTimeline if segments are not continuous. (#26691) fix segfault in buildtimeline --- tools/replay/replay.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 1464a6cf57..339e688be1 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -123,9 +123,9 @@ void Replay::buildTimeline() { uint64_t alert_begin = 0; TimelineType alert_type = TimelineType::None; - for (int i = 0; i < segments_.size() && !exit_; ++i) { + for (auto it = segments_.cbegin(); it != segments_.cend() && !exit_; ++it) { LogReader log; - if (!log.load(route_->at(i).qlog.toStdString(), &exit_, + if (!log.load(route_->at(it->first).qlog.toStdString(), &exit_, {cereal::Event::Which::CONTROLS_STATE, cereal::Event::Which::USER_FLAG}, !hasFlag(REPLAY_FLAG_NO_FILE_CACHE), 0, 3)) continue; From f6496ce6702090747f2ee45f26a8ef91730cc9ef Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 5 Dec 2022 03:28:54 +0800 Subject: [PATCH 0438/1179] Cabana: show video thumbnail over slider (#26689) * show thumbnail * copy segments vector * cleanup cleanup mouseMoveEvent cleanup include * move lambda to memeber function * reduce lock time * private functions * split to small functions --- tools/cabana/canmessages.h | 3 +- tools/cabana/mainwin.cc | 2 +- tools/cabana/videowidget.cc | 62 +++++++++++++++++++++++++++++++++++++ tools/cabana/videowidget.h | 15 +++++++++ 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 4cb0f403a0..1713778af7 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -31,7 +31,7 @@ public: QList findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); bool eventFilter(const Event *event); - inline QString route() const { return replay->route()->name(); } + inline QString routeName() const { return replay->route()->name(); } inline QString carFingerprint() const { return replay->carFingerprint().c_str(); } inline double totalSeconds() const { return replay->totalSeconds(); } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } @@ -39,6 +39,7 @@ public: const std::deque messages(const QString &id); inline const CanData &lastMessage(const QString &id) { return can_msgs[id]; } + inline const Route* route() const { return replay->route(); } inline const std::vector *events() const { return replay->events(); } inline void setSpeed(float speed) { replay->setSpeed(speed); } inline bool isPaused() const { return replay->isPaused(); } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 6a298bc228..70297f9978 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -71,7 +71,7 @@ MainWindow::MainWindow() : QMainWindow() { right_hlayout->addWidget(fingerprint_label, 0, Qt::AlignLeft); // TODO: click to select another route. - right_hlayout->addWidget(new QLabel(can->route()), 0, Qt::AlignRight); + right_hlayout->addWidget(new QLabel(can->routeName()), 0, Qt::AlignRight); r_layout->addLayout(right_hlayout); video_widget = new VideoWidget(this); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index d85b23b7e6..3e64d907ec 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -1,13 +1,17 @@ #include "tools/cabana/videowidget.h" +#include #include #include #include #include #include +#include #include #include +#include #include +#include inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); @@ -92,7 +96,50 @@ Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { timeline = can->getTimeline(); update(); }); + setMouseTracking(true); + QObject::connect(can, SIGNAL(streamStarted()), timer, SLOT(start())); + QObject::connect(can, &CANMessages::streamStarted, this, &Slider::streamStarted); +} + +void Slider::streamStarted() { + abort_load_thumbnail = true; + thumnail_future.waitForFinished(); + abort_load_thumbnail = false; + thumbnails.clear(); + thumnail_future = QtConcurrent::run(this, &Slider::loadThumbnails); +} + +void Slider::loadThumbnails() { + const auto segments = can->route()->segments(); + for (auto it = segments.rbegin(); it != segments.rend() && !abort_load_thumbnail; ++it) { + std::string qlog = it->second.qlog.toStdString(); + if (!qlog.empty()) { + LogReader log; + if (log.load(qlog, &abort_load_thumbnail, {cereal::Event::Which::THUMBNAIL}, true, 0, 3)) { + for (auto ev = log.events.cbegin(); ev != log.events.cend() && !abort_load_thumbnail; ++ev) { + auto thumb = (*ev)->event.getThumbnail(); + QString str = getThumbnailString(thumb.getThumbnail()); + std::lock_guard lk(thumbnail_lock); + thumbnails[thumb.getTimestampEof()] = str; + } + } + } + } +} + +QString Slider::getThumbnailString(const capnp::Data::Reader &data) { + QPixmap thumb; + if (thumb.loadFromData(data.begin(), data.size(), "jpeg")) { + thumb = thumb.scaled({thumb.width()/3, thumb.height()/3}, Qt::KeepAspectRatio); + thumbnail_size = thumb.size(); + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::WriteOnly); + thumb.save(&buffer, "png"); + return QString("").arg(QString(bytes.toBase64())); + } + return {}; } void Slider::sliderChange(QAbstractSlider::SliderChange change) { @@ -146,3 +193,18 @@ void Slider::mousePressEvent(QMouseEvent *e) { emit sliderReleased(); } } + +void Slider::mouseMoveEvent(QMouseEvent *e) { + QString thumb; + { + double seconds = (minimum() + e->pos().x() * ((maximum() - minimum()) / (double)width())) / 1000.0; + std::lock_guard lk(thumbnail_lock); + auto it = thumbnails.lowerBound((seconds + can->routeStartTime()) * 1e9); + if (it != thumbnails.end()) { + thumb = it.value(); + } + } + QPoint pt = mapToGlobal({e->pos().x() - thumbnail_size.width() / 2, -thumbnail_size.height() - 30}); + QToolTip::showText(pt, thumb, this, rect()); + QSlider::mouseMoveEvent(e); +} diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 16f60b0b03..ea62081a91 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -1,5 +1,9 @@ #pragma once +#include +#include + +#include #include #include #include @@ -12,12 +16,23 @@ class Slider : public QSlider { public: Slider(QWidget *parent); + +private: void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; void sliderChange(QAbstractSlider::SliderChange change) override; void paintEvent(QPaintEvent *ev) override; + void streamStarted(); + void loadThumbnails(); + QString getThumbnailString(const capnp::Data::Reader &data); int slider_x = -1; std::vector> timeline; + std::mutex thumbnail_lock; + std::atomic abort_load_thumbnail = false; + QMap thumbnails; + QFuture thumnail_future; + QSize thumbnail_size = {}; }; class VideoWidget : public QWidget { From b513b832214f5427dd5d6c217f2e31b4bcecdfac Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 5 Dec 2022 03:30:31 +0800 Subject: [PATCH 0439/1179] Replay: remove wrong text in TIME (#26692) remove wrong time string --- tools/replay/consoleui.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/replay/consoleui.cc b/tools/replay/consoleui.cc index 5f165ac312..77357a2873 100644 --- a/tools/replay/consoleui.cc +++ b/tools/replay/consoleui.cc @@ -156,13 +156,13 @@ void ConsoleUI::timerEvent(QTimerEvent *ev) { } void ConsoleUI::updateStatus() { - auto write_item = [this](int y, int x, const char *key, const std::string &value, const char *unit, + auto write_item = [this](int y, int x, const char *key, const std::string &value, const std::string &unit, bool bold = false, Color color = Color::BrightWhite) { auto win = w[Win::CarState]; wmove(win, y, x); add_str(win, key); add_str(win, value.c_str(), color, bold); - add_str(win, unit); + add_str(win, unit.c_str()); }; static const std::pair status_text[] = { {"loading...", Color::Red}, @@ -177,9 +177,8 @@ void ConsoleUI::updateStatus() { } auto [status_str, status_color] = status_text[status]; write_item(0, 0, "STATUS: ", status_str, " ", false, status_color); - std::string suffix = util::string_format(" / %s [%d/%d] ", format_seconds(replay->totalSeconds()).c_str(), - replay->currentSeconds() / 60, replay->route()->segments().size()); - write_item(0, 25, "TIME: ", format_seconds(replay->currentSeconds()), suffix.c_str(), true); + std::string suffix = " / " + format_seconds(replay->totalSeconds()); + write_item(0, 25, "TIME: ", format_seconds(replay->currentSeconds()), suffix, true); auto p = sm["liveParameters"].getLiveParameters(); write_item(1, 0, "STIFFNESS: ", util::string_format("%.2f %%", p.getStiffnessFactor() * 100), " "); From 2976260b4f57953ac230f0d85349cf3d0ba23168 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 4 Dec 2022 11:33:58 -0800 Subject: [PATCH 0440/1179] Hyundai: update Kona lat accel factor --- selfdrive/car/torque_data/params.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 7901972fc2..c081359937 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -31,7 +31,7 @@ HYUNDAI IONIQ 5 2022: [3.172929, 3.0, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] HYUNDAI IONIQ PLUG-IN HYBRID 2019: [2.970807902012267, 1.6312321830002083, 0.1088964990357482] -HYUNDAI KONA ELECTRIC 2019: [4.398306735170212, 3.2961956260770484, 0.08651833437845884] +HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 3.2961956260770484, 0.08651833437845884] HYUNDAI PALISADE 2020: [2.544642494803999, 1.8721703683337008, 0.1301424599248651] HYUNDAI SANTA FE 2019: [3.0787027729757632, 2.6173437483495565, 0.1207019341823945] HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963] From 0398f3ecf4c62e26768f3baa661ac27b9280955c Mon Sep 17 00:00:00 2001 From: Nelson Chen Date: Sun, 4 Dec 2022 14:46:52 -0800 Subject: [PATCH 0441/1179] Undo accidental revert of Toyota: Add FW for 2023 Toyota Camry Hybrid #26654 (#26699) Fix accidental revert of 1f4554b0c030cfc2623d7c7db413e9c61dabaef4 in c0d545523e48464acdd6a356d505e0e81266582d --- selfdrive/car/toyota/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 04ffc79f4f..c9e13e21a1 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -551,10 +551,12 @@ FW_VERSIONS = { (Ecu.abs, 0x7b0, None): [ b'F152633D00\x00\x00\x00\x00\x00\x00', b'F152633D60\x00\x00\x00\x00\x00\x00', + b'F152633310\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x018966306Q6000\x00\x00\x00\x00', b'\x018966306Q7000\x00\x00\x00\x00', + b'\x018966306V1000\x00\x00\x00\x00', b'\x01896633T20000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 15): [ @@ -565,6 +567,7 @@ FW_VERSIONS = { b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', + b'\x028646F3305500\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.CHR: { From f84b1f2d9f772b1470eee99503b6dc1d0c813957 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 6 Dec 2022 05:05:41 +0800 Subject: [PATCH 0442/1179] Sensord: remove unused pm_mutex (#26705) remove unused mutex --- selfdrive/sensord/sensors_qcom2.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/sensord/sensors_qcom2.cc b/selfdrive/sensord/sensors_qcom2.cc index 2279cf2532..fc8dc8620b 100644 --- a/selfdrive/sensord/sensors_qcom2.cc +++ b/selfdrive/sensord/sensors_qcom2.cc @@ -27,7 +27,6 @@ #define I2C_BUS_IMU 1 ExitHandler do_exit; -std::mutex pm_mutex; uint64_t init_ts = 0; void interrupt_loop(std::vector& sensors, From e6fcc2d6aa582f90fd3a2b2192616005f875fcb2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 5 Dec 2022 13:58:15 -0800 Subject: [PATCH 0443/1179] planner: read experimental mode from controlsState (#26553) read from controlsState --- selfdrive/controls/lib/longitudinal_planner.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index def0a1208a..a0f6318323 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -6,7 +6,6 @@ from common.numpy_fast import clip, interp import cereal.messaging as messaging from common.conversions import Conversions as CV from common.filter_simple import FirstOrderFilter -from common.params import Params from common.realtime import DT_MDL from selfdrive.modeld.constants import T_IDXS from selfdrive.controls.lib.longcontrol import LongCtrlState @@ -48,12 +47,7 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP): class LongitudinalPlanner: def __init__(self, CP, init_v=0.0, init_a=0.0): self.CP = CP - self.params = Params() - self.param_read_counter = 0 - self.mpc = LongitudinalMpc() - self.read_param() - self.fcw = False self.a_desired = init_a @@ -65,10 +59,6 @@ class LongitudinalPlanner: self.j_desired_trajectory = np.zeros(CONTROL_N) self.solverExecutionTime = 0.0 - def read_param(self): - e2e = self.params.get_bool('ExperimentalMode') and self.CP.openpilotLongitudinalControl - self.mpc.mode = 'blended' if e2e else 'acc' - @staticmethod def parse_model(model_msg, model_error): if (len(model_msg.position.x) == 33 and @@ -85,10 +75,8 @@ class LongitudinalPlanner: j = np.zeros(len(T_IDXS_MPC)) return x, v, a, j - def update(self, sm, read=True): - if self.param_read_counter % 50 == 0 and read: - self.read_param() - self.param_read_counter += 1 + def update(self, sm): + self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc' v_ego = sm['carState'].vEgo v_cruise_kph = sm['controlsState'].vCruise From 2d0e29d60e1a74ef79de7e64af1495c94d262fcd Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Mon, 5 Dec 2022 16:59:36 -0500 Subject: [PATCH 0444/1179] VW MQB: Add FW for 2018 Volkswagen Atlas (#26702) --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index c96f6decbf..18a444bf7c 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -320,11 +320,13 @@ FW_VERSIONS = { b'\xf1\x8703H906026J \xf1\x899971', b'\xf1\x8703H906026S \xf1\x896693', b'\xf1\x8703H906026S \xf1\x899970', + b'\xf1\x873CN906259 \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158A \xf1\x893387', b'\xf1\x8709G927158DR\xf1\x893536', b'\xf1\x8709G927158DR\xf1\x893742', + b'\xf1\x8709G927158F \xf1\x893489', b'\xf1\x8709G927158FT\xf1\x893835', b'\xf1\x8709G927158GL\xf1\x893939', ], @@ -338,6 +340,7 @@ FW_VERSIONS = { (Ecu.eps, 0x712, None): [ b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\00571B60924A1', b'\xf1\x873QF909144B \xf1\x891582\xf1\x82\x0571B6G920A1', + b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820528B6080105', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820528B6090105', ], (Ecu.fwdRadar, 0x757, None): [ From 4d74e44ae14301aab27b833974bb90955d20d04e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 6 Dec 2022 07:12:36 +0800 Subject: [PATCH 0445/1179] Cabana: display dash instead of zero if no data (#26686) display dash instead of zero if no data --- tools/cabana/binaryview.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index e655bf0c04..bc64edbfeb 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -181,15 +181,14 @@ 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(); + if (binary.size() > row_count) { + beginInsertRows({}, row_count, binary.size() - 1); row_count = binary.size(); - items.clear(); items.resize(row_count * column_count); - endResetModel(); + endInsertRows(); } char hex[3] = {'\0'}; - for (int i = 0; i < std::min(binary.size(), row_count); ++i) { + for (int i = 0; i < binary.size(); ++i) { for (int j = 0; j < column_count - 1; ++j) { items[i * column_count + j].val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0'; } @@ -197,8 +196,13 @@ void BinaryViewModel::updateState() { hex[1] = toHex(binary[i] & 0xf); items[i * column_count + 8].val = hex; } + for (int i = binary.size(); i < row_count; ++i) { + for (int j = 0; j < column_count; ++j) { + items[i * column_count + j].val = "-"; + } + } - for (int i = 0; i < items.size(); ++i) { + for (int i = 0; i < row_count; ++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); From be0c2dbbf9ea3ae2c94a057b22e972f405f7e67f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 5 Dec 2022 15:23:00 -0800 Subject: [PATCH 0446/1179] Longitudinal planner: fix tests (#26707) fix tests --- selfdrive/test/longitudinal_maneuvers/plant.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index c3af1eee03..0d3336134f 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -4,6 +4,7 @@ import numpy as np from cereal import log import cereal.messaging as messaging +from common.params import Params from common.realtime import Ratekeeper, DT_MDL from selfdrive.controls.lib.longcontrol import LongCtrlState from selfdrive.modeld.constants import T_IDXS @@ -17,6 +18,7 @@ class Plant: def __init__(self, lead_relevancy=False, speed=0.0, distance_lead=2.0, enabled=True, only_lead2=False, only_radar=False): self.rate = 1. / DT_MDL + self.params = Params() if not Plant.messaging_initialized: Plant.radar = messaging.pub_sock('radarState') @@ -109,6 +111,7 @@ class Plant: control.controlsState.longControlState = LongCtrlState.pid if self.enabled else LongCtrlState.off control.controlsState.vCruise = float(v_cruise * 3.6) + control.controlsState.experimentalMode = self.params.get_bool("ExperimentalMode") car_state.carState.vEgo = float(self.speed) car_state.carState.standstill = self.speed < 0.01 From 973ecdc0c9c719a255b39dad69923be0e2ede1a5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 5 Dec 2022 15:24:54 -0800 Subject: [PATCH 0447/1179] Hyundai: Tucson 2023 support (#26427) * Hardcode fingerprint * no skipping * rev * the SE does not have SCC https://cdn.dealereprocess.org/cdn/brochures/hyundai/2022-tucson.pdf * revert * adjust weight * add versions for 2023 * update docs * fingerprint properly * add package for 2022 but comment out * updatedocs * update route * bump * bump! * 2022 * Update selfdrive/car/tests/routes.py --- RELEASES.md | 1 + docs/CARS.md | 4 +++- selfdrive/car/hyundai/interface.py | 4 ++-- selfdrive/car/hyundai/values.py | 22 ++++++++++++++++++---- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index c41b3ed0f7..44fc5e715e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,6 +4,7 @@ Version 0.9.1 (2022-12-XX) * Removed driver monitoring timer resetting on interaction if face detected and distracted * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! +* Hyundai Tucson 2022-23 support Version 0.9.0 (2022-11-21) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index 580e2ad461..141e910fa5 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 217 Supported Cars +# 219 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -83,6 +83,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Sonata 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Hyundai|Tucson 2023|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Tucson Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 7b157d048b..b9f6b8fc58 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -114,8 +114,8 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.67 ret.steerRatio = 14.00 * 1.15 tire_stiffness_factor = 0.385 - elif candidate == CAR.TUCSON_HYBRID_4TH_GEN: - ret.mass = 1680. + STD_CARGO_KG # average of all 3 trims + elif candidate in (CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN): + ret.mass = 1630. + STD_CARGO_KG # average ret.wheelbase = 2.756 ret.steerRatio = 16. tire_stiffness_factor = 0.385 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index e5f180a510..74c881e2b6 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -86,6 +86,7 @@ class CAR: VELOSTER = "HYUNDAI VELOSTER 2019" SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021" IONIQ_5 = "HYUNDAI IONIQ 5 2022" + TUCSON_4TH_GEN = "HYUNDAI TUCSON 4TH GEN" TUCSON_HYBRID_4TH_GEN = "HYUNDAI TUCSON HYBRID 4TH GEN" SANTA_CRUZ_1ST_GEN = "HYUNDAI SANTA CRUZ 1ST GEN" @@ -157,11 +158,15 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e), CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a), CAR.IONIQ_5: [ - HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23" , "Highway Driving Assist", harness=Harness.hyundai_k), + HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", harness=Harness.hyundai_k), HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", harness=Harness.hyundai_q), ], + CAR.TUCSON_4TH_GEN: [ + HyundaiCarInfo("Hyundai Tucson 2022", harness=Harness.hyundai_n), + HyundaiCarInfo("Hyundai Tucson 2023", "All", harness=Harness.hyundai_n), + ], CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), - CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_n), + CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-22", harness=Harness.hyundai_n), # Kia CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), @@ -184,7 +189,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Optima Hybrid 2019"), ], CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", harness=Harness.hyundai_a), - CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", "Smart Cruise Control (SCC)", harness=Harness.hyundai_n), + CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", harness=Harness.hyundai_n), CAR.KIA_SORENTO: [ HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), @@ -1435,6 +1440,14 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', ], }, + CAR.TUCSON_4TH_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ', + ], + }, CAR.TUCSON_HYBRID_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9240 14Q', @@ -1496,7 +1509,7 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # The radar does SCC on these cars when HDA I, rather than the camera CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} @@ -1555,6 +1568,7 @@ DBC = { CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None), CAR.KIA_EV6: dbc_dict('hyundai_canfd', None), CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), + CAR.TUCSON_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.IONIQ_5: dbc_dict('hyundai_canfd', None), CAR.SANTA_CRUZ_1ST_GEN: dbc_dict('hyundai_canfd', None), diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index a20616de43..89b895864a 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -96,6 +96,7 @@ routes = [ CarTestRoute("5b7c365c50084530|2020-04-15--16-13-24", HYUNDAI.SONATA), CarTestRoute("b2a38c712dcf90bd|2020-05-18--18-12-48", HYUNDAI.SONATA_LF), CarTestRoute("fb3fd42f0baaa2f8|2022-03-30--15-25-05", HYUNDAI.TUCSON), + CarTestRoute("db68bbe12250812c|2022-12-05--00-54-12", HYUNDAI.TUCSON_4TH_GEN), # 2023 CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), CarTestRoute("628935d7d3e5f4f7|2022-11-30--01-12-46", HYUNDAI.KIA_SORENTO_PHEV_4TH_GEN), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index df696bc0fc..aeb2e6f280 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -35,6 +35,7 @@ HYUNDAI IONIQ ELECTRIC 2020: HYUNDAI IONIQ PLUG-IN HYBRID 2019 HYUNDAI ELANTRA 2017: HYUNDAI SONATA 2019 HYUNDAI ELANTRA HYBRID 2021: HYUNDAI SONATA 2020 HYUNDAI TUCSON 2019: HYUNDAI SANTA FE 2019 +HYUNDAI TUCSON 4TH GEN: HYUNDAI TUCSON HYBRID 4TH GEN HYUNDAI SANTA FE 2022: HYUNDAI SANTA FE HYBRID 2022 KIA STINGER 2022: KIA STINGER GT2 2018 GENESIS G90 2017: GENESIS G70 2018 From a311d936d094b294d22a9ee034380400ec532e91 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 5 Dec 2022 15:27:35 -0800 Subject: [PATCH 0448/1179] releases: fix car port sorting --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 44fc5e715e..211e63a755 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,9 +2,9 @@ Version 0.9.1 (2022-12-XX) ======================== * Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted -* Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Hyundai Tucson 2022-23 support +* Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! Version 0.9.0 (2022-11-21) ======================== From e598438a97b9ae6c4d5d921cd094efe1f40320b4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 6 Dec 2022 07:30:43 +0800 Subject: [PATCH 0449/1179] Cabana: show welcome widget if no msg selected (#26703) * show a blank widget if no msg selected * smaller font * rename to WelcomeWidget --- tools/cabana/detailwidget.cc | 37 ++++++++++++++++++++++++++++++++++-- tools/cabana/detailwidget.h | 7 +++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 5035bf49b4..cd1057f7e1 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -16,9 +16,9 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { undo_stack = new QUndoStack(this); - setMinimumWidth(500); - QVBoxLayout *main_layout = new QVBoxLayout(this); + QWidget *main_widget = new QWidget(this); + QVBoxLayout *main_layout = new QVBoxLayout(main_widget); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); @@ -90,6 +90,10 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget->addTab(history_log, "&Logs"); main_layout->addWidget(tab_widget); + stacked_layout = new QStackedLayout(this); + stacked_layout->addWidget(new WelcomeWidget(this)); + stacked_layout->addWidget(main_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); @@ -136,6 +140,7 @@ void DetailWidget::setMessage(const QString &message_id) { tabbar->setCurrentIndex(index); dbcMsgChanged(); scroll->verticalScrollBar()->setValue(0); + stacked_layout->setCurrentIndex(1); } void DetailWidget::dbcMsgChanged(int show_form_idx) { @@ -302,3 +307,31 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } + +// WelcomeWidget + +WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->addStretch(0); + QLabel *logo = new QLabel("CABANA"); + logo->setAlignment(Qt::AlignCenter); + logo->setStyleSheet("font-size:50px;font-weight:bold;"); + main_layout->addWidget(logo); + + auto newShortcutRow = [](const QString &title, const QString &key) { + QHBoxLayout *hlayout = new QHBoxLayout(); + auto btn = new QToolButton(); + btn->setText(key); + btn->setEnabled(false); + hlayout->addWidget(new QLabel(title), 0, Qt::AlignRight); + hlayout->addWidget(btn, 0, Qt::AlignLeft); + return hlayout; + }; + + main_layout->addLayout(newShortcutRow("Pause", "Space")); + main_layout->addLayout(newShortcutRow("Help", "Alt + H")); + main_layout->addStretch(0); + + setStyleSheet("QLabel{color:darkGray;}"); +} + diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 75409fa706..91127c9b74 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -18,6 +19,11 @@ public: QSpinBox *size_spin; }; +class WelcomeWidget : public QWidget { +public: + WelcomeWidget(QWidget *parent); +}; + class DetailWidget : public QWidget { Q_OBJECT @@ -51,5 +57,6 @@ private: BinaryView *binary_view; QScrollArea *scroll; ChartsWidget *charts; + QStackedLayout *stacked_layout; QList signal_list; }; From 9ea72b655035ee9f96c60c3268049bba6b8b9e1a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 5 Dec 2022 17:34:57 -0800 Subject: [PATCH 0450/1179] Longitudinal tests: clean up (#26708) * refactor test_cruise_speed.py * clean up long tests * and here --- selfdrive/controls/tests/test_cruise_speed.py | 8 +- .../controls/tests/test_following_distance.py | 9 +- .../test/longitudinal_maneuvers/maneuver.py | 4 +- .../test/longitudinal_maneuvers/plant.py | 7 +- .../test_longitudinal.py | 278 +++++++++--------- 5 files changed, 149 insertions(+), 157 deletions(-) diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index a635198ceb..cd1d31cf07 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -6,14 +6,13 @@ import unittest from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN, IMPERIAL_INCREMENT from cereal import car from common.conversions import Conversions as CV -from common.params import Params from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver ButtonEvent = car.CarState.ButtonEvent ButtonType = car.CarState.ButtonEvent.Type -def run_cruise_simulation(cruise, t_end=20.): +def run_cruise_simulation(cruise, e2e, t_end=20.): man = Maneuver( '', duration=t_end, @@ -23,6 +22,7 @@ def run_cruise_simulation(cruise, t_end=20.): cruise_values=[cruise], prob_lead_values=[0.0], breakpoints=[0.], + e2e=e2e, ) valid, output = man.evaluate() assert valid @@ -31,14 +31,12 @@ def run_cruise_simulation(cruise, t_end=20.): class TestCruiseSpeed(unittest.TestCase): def test_cruise_speed(self): - params = Params() for e2e in [False, True]: - params.put_bool("ExperimentalMode", e2e) for speed in np.arange(5, 40, 5): print(f'Testing {speed} m/s') cruise_speed = float(speed) - simulation_steady_state = run_cruise_simulation(cruise_speed) + simulation_steady_state = run_cruise_simulation(cruise_speed, e2e) self.assertAlmostEqual(simulation_steady_state, cruise_speed, delta=.01, msg=f'Did not reach {speed} m/s') diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py index 0535caab84..5185867d2d 100644 --- a/selfdrive/controls/tests/test_following_distance.py +++ b/selfdrive/controls/tests/test_following_distance.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 import unittest import numpy as np -from common.params import Params - from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import desired_follow_distance from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver + def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False): man = Maneuver( '', @@ -16,7 +15,7 @@ def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False): initial_distance_lead=100, speed_lead_values=[v_lead], breakpoints=[0.], - e2e=e2e + e2e=e2e, ) valid, output = man.evaluate() assert valid @@ -25,13 +24,11 @@ def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False): class TestFollowingDistance(unittest.TestCase): def test_following_distance(self): - params = Params() for e2e in [False, True]: - params.put_bool("ExperimentalMode", e2e) for speed in np.arange(0, 40, 5): print(f'Testing {speed} m/s') v_lead = float(speed) - simulation_steady_state = run_following_distance_simulation(v_lead) + simulation_steady_state = run_following_distance_simulation(v_lead, e2e=e2e) correct_steady_state = desired_follow_distance(v_lead, v_lead) err_ratio = 0.2 if e2e else 0.1 self.assertAlmostEqual(simulation_steady_state, correct_steady_state, delta=(err_ratio * correct_steady_state + .5)) diff --git a/selfdrive/test/longitudinal_maneuvers/maneuver.py b/selfdrive/test/longitudinal_maneuvers/maneuver.py index 071eaada12..65935f8979 100644 --- a/selfdrive/test/longitudinal_maneuvers/maneuver.py +++ b/selfdrive/test/longitudinal_maneuvers/maneuver.py @@ -2,7 +2,7 @@ import numpy as np from selfdrive.test.longitudinal_maneuvers.plant import Plant -class Maneuver(): +class Maneuver: def __init__(self, title, duration, **kwargs): # Was tempted to make a builder class self.distance_lead = kwargs.get("initial_distance_lead", 200.0) @@ -18,6 +18,7 @@ class Maneuver(): self.only_radar = kwargs.get("only_radar", False) self.ensure_start = kwargs.get("ensure_start", False) self.enabled = kwargs.get("enabled", True) + self.e2e = kwargs.get("e2e", False) self.duration = duration self.title = title @@ -30,6 +31,7 @@ class Maneuver(): enabled=self.enabled, only_lead2=self.only_lead2, only_radar=self.only_radar, + e2e=self.e2e, ) valid = True diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index 0d3336134f..8e150d800c 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -4,7 +4,6 @@ import numpy as np from cereal import log import cereal.messaging as messaging -from common.params import Params from common.realtime import Ratekeeper, DT_MDL from selfdrive.controls.lib.longcontrol import LongCtrlState from selfdrive.modeld.constants import T_IDXS @@ -16,9 +15,8 @@ class Plant: messaging_initialized = False def __init__(self, lead_relevancy=False, speed=0.0, distance_lead=2.0, - enabled=True, only_lead2=False, only_radar=False): + enabled=True, only_lead2=False, only_radar=False, e2e=False): self.rate = 1. / DT_MDL - self.params = Params() if not Plant.messaging_initialized: Plant.radar = messaging.pub_sock('radarState') @@ -40,6 +38,7 @@ class Plant: self.enabled = enabled self.only_lead2 = only_lead2 self.only_radar = only_radar + self.e2e = e2e self.rk = Ratekeeper(self.rate, print_delay_threshold=100.0) self.ts = 1. / self.rate @@ -111,7 +110,7 @@ class Plant: control.controlsState.longControlState = LongCtrlState.pid if self.enabled else LongCtrlState.off control.controlsState.vCruise = float(v_cruise * 3.6) - control.controlsState.experimentalMode = self.params.get_bool("ExperimentalMode") + control.controlsState.experimentalMode = self.e2e car_state.carState.vEgo = float(self.speed) car_state.carState.standstill = self.speed < 0.01 diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py index e859952445..686b35e456 100755 --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import os +from parameterized import parameterized import unittest from common.params import Params @@ -8,124 +9,137 @@ from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver # TODO: make new FCW tests -maneuvers = [ - Maneuver( - 'approach stopped car at 25m/s, initial distance: 120m', - duration=20., - initial_speed=25., - lead_relevancy=True, - initial_distance_lead=120., - speed_lead_values=[30., 0.], - breakpoints=[0., 1.], - ), - Maneuver( - 'approach stopped car at 20m/s, initial distance 90m', - duration=20., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=90., - speed_lead_values=[20., 0.], - breakpoints=[0., 1.], - ), - Maneuver( - 'steady state following a car at 20m/s, then lead decel to 0mph at 1m/s^2', - duration=50., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=35., - speed_lead_values=[20., 20., 0.], - breakpoints=[0., 15., 35.0], - ), - Maneuver( - 'steady state following a car at 20m/s, then lead decel to 0mph at 2m/s^2', - duration=50., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=35., - speed_lead_values=[20., 20., 0.], - breakpoints=[0., 15., 25.0], - ), - Maneuver( - 'steady state following a car at 20m/s, then lead decel to 0mph at 3m/s^2', - duration=50., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=35., - speed_lead_values=[20., 20., 0.], - breakpoints=[0., 15., 21.66], - ), - Maneuver( - 'steady state following a car at 20m/s, then lead decel to 0mph at 3+m/s^2', - duration=40., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=35., - speed_lead_values=[20., 20., 0.], - prob_lead_values=[0., 1., 1.], - cruise_values=[20., 20., 20.], - breakpoints=[2., 2.01, 8.8], - ), - Maneuver( - "approach stopped car at 20m/s, with prob_lead_values", - duration=30., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=120., - speed_lead_values=[0.0, 0., 0.], - prob_lead_values=[0.0, 0., 1.], - cruise_values=[20., 20., 20.], - breakpoints=[0.0, 2., 2.01], - ), - Maneuver( - "approach slower cut-in car at 20m/s", - duration=20., - initial_speed=20., - lead_relevancy=True, - initial_distance_lead=50., - speed_lead_values=[15., 15.], - breakpoints=[1., 11.], - only_lead2=True, - ), - Maneuver( - "stay stopped behind radar override lead", - duration=20., - initial_speed=0., - lead_relevancy=True, - initial_distance_lead=10., - speed_lead_values=[0., 0.], - prob_lead_values=[0., 0.], - breakpoints=[1., 11.], - only_radar=True, - ), - Maneuver( - "NaN recovery", - duration=30., - initial_speed=15., - lead_relevancy=True, - initial_distance_lead=60., - speed_lead_values=[0., 0., 0.0], - breakpoints=[1., 1.01, 11.], - cruise_values=[float("nan"), 15., 15.], - ), - # controls relies on planner commanding to move for stock-ACC resume spamming - Maneuver( - "resume from a stop", - duration=20., - initial_speed=0., - lead_relevancy=True, - initial_distance_lead=STOP_DISTANCE, - speed_lead_values=[0., 0., 2.], - breakpoints=[1., 10., 15.], - ensure_start=True, - ), - Maneuver( - 'cruising at 25 m/s while disabled', - duration=20., - initial_speed=25., - lead_relevancy=False, - enabled=False, - ), -] +def create_maneuvers(e2e): + return [ + Maneuver( + 'approach stopped car at 25m/s, initial distance: 120m', + duration=20., + initial_speed=25., + lead_relevancy=True, + initial_distance_lead=120., + speed_lead_values=[30., 0.], + breakpoints=[0., 1.], + e2e=e2e, + ), + Maneuver( + 'approach stopped car at 20m/s, initial distance 90m', + duration=20., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=90., + speed_lead_values=[20., 0.], + breakpoints=[0., 1.], + e2e=e2e, + ), + Maneuver( + 'steady state following a car at 20m/s, then lead decel to 0mph at 1m/s^2', + duration=50., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=35., + speed_lead_values=[20., 20., 0.], + breakpoints=[0., 15., 35.0], + e2e=e2e, + ), + Maneuver( + 'steady state following a car at 20m/s, then lead decel to 0mph at 2m/s^2', + duration=50., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=35., + speed_lead_values=[20., 20., 0.], + breakpoints=[0., 15., 25.0], + e2e=e2e, + ), + Maneuver( + 'steady state following a car at 20m/s, then lead decel to 0mph at 3m/s^2', + duration=50., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=35., + speed_lead_values=[20., 20., 0.], + breakpoints=[0., 15., 21.66], + e2e=e2e, + ), + Maneuver( + 'steady state following a car at 20m/s, then lead decel to 0mph at 3+m/s^2', + duration=40., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=35., + speed_lead_values=[20., 20., 0.], + prob_lead_values=[0., 1., 1.], + cruise_values=[20., 20., 20.], + breakpoints=[2., 2.01, 8.8], + e2e=e2e, + ), + Maneuver( + "approach stopped car at 20m/s, with prob_lead_values", + duration=30., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=120., + speed_lead_values=[0.0, 0., 0.], + prob_lead_values=[0.0, 0., 1.], + cruise_values=[20., 20., 20.], + breakpoints=[0.0, 2., 2.01], + e2e=e2e, + ), + Maneuver( + "approach slower cut-in car at 20m/s", + duration=20., + initial_speed=20., + lead_relevancy=True, + initial_distance_lead=50., + speed_lead_values=[15., 15.], + breakpoints=[1., 11.], + only_lead2=True, + e2e=e2e, + ), + Maneuver( + "stay stopped behind radar override lead", + duration=20., + initial_speed=0., + lead_relevancy=True, + initial_distance_lead=10., + speed_lead_values=[0., 0.], + prob_lead_values=[0., 0.], + breakpoints=[1., 11.], + only_radar=True, + e2e=e2e, + ), + Maneuver( + "NaN recovery", + duration=30., + initial_speed=15., + lead_relevancy=True, + initial_distance_lead=60., + speed_lead_values=[0., 0., 0.0], + breakpoints=[1., 1.01, 11.], + cruise_values=[float("nan"), 15., 15.], + e2e=e2e, + ), + # controls relies on planner commanding to move for stock-ACC resume spamming + Maneuver( + "resume from a stop", + duration=20., + initial_speed=0., + lead_relevancy=True, + initial_distance_lead=STOP_DISTANCE, + speed_lead_values=[0., 0., 2.], + breakpoints=[1., 10., 15.], + ensure_start=True, + e2e=e2e, + ), + Maneuver( + 'cruising at 25 m/s while disabled', + duration=20., + initial_speed=25., + lead_relevancy=False, + enabled=False, + e2e=e2e, + ), + ] class LongitudinalControl(unittest.TestCase): @@ -140,29 +154,11 @@ class LongitudinalControl(unittest.TestCase): params.put_bool("Passive", bool(os.getenv("PASSIVE"))) params.put_bool("OpenpilotEnabledToggle", True) - # hack - def test_longitudinal_setup(self): - pass - - -def run_maneuver_worker(k): - def run(self): - params = Params() - - man = maneuvers[k] - params.put_bool("ExperimentalMode", True) - print(man.title, ' in e2e mode') - valid, _ = man.evaluate() - self.assertTrue(valid, msg=man.title) - params.put_bool("ExperimentalMode", False) - print(man.title, ' in acc mode') - valid, _ = man.evaluate() - self.assertTrue(valid, msg=man.title) - return run - -for k in range(len(maneuvers)): - setattr(LongitudinalControl, f"test_longitudinal_maneuvers_{k+1}", - run_maneuver_worker(k)) + @parameterized.expand([(man,) for e2e in [True, False] for man in create_maneuvers(e2e)]) + def test_maneuver(self, maneuver): + print(maneuver.title, f'in {"e2e" if maneuver.e2e else "acc"} mode') + valid, _ = maneuver.evaluate() + self.assertTrue(valid, msg=maneuver.title) if __name__ == "__main__": From f36e8bc3c7316bd4aac38f8997b66d1649819fe9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 5 Dec 2022 17:35:19 -0800 Subject: [PATCH 0451/1179] Revert "Toyota: Don't Set Standstill Bit on TSS-P Prius" (#26709) Revert "Toyota: Don't Set Standstill Bit on TSS-P Prius (#26671)" This reverts commit 7b0bfabb95ecb39487d311ba6ccc6b4c4e11ff08. --- docs/CARS.md | 6 +++--- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 141e910fa5..4dccb30285 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -181,10 +181,10 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index c9e13e21a1..56bb2697c7 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -2056,4 +2056,4 @@ EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2 CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} # no resume button press required -NO_STOP_TIMER_CAR = TSS2_CAR | {CAR.PRIUS, CAR.PRIUS_V, CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_ESH} +NO_STOP_TIMER_CAR = TSS2_CAR | {CAR.PRIUS_V, CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_ESH} From 6e0893299ad435291782e40a92ddeb85b85f4b87 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 5 Dec 2022 17:41:32 -0800 Subject: [PATCH 0452/1179] navmodeld: only render necessary frames (#26698) --- selfdrive/modeld/navmodeld.cc | 1 - selfdrive/navd/map_renderer.cc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/modeld/navmodeld.cc b/selfdrive/modeld/navmodeld.cc index 57ef7cf0e0..75f2c62ab3 100644 --- a/selfdrive/modeld/navmodeld.cc +++ b/selfdrive/modeld/navmodeld.cc @@ -21,7 +21,6 @@ void run_model(NavModelState &model, VisionIpcClient &vipc_client) { while (!do_exit) { VisionBuf *buf = vipc_client.recv(&extra); if (buf == nullptr) continue; - if (extra.frame_id < last_frame_id + 10) continue; // Run at 2Hz double t1 = millis_since_boot(); NavModelResult *model_res = navmodel_eval_frame(&model, buf); diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 247b69c4c5..6a19f45fed 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -79,7 +79,7 @@ void MapRenderer::msgUpdate() { auto orientation = location.getCalibratedOrientationNED(); bool localizer_valid = (location.getStatus() == cereal::LiveLocationKalman::Status::VALID) && pos.getValid(); - if (localizer_valid) { + if (localizer_valid && (sm->rcv_frame("liveLocationKalman") % 10) == 0) { updatePosition(QMapbox::Coordinate(pos.getValue()[0], pos.getValue()[1]), RAD2DEG(orientation.getValue()[2])); } } From ddae8ffc09261fe932c24192fccc6d8bceb1d088 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Mon, 5 Dec 2022 19:25:57 -0800 Subject: [PATCH 0453/1179] add onnx2torch dependency (#26710) * add onnx2torch dependency * sort Co-authored-by: Cameron Clough --- poetry.lock | 31 ++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index fbe0009a26..39fb78cf2a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2439,6 +2439,20 @@ typing-extensions = ">=3.6.2.1" [package.extras] lint = ["clang-format (==13.0.0)", "flake8", "mypy (==0.782)", "types-protobuf (==3.18.4)"] +[[package]] +name = "onnx2torch" +version = "1.5.4" +description = "Nice Onnx to Pytorch converter" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = ">=1.16.4" +onnx = ">=1.9.0" +torch = ">=1.8.0" +torchvision = ">=0.9.0" + [[package]] name = "onnxoptimizer" version = "0.3.1" @@ -4400,7 +4414,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "a41b1d669ec4f0a94abe12af8a9a7d709b2bb56e9c83aa87801cdf5d9af074f8" +content-hash = "331a7b700c17c618a4f0fa7d0ec3e5b585c1dc467f6f03261c3778f729058f55" [metadata.files] adal = [ @@ -5406,6 +5420,7 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6401,6 +6416,9 @@ onnx = [ {file = "onnx-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:af90427ca04c6b7b8107c2021e1273227a3ef1a7a01f3073039cae7855a59833"}, {file = "onnx-1.12.0.tar.gz", hash = "sha256:13b3e77d27523b9dbf4f30dfc9c959455859d5e34e921c44f712d69b8369eff9"}, ] +onnx2torch = [ + {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, +] onnxoptimizer = [ {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, {file = "onnxoptimizer-0.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bf2bfe0dc43f0776867688e1759122dec049ff4f45f7221931b687fe7e139e"}, @@ -6576,6 +6594,11 @@ pillow-avif-plugin = [ {file = "pillow_avif_plugin-1.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017e5e52cb4320414e8ce3e2089eae2cb87c22c73ff6012b17ae326fc5753b20"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2a57136d4866de5dc80cfb24d66655955fbdd87acf1d11d88c8dc2ab41023e46"}, {file = "pillow_avif_plugin-1.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:f339511d0fccb69e3a5e3af39f8fe6700b0a07279015006ea56f8f49e7fecff4"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05e821ecd90bb0b8d2dc7610625372cc47de9cb893d09662528bad572f669d1c"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33886a5f9796fe9a8a3bc25ccfdeba7db119adb50b7004f1928a14b07d0213a"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75b7ed186c2f740dd26e556f6a966c59a170b70263e429a2c81920fe444da8a7"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11aef6b79078b8dad25c928e5871c146ab94424472851d5bf539ba62abde9ac"}, + {file = "pillow_avif_plugin-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:10696c536d68a14cefea3b98edb8d5a7ae29e8e07458f1d59c5d1cd780a8bf2a"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1a7291d6a5fb7336e72685a31d193e0b3a6bee9986c9ac4d8bd4b68dbe6d4f7f"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:14b9c5dbf237e7dc12f69819ea181a457b3bd4f59f8cd71d028d3635fd3bcab4"}, {file = "pillow_avif_plugin-1.2.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:799cbfbeee831332d280c80df9ce16b5c3b1224c318264e97e89df8da32e870e"}, @@ -6772,6 +6795,7 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -6779,12 +6803,14 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, + {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, @@ -6964,11 +6990,13 @@ pyprof2calltree = [ ] pyproj = [ {file = "pyproj-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f343725566267a296b09ee7e591894f1fdc90f84f8ad5ec476aeb53bd4479c07"}, + {file = "pyproj-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5816807ca0bdc7256558770c6206a6783a3f02bcf844f94ee245f197bb5f7285"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e609903572a56cca758bbaee5c1663c3e829ddce5eec4f368e68277e37022b"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fd425ee8b6781c249c7adb7daa2e6c41ce573afabe4f380f5eecd913b56a3be"}, {file = "pyproj-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954b068136518b3174d0a99448056e97af62b63392a95c420894f7de2229dae6"}, {file = "pyproj-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:4a23d84c5ffc383c7d9f0bde3a06fc1f6697b1b96725597f8f01e7b4bef0a2b5"}, {file = "pyproj-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f9c100fd0fd80edbc7e4daa303600a8cbef6f0de43d005617acb38276b88dc0"}, + {file = "pyproj-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa5171f700f174777a9e9ed8f4655583243967c0f9cf2c90e3f54e54ff740134"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a496d9057b2128db9d733e66b206f2d5954bbae6b800d412f562d780561478c"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52e54796e2d9554a5eb8f11df4748af1fbbc47f76aa234d6faf09216a84554c5"}, {file = "pyproj-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a454a7c4423faa2a14e939d08ef293ee347fa529c9df79022b0585a6e1d8310c"}, @@ -6979,6 +7007,7 @@ pyproj = [ {file = "pyproj-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f80adda8c54b84271a93829477a01aa57bc178c834362e9f74e1de1b5033c74c"}, {file = "pyproj-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:221d8939685e0c43ee594c9f04b6a73a10e8e1cc0e85f28be0b4eb2f1bc8777d"}, {file = "pyproj-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d94afed99f31673d3d19fe750283621e193e2a53ca9e0443bf9d092c3905833b"}, + {file = "pyproj-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fff9c3a991508f16027be27d153f6c5583d03799443639d13c681e60f49e2d7"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85acf09e5a9e35cd9ee72989793adb7089b4e611be02a43d3d0bda50ad116b"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45554f47d1a12a84b0620e4abc08a2a1b5d9f273a4759eaef75e74788ec7162a"}, {file = "pyproj-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12f62c20656ac9b6076ebb213e9a635d52f4f01fef95310121d337e62e910cb6"}, diff --git a/pyproject.toml b/pyproject.toml index c890b78875..d26fc7ff1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -147,6 +147,7 @@ mpld3 = "^0.5.8" msgpack-python = "^0.5.6" networkx = "~2.3" nvidia-ml-py3 = "^7.352.0" +onnx2torch = "^1.5.4" onnxoptimizer = "^0.3.1" opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" } osmium = "^3.3.0" From 2d5e2d992aba4b5bcbc3f1f9017a4e84c37a4080 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 6 Dec 2022 01:03:59 -0800 Subject: [PATCH 0454/1179] Kia Sorento: fix dash speed matching (#26582) * exception for Sorento * comment --- selfdrive/car/hyundai/carstate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index dfb33f2eb4..bd6b72f461 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -72,8 +72,10 @@ class CarState(CarStateBase): self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"] self.cluster_speed_counter = 0 - # mimic how dash converts to imperial - if not self.is_metric: + # Mimic how dash converts to imperial. + # Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric + # TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this + if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,): self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH) ret.vEgoCluster = self.cluster_speed * speed_conv From 5661738372d8bd3a7d453a7262ac56e7f182b331 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 6 Dec 2022 15:00:11 -0800 Subject: [PATCH 0455/1179] Car docs: move shop footnotes into openpilot (#26715) move shop footnotes into openpilot --- docs/CARS.md | 131 +++++++++++++++--------------- selfdrive/car/docs_definitions.py | 2 +- selfdrive/car/hyundai/values.py | 15 +++- 3 files changed, 80 insertions(+), 68 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 4dccb30285..2c897a371c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -11,12 +11,12 @@ A supported vehicle is one that just works when you install a comma three. All s |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| |Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| @@ -32,7 +32,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Genesis|GV70 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| |Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| @@ -61,8 +61,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Ioniq 5 (with HDA II) 2022-23|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| -|Hyundai|Ioniq 5 (without HDA II) 2022-23|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| +|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| +|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| @@ -74,7 +74,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I| |Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Santa Cruz 2021-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Hyundai|Santa Cruz 2021-22[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D| |Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| @@ -83,16 +83,16 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Sonata 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Hyundai|Tucson 2023|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Tucson Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Hyundai|Tucson Hybrid 2022[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Kia|EV6 (with HDA II) 2022|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| -|Kia|EV6 (without HDA II) 2022|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| +|Kia|EV6 (with HDA II) 2022[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| +|Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| |Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| @@ -107,9 +107,9 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Kia|Sorento Plug-in Hybrid 2022-23|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Kia|Sportage 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| +|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| +|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| @@ -137,8 +137,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| @@ -149,13 +149,13 @@ A supported vehicle is one that just works when you install a comma three. All s |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Škoda|Kamiq 2021[6](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| @@ -166,8 +166,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry 2018-20|All|Stock|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry 2021-22|All|openpilot|0 mph[5](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| +|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| @@ -196,48 +196,49 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat 2015-22[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[9](#footnotes)| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,8](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| +|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-5openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
-6Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
-7Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
-8Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC.
-9Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
+5Requires a red panda and additional harness box. Also requires a USB-A to USB-C adapter and USB-A to USB-A cable.
+6openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
+7Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
+8Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
+9Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC.
+10Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store.
## Community Maintained Cars Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 7cf44514d6..03e9e721b5 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -68,7 +68,7 @@ class Harness(Enum): none = "None" -CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only"], defaults=(None, False)) +CarFootnote = namedtuple("CarFootnote", ["text", "column", "docs_only", "shop_footnote"], defaults=(False, False)) class CommonFootnote(Enum): diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 74c881e2b6..0c5f80f7b4 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1,12 +1,12 @@ -from enum import IntFlag from dataclasses import dataclass +from enum import Enum, IntFlag from typing import Dict, List, Optional, Union from cereal import car from panda.python import uds from common.conversions import Conversions as CV from selfdrive.car import dbc_dict -from selfdrive.car.docs_definitions import CarInfo, Harness +from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu @@ -117,10 +117,21 @@ class CAR: GENESIS_G90 = "GENESIS G90 2017" +class Footnote(Enum): + CANFD = CarFootnote( + "Requires a red panda and additional harness box. " + + "Also requires a USB-A to USB-C adapter and USB-A to USB-A cable.", + Column.MODEL, shop_footnote=True) + + @dataclass class HyundaiCarInfo(CarInfo): package: str = "Smart Cruise Control (SCC)" + def init_make(self, CP: car.CarParams): + if CP.carFingerprint in CANFD_CAR: + self.footnotes.insert(0, Footnote.CANFD) + CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.ELANTRA: [ From 47977b2c0ed9f46d79e4a839ed8d83bace885504 Mon Sep 17 00:00:00 2001 From: alancyau <59986772+alancyau@users.noreply.github.com> Date: Tue, 6 Dec 2022 18:37:18 -0600 Subject: [PATCH 0456/1179] Mazda: Add support for 2023 CX9 in CARS.md (#26717) * Mazda: Add support for 2023 CX9 See https://github.com/commaai/openpilot/pull/26704 for the 2023 CX9 firmware. * update values Co-authored-by: Adeeb Shihadeh --- docs/CARS.md | 2 +- selfdrive/car/mazda/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 2c897a371c..9172377a4f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -131,7 +131,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| -|Mazda|CX-9 2021-22|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B| |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index 129273efee..b417e821c7 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -42,7 +42,7 @@ CAR_INFO: Dict[str, Union[MazdaCarInfo, List[MazdaCarInfo]]] = { CAR.CX9: MazdaCarInfo("Mazda CX-9 2016-20"), CAR.MAZDA3: MazdaCarInfo("Mazda 3 2017-18"), CAR.MAZDA6: MazdaCarInfo("Mazda 6 2017-20"), - CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-22", video_link="https://youtu.be/dA3duO4a0O4"), + CAR.CX9_2021: MazdaCarInfo("Mazda CX-9 2021-23", video_link="https://youtu.be/dA3duO4a0O4"), CAR.CX5_2022: MazdaCarInfo("Mazda CX-5 2022-23"), } From 57ad0c94586d12df54d5ab4a65d0e47945a35065 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 7 Dec 2022 13:17:37 +0800 Subject: [PATCH 0457/1179] Cabana: support multiple instances (#26286) * multiple instance * new file qtuitl.h * Revert "new file qtuitl.h" This reverts commit 19ef28945e8647724bbfc6c8469a664a58c09f16. --- tools/cabana/cabana.cc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index e7e3eb213b..3e76a3e029 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -1,5 +1,7 @@ #include +#include #include +#include #include "selfdrive/ui/qt/util.h" #include "tools/cabana/mainwin.h" @@ -20,12 +22,22 @@ int main(int argc, char *argv[]) { cmd_parser.showHelp(); } + QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); + QString msgq_path = "/dev/shm/" + uuid; + + QDir dir; + dir.mkdir(msgq_path); + setenv("OPENPILOT_PREFIX", qPrintable(uuid), 1); + + int ret = 0; const QString route = args.empty() ? DEMO_ROUTE : args.first(); CANMessages p(&app); - if (!p.loadRoute(route, cmd_parser.value("data_dir"), cmd_parser.isSet("qcam"))) { - return 0; + if (p.loadRoute(route, cmd_parser.value("data_dir"), cmd_parser.isSet("qcam"))) { + MainWindow w; + w.showMaximized(); + ret = app.exec(); } - MainWindow w; - w.showMaximized(); - return app.exec(); + + dir.rmdir(msgq_path); + return ret; } From cf3ced9d17b915632f1c3e820e1dee5218a9f5fb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 6 Dec 2022 23:32:58 -0800 Subject: [PATCH 0458/1179] Car docs: update CAN-FD footnote (#26718) * Update footnote * link to obd-c * update --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 9172377a4f..c92c0b2270 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -233,7 +233,7 @@ A supported vehicle is one that just works when you install a comma three. All s 2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-5Requires a red panda and additional harness box. Also requires a USB-A to USB-C adapter and USB-A to USB-A cable.
+5Requires a red panda, additional harness box, additional OBD-C cable, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle.
6openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
7Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
8Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 0c5f80f7b4..1e9d0f7f62 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -119,8 +119,8 @@ class CAR: class Footnote(Enum): CANFD = CarFootnote( - "Requires a red panda and additional harness box. " + - "Also requires a USB-A to USB-C adapter and USB-A to USB-A cable.", + "Requires a red panda, additional harness box, " + + "additional OBD-C cable, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle.", Column.MODEL, shop_footnote=True) From fa0bf404c879e41bc212e46df30f522b434ced44 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Wed, 7 Dec 2022 14:57:30 -0300 Subject: [PATCH 0459/1179] Update comment on sound.cc volume based(speed ->noise) (#26719) Update sound.cc --- selfdrive/ui/soundd/sound.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index f039511ff8..d07b6b6efd 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -46,7 +46,7 @@ void Sound::update() { return; } - // scale volume with speed + // scale volume using ambient noise level if (sm.updated("microphone")) { float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 52.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); From a7fb5da6e592cbc8750ae93b733da7d8b0f096aa Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 7 Dec 2022 12:04:33 -0800 Subject: [PATCH 0460/1179] Chrysler: fix LKAS fault for 2017 Pacifica (#26711) * gate on FW * fix * reverse docs * fix * Revert "fix" This reverts commit a0f2558fba0adc59c70eb92ffb8bd815bf033979. Revert "reverse docs" This reverts commit 9a46c517dfa7182f2f30501de801e35f7e1004c4. Revert "fix" This reverts commit 7b4d4bd3d2c2216890ea1877d52fdfbd9cec3ed7. Revert "gate on FW" This reverts commit 296826e71323e63f8e57b8988e573cef33149022. * use a flag * fix * draft * clean up * clean up * more clear * comment * remove --- selfdrive/car/chrysler/carcontroller.py | 4 ++-- selfdrive/car/chrysler/interface.py | 22 ++++++++++++++-------- selfdrive/car/chrysler/values.py | 5 +++++ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 5a2d90c64c..879da88123 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -2,7 +2,7 @@ from opendbc.can.packer import CANPacker from common.realtime import DT_CTRL from selfdrive.car import apply_toyota_steer_torque_limits from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_command, create_cruise_buttons -from selfdrive.car.chrysler.values import CAR, RAM_CARS, CarControllerParams +from selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags class CarController: @@ -51,7 +51,7 @@ class CarController: lkas_control_bit = self.lkas_control_bit_prev if CS.out.vEgo > self.CP.minSteerSpeed: lkas_control_bit = True - elif self.CP.carFingerprint in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019): + elif self.CP.flags & ChryslerFlags.HIGHER_MIN_STEERING_SPEED: if CS.out.vEgo < (self.CP.minSteerSpeed - 3.0): lkas_control_bit = False elif self.CP.carFingerprint in RAM_CARS: diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 5e8fe3c44e..2f058165ac 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from selfdrive.car import STD_CARGO_KG, get_safety_config -from selfdrive.car.chrysler.values import CAR, DBC, RAM_HD, RAM_DT +from selfdrive.car.chrysler.values import CAR, DBC, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags from selfdrive.car.interfaces import CarInterfaceBase @@ -24,9 +24,12 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_DT ret.minSteerSpeed = 3.8 # m/s - if candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019): - # TODO: allow 2019 cars to steer down to 13 m/s if already engaged. - ret.minSteerSpeed = 17.5 # m/s 17 on the way up, 13 on the way down once engaged. + if candidate not in RAM_CARS: + # Newer FW versions standard on the following platforms, or flashed by a dealer onto older platforms have a higher minimum steering speed. + new_eps_platform = candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019) + new_eps_firmware = any(fw.ecu == 'eps' and fw.fwVersion[:4] >= b"6841" for fw in car_fw) + if new_eps_platform or new_eps_firmware: + ret.flags |= ChryslerFlags.HIGHER_MIN_STEERING_SPEED.value # Chrysler if candidate in (CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018, CAR.PACIFICA_2018_HYBRID, CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020): @@ -55,10 +58,9 @@ class CarInterface(CarInterfaceBase): ret.mass = 2493. + STD_CARGO_KG CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) ret.minSteerSpeed = 14.5 - if car_fw is not None: - for fw in car_fw: - if fw.ecu == 'eps' and fw.fwVersion[:8] in (b"68312176", b"68273275"): - ret.minSteerSpeed = 0. + for fw in car_fw: + if fw.ecu == 'eps' and fw.fwVersion.startswith((b"68312176", b"68273275")): + ret.minSteerSpeed = 0. elif candidate == CAR.RAM_HD: ret.steerActuatorDelay = 0.2 @@ -71,6 +73,10 @@ class CarInterface(CarInterfaceBase): else: raise ValueError(f"Unsupported car: {candidate}") + if ret.flags & ChryslerFlags.HIGHER_MIN_STEERING_SPEED: + # TODO: allow these cars to steer down to 13 m/s if already engaged. + ret.minSteerSpeed = 17.5 # m/s 17 on the way up, 13 on the way down once engaged. + ret.centerToFront = ret.wheelbase * 0.44 ret.enableBsm = 720 in fingerprint[0] diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 16530ed989..02261a0b63 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -1,3 +1,4 @@ +from enum import IntFlag from dataclasses import dataclass from enum import Enum from typing import Dict, List, Optional, Union @@ -11,6 +12,10 @@ from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16 Ecu = car.CarParams.Ecu +class ChryslerFlags(IntFlag): + HIGHER_MIN_STEERING_SPEED = 1 + + class CAR: # Chrysler PACIFICA_2017_HYBRID = "CHRYSLER PACIFICA HYBRID 2017" From b3fae2d11351bf93b1e4a3aec7257dd95cc03f4e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 7 Dec 2022 15:22:02 -0800 Subject: [PATCH 0461/1179] Kona: adjust friction (#26720) adjust friction (* 1/0.7) --- selfdrive/car/torque_data/params.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index c081359937..3b212c6507 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -31,7 +31,7 @@ HYUNDAI IONIQ 5 2022: [3.172929, 3.0, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] HYUNDAI IONIQ PLUG-IN HYBRID 2019: [2.970807902012267, 1.6312321830002083, 0.1088964990357482] -HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 3.2961956260770484, 0.08651833437845884] +HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 3.2961956260770484, 0.12359762054065548] HYUNDAI PALISADE 2020: [2.544642494803999, 1.8721703683337008, 0.1301424599248651] HYUNDAI SANTA FE 2019: [3.0787027729757632, 2.6173437483495565, 0.1207019341823945] HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963] From 9c62513ffa5be7ee6a007ee4f6f421981039a046 Mon Sep 17 00:00:00 2001 From: alancyau <59986772+alancyau@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:50:14 -0600 Subject: [PATCH 0462/1179] Mazda: Add 2023 CX9 fw (#26704) * Mazda: Add 2023 CX9 fw DongleID: 629c4aced073d15a Discord User: bsk#7841 * Attempt to steer below 28mph for CX9 * undo comment Co-authored-by: Shane Smiskol --- selfdrive/car/mazda/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index b417e821c7..e6e9b3aee8 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -283,6 +283,7 @@ FW_VERSIONS = { b'TC3M-3210X-A-00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7e0, None): [ + b'PXGW-188K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PXM4-188K2-C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PXM4-188K2-D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'PXM6-188K2-E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', @@ -299,6 +300,7 @@ FW_VERSIONS = { b'GSH7-67XK2-N\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'GSH7-67XK2-P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'GSH7-67XK2-S\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'GSH7-67XK2-T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.transmission, 0x7e1, None): [ b'PXM4-21PS1-B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From 1da6f6a6e213280979dcf64b4d3e90f291bda4a3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 7 Dec 2022 19:36:30 -0800 Subject: [PATCH 0463/1179] nav model replay (#26697) * nav model replay * set token * fix gh actions * update refs * fix pc --- .github/workflows/selfdrive_tests.yaml | 2 +- Jenkinsfile | 2 + selfdrive/navd/map_renderer.cc | 16 +++-- selfdrive/navd/map_renderer.h | 1 - selfdrive/test/process_replay/compare_logs.py | 40 ++++++----- selfdrive/test/process_replay/model_replay.py | 70 +++++++++++++++++-- .../process_replay/model_replay_ref_commit | 2 +- 7 files changed, 103 insertions(+), 30 deletions(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index f2cc51285d..7cc45d23b9 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -294,7 +294,7 @@ jobs: - 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 && \ + ${{ env.RUN_CL }} "ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ coverage xml" - name: Run unit tests timeout-minutes: 5 diff --git a/Jenkinsfile b/Jenkinsfile index e8323bca7d..f1d7f1e289 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -11,6 +11,7 @@ export SOURCE_DIR=${env.SOURCE_DIR} export GIT_BRANCH=${env.GIT_BRANCH} export GIT_COMMIT=${env.GIT_COMMIT} export AZURE_TOKEN='${env.AZURE_TOKEN}' +export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}' source ~/.bash_profile if [ -f /TICI ]; then @@ -47,6 +48,7 @@ pipeline { TEST_DIR = "/data/openpilot" SOURCE_DIR = "/data/openpilot_source/" AZURE_TOKEN = credentials('azure_token') + MAPBOX_TOKEN = credentials('mapbox_token') } options { timeout(time: 4, unit: 'HOURS') diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 6a19f45fed..a9c34b5bd5 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -4,10 +4,10 @@ #include #include #include -#include #include "common/util.h" #include "common/timing.h" +#include "common/swaglog.h" #include "selfdrive/ui/qt/maps/map_helpers.h" const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear @@ -56,22 +56,27 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set m_map->setFramebufferObject(fbo->handle(), fbo->size()); gl_functions->glViewport(0, 0, WIDTH, HEIGHT); + QObject::connect(m_map.data(), &QMapboxGL::mapLoadingFailed, [=](QMapboxGL::MapLoadingFailure err_code, const QString &reason) { + LOGE("Map loading failed with %d: '%s'\n", err_code, reason.toStdString().c_str()); + }); + if (online) { vipc_server.reset(new VisionIpcServer("navd")); vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH, HEIGHT); vipc_server->start_listener(); pm.reset(new PubMaster({"navThumbnail"})); - sm.reset(new SubMaster({"liveLocationKalman", "navRoute"})); + sm.reset(new SubMaster({"liveLocationKalman", "navRoute"}, {"liveLocationKalman"})); timer = new QTimer(this); + timer->setSingleShot(true); QObject::connect(timer, SIGNAL(timeout()), this, SLOT(msgUpdate())); - timer->start(50); + timer->start(0); } } void MapRenderer::msgUpdate() { - sm->update(0); + sm->update(1000); if (sm->updated("liveLocationKalman")) { auto location = (*sm)["liveLocationKalman"].getLiveLocationKalman(); @@ -92,6 +97,9 @@ void MapRenderer::msgUpdate() { } updateRoute(route); } + + // schedule next update + timer->start(0); } void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) { diff --git a/selfdrive/navd/map_renderer.h b/selfdrive/navd/map_renderer.h index 855dc91894..7f725c93fe 100644 --- a/selfdrive/navd/map_renderer.h +++ b/selfdrive/navd/map_renderer.h @@ -25,7 +25,6 @@ public: bool loaded(); ~MapRenderer(); - private: std::unique_ptr ctx; std::unique_ptr surface; diff --git a/selfdrive/test/process_replay/compare_logs.py b/selfdrive/test/process_replay/compare_logs.py index c14956b1b2..e5e21a6fef 100755 --- a/selfdrive/test/process_replay/compare_logs.py +++ b/selfdrive/test/process_replay/compare_logs.py @@ -2,6 +2,7 @@ import bz2 import sys import math +import capnp import numbers import dictdiffer from collections import Counter @@ -30,20 +31,23 @@ def remove_ignored_fields(msg, ignore): continue for k in keys[:-1]: - try: - attr = getattr(msg, k) - except AttributeError: - break - else: - v = getattr(attr, keys[-1]) - if isinstance(v, bool): - val = False - elif isinstance(v, numbers.Number): - val = 0 + # indexing into list + if k.isdigit(): + attr = attr[int(k)] else: - raise NotImplementedError('Error ignoring field') - setattr(attr, keys[-1], val) - return msg.as_reader() + attr = getattr(attr, k) + + v = getattr(attr, keys[-1]) + if isinstance(v, bool): + val = False + elif isinstance(v, numbers.Number): + val = 0 + elif isinstance(v, (list, capnp.lib.capnp._DynamicListBuilder)): + val = [] + else: + raise NotImplementedError(f"Unknown type: {type(v)}") + setattr(attr, keys[-1], val) + return msg def get_field_tolerance(diff_field, field_tolerances): @@ -79,12 +83,12 @@ def compare_logs(log1, log2, ignore_fields=None, ignore_msgs=None, tolerance=Non print(msg1, msg2) raise Exception("msgs not aligned between logs") - msg1_bytes = remove_ignored_fields(msg1, ignore_fields).as_builder().to_bytes() - msg2_bytes = remove_ignored_fields(msg2, ignore_fields).as_builder().to_bytes() + msg1 = remove_ignored_fields(msg1, ignore_fields) + msg2 = remove_ignored_fields(msg2, ignore_fields) - if msg1_bytes != msg2_bytes: - msg1_dict = msg1.to_dict(verbose=True) - msg2_dict = msg2.to_dict(verbose=True) + if msg1.to_bytes() != msg2.to_bytes(): + msg1_dict = msg1.as_reader().to_dict(verbose=True) + msg2_dict = msg2.as_reader().to_dict(verbose=True) dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore_fields) diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index a63ec6489b..1f43bb791a 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -20,14 +20,17 @@ from system.version import get_commit from tools.lib.framereader import FrameReader from tools.lib.logreader import LogReader -TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36" -SEGMENT = 0 +TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30" +SEGMENT = 6 MAX_FRAMES = 100 if PC else 600 +NAV_FRAMES = 20 +NO_NAV = "NO_NAV" in os.environ # TODO: make map renderer work in CI SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0")) VIPC_STREAM = {"roadCameraState": VisionStreamType.VISION_STREAM_ROAD, "driverCameraState": VisionStreamType.VISION_STREAM_DRIVER, "wideRoadCameraState": VisionStreamType.VISION_STREAM_WIDE_ROAD} + def get_log_fn(ref_commit, test_route): return f"{test_route}_model_tici_{ref_commit}.bz2" @@ -39,6 +42,47 @@ def replace_calib(msg, calib): return msg +def nav_model_replay(lr): + pm = messaging.PubMaster(['liveLocationKalman', 'navRoute']) + sock = messaging.sub_sock('navModel', conflate=False, timeout=1000) + + log_msgs = [] + try: + managed_processes['mapsd'].start() + managed_processes['navmodeld'].start() + + # setup position and route + nav = [m for m in lr if m.which() == 'navRoute'] + llk = [m for m in lr if m.which() == 'liveLocationKalman'] + assert len(nav) > 0 and len(llk) > 0 + + for _ in range(30): + for s in (llk, nav): + msg = s[0] + pm.send(msg.which(), msg.as_builder().to_bytes()) + if messaging.recv_one(sock) is not None: + break + else: + raise Exception("no navmodeld outputs") + + time.sleep(2) + messaging.drain_sock_raw(sock) + + # run replay + for _ in range(NAV_FRAMES): + # 2Hz decimation + for _ in range(10): + pm.send(llk[0].which(), llk[0].as_builder().to_bytes()) + time.sleep(0.1) + with Timeout(5, "timed out waiting for nav model outputs"): + log_msgs.append(messaging.recv_one_retry(sock)) + finally: + managed_processes['mapsd'].stop() + managed_processes['navmodeld'].stop() + + return log_msgs + + def model_replay(lr, frs): if not PC: spinner = Spinner() @@ -154,8 +198,10 @@ if __name__ == "__main__": 'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True) } - # run replay + # run replays log_msgs = model_replay(lr, frs) + if not NO_NAV: + log_msgs += nav_model_replay(lr) # get diff failed = False @@ -164,15 +210,29 @@ if __name__ == "__main__": ref_commit = f.read().strip() log_fn = get_log_fn(ref_commit, TEST_ROUTE) try: - cmp_log = list(LogReader(BASE_URL + log_fn))[:2*MAX_FRAMES] + expected_msgs = 2*MAX_FRAMES + if not NO_NAV: + expected_msgs += NAV_FRAMES + cmp_log = list(LogReader(BASE_URL + log_fn))[:expected_msgs] ignore = [ 'logMonoTime', 'modelV2.frameDropPerc', 'modelV2.modelExecutionTime', 'driverStateV2.modelExecutionTime', - 'driverStateV2.dspExecutionTime' + 'driverStateV2.dspExecutionTime', + 'navModel.dspExecutionTime', + 'navModel.modelExecutionTime', ] + if PC: + ignore += [ + 'modelV2.laneLines.0.t', + 'modelV2.laneLines.1.t', + 'modelV2.laneLines.2.t', + 'modelV2.laneLines.3.t', + 'modelV2.roadEdges.0.t', + 'modelV2.roadEdges.1.t', + ] # TODO this tolerance is absurdly large tolerance = 2.0 if PC else None results: Any = {TEST_ROUTE: {}} diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index f541b6a6d5..b58cca1aaf 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -30efb4238327d723e17a3bda7e7c19c18f8a3b18 +4b2c6516cd460ee443b9006f01233168edf3d170 \ No newline at end of file From d64a5020b20cf32f2a9ce3a3ba2dd8547751ebc5 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 7 Dec 2022 22:15:58 -0800 Subject: [PATCH 0464/1179] soundd: tune volume to reach max at slightly higher noise level --- selfdrive/ui/soundd/sound.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index d07b6b6efd..42fc9c4b1a 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -48,7 +48,7 @@ void Sound::update() { // scale volume using ambient noise level if (sm.updated("microphone")) { - float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 52.f, 0.f, 1.f); + float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 54.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); Hardware::set_volume(volume); } From 53023abd24f9aacea11da4dff07183f16557c9b4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 7 Dec 2022 22:21:05 -0800 Subject: [PATCH 0465/1179] jenkins: don't clog up build queue (#26724) * jenkins: don't clog up build queue * not real --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f1d7f1e289..37621dde5c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -51,7 +51,8 @@ pipeline { MAPBOX_TOKEN = credentials('mapbox_token') } options { - timeout(time: 4, unit: 'HOURS') + timeout(time: 3, unit: 'HOURS') + disableConcurrentBuilds(abortPrevious: env.BRANCH_NAME != 'master') } stages { From d97336d5326190559d1ff0518daee273f270aaf8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 8 Dec 2022 03:01:57 -0800 Subject: [PATCH 0466/1179] LatControl: remove duplicate logic for saturation (#26725) this is already checked --- selfdrive/controls/controlsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 342ecc52fe..3840d6e0de 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -625,7 +625,7 @@ class Controls: max_torque = abs(self.last_actuators.steer) > 0.99 if undershooting and turning and good_speed and max_torque: self.events.add(EventName.steerSaturated) - elif lac_log.active and not CS.steeringPressed and lac_log.saturated: + elif lac_log.active and lac_log.saturated: dpath_points = lat_plan.dPathPoints if len(dpath_points): # Check if we deviated from the path From 1c5c0e723cd3adc32c1cf398228d79601d2f25a2 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Dec 2022 03:06:38 +0800 Subject: [PATCH 0467/1179] CameraView: remove double semicolon (#26728) remove double semicolon --- selfdrive/ui/qt/widgets/cameraview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 347cdb1dca..16aad13437 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -359,7 +359,7 @@ void CameraWidget::vipcThread() { if (!vipc_client || cur_stream != requested_stream_type) { clearFrames(); qDebug() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; - cur_stream = requested_stream_type;; + cur_stream = requested_stream_type; vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); } active_stream_type = cur_stream; From cf67ae6ac13944fd0236ac7ffa3151b8c2617229 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Dec 2022 03:18:52 +0800 Subject: [PATCH 0468/1179] Cabana: fix build error on mac (#26730) fix build error on mac --- tools/cabana/dbcmanager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index e7d3ead9c6..1b33c4cc42 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -111,7 +111,7 @@ DBCManager *dbc() { std::vector DBCMsg::getSignals() const { std::vector ret; - for (auto &[name, sig] : sigs) ret.push_back(&sig); + for (auto &[_, 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; } From 7006230e0885d3da26c034517660f566c8dd37e9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Dec 2022 03:19:57 +0800 Subject: [PATCH 0469/1179] Cabana: add `--ecam` flag to dispaly the wide road camera (#26727) --- tools/cabana/cabana | 2 +- tools/cabana/cabana.cc | 12 ++++++++++-- tools/cabana/canmessages.cc | 4 ++-- tools/cabana/canmessages.h | 3 ++- tools/cabana/videowidget.cc | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tools/cabana/cabana b/tools/cabana/cabana index b29dd66e3d..14647b6a10 100755 --- a/tools/cabana/cabana +++ b/tools/cabana/cabana @@ -1,4 +1,4 @@ #!/bin/sh cd "$(dirname "$0")" export LD_LIBRARY_PATH="../../opendbc/can:$LD_LIBRARY_PATH" -exec ./_cabana "$1" +exec ./_cabana "$@" diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 3e76a3e029..5e9b255731 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -15,6 +15,7 @@ int main(int argc, char *argv[]) { 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({"ecam", "load wide road camera"}); cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"}); cmd_parser.process(app); const QStringList args = cmd_parser.positionalArguments(); @@ -29,10 +30,17 @@ int main(int argc, char *argv[]) { dir.mkdir(msgq_path); setenv("OPENPILOT_PREFIX", qPrintable(uuid), 1); - int ret = 0; const QString route = args.empty() ? DEMO_ROUTE : args.first(); + uint32_t replay_flags = REPLAY_FLAG_NONE; + if (cmd_parser.isSet("ecam")) { + replay_flags |= REPLAY_FLAG_ECAM; + } else if (cmd_parser.isSet("qcam")) { + replay_flags |= REPLAY_FLAG_QCAMERA; + } + CANMessages p(&app); - if (p.loadRoute(route, cmd_parser.value("data_dir"), cmd_parser.isSet("qcam"))) { + int ret = 0; + if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { MainWindow w; w.showMaximized(); ret = app.exec(); diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index a8e881c5fe..9959ba7313 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -21,8 +21,8 @@ static bool event_filter(const Event *e, void *opaque) { return c->eventFilter(e); } -bool CANMessages::loadRoute(const QString &route, const QString &data_dir, bool use_qcam) { - replay = new Replay(route, {"can", "roadEncodeIdx", "carParams"}, {}, nullptr, use_qcam ? REPLAY_FLAG_QCAMERA : 0, data_dir, this); +bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { + replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); replay->setSegmentCacheLimit(settings.cached_segment_limit); replay->installEventFilter(event_filter, this); QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 1713778af7..f9103aa96b 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -26,13 +26,14 @@ public: enum FindFlags{ EQ, LT, GT }; CANMessages(QObject *parent); ~CANMessages(); - bool loadRoute(const QString &route, const QString &data_dir, bool use_qcam); + bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); void seekTo(double ts); QList findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); bool eventFilter(const Event *event); inline QString routeName() const { return replay->route()->name(); } inline QString carFingerprint() const { return replay->carFingerprint().c_str(); } + inline VisionStreamType visionStreamType() const { return replay->hasFlag(REPLAY_FLAG_ECAM) ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD; } inline double totalSeconds() const { return replay->totalSeconds(); } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } inline double currentSec() const { return replay->currentSeconds(); } diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 3e64d907ec..6cd173b514 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -21,7 +21,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); - cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false, this); + cam_widget = new CameraWidget("camerad", can->visionStreamType(), false, this); cam_widget->setFixedSize(parent->width(), parent->width() / 1.596); main_layout->addWidget(cam_widget); From 6bea668e35408361fd8efa5bec641d2fe7cf94e8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 9 Dec 2022 03:54:22 +0800 Subject: [PATCH 0470/1179] Cabana: fix the binaryview is not updated correctly (#26731) --- tools/cabana/binaryview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index bc64edbfeb..aa256b4ce1 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -202,7 +202,7 @@ void BinaryViewModel::updateState() { } } - for (int i = 0; i < row_count; ++i) { + for (int i = 0; i < row_count * column_count; ++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); From 41667d020ac8eb8d518e9437de32d8d9d09b6b15 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 8 Dec 2022 16:26:41 -0800 Subject: [PATCH 0471/1179] Car controls: common angle limiting function (#26732) * common angle limiting function * save a line --- selfdrive/car/__init__.py | 13 ++++++++++++- selfdrive/car/nissan/carcontroller.py | 15 ++++----------- selfdrive/car/nissan/values.py | 7 +++---- selfdrive/car/tesla/carcontroller.py | 14 +++++--------- selfdrive/car/tesla/values.py | 7 +++---- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index 491c551b1b..c056f7ca3d 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -1,8 +1,9 @@ # functions common among cars import capnp +from collections import namedtuple from cereal import car -from common.numpy_fast import clip +from common.numpy_fast import clip, interp from typing import Dict # kg of standard extra cargo to count for drive, gas, etc... @@ -10,6 +11,7 @@ STD_CARGO_KG = 136. ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName +AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v']) def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float: @@ -111,6 +113,15 @@ def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torq return int(round(float(apply_torque))) +def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS): + # pick angle rate limits based on wind up/down + steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last) + rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN + + angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v) + return clip(apply_angle, apply_angle_last - angle_rate_lim, apply_angle_last + angle_rate_lim) + + def crc8_pedal(data): crc = 0xFF # standard init value poly = 0xD5 # standard crc8: x8+x7+x6+x4+x2+1 diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index dbc2b33c6b..ff13812398 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -1,6 +1,6 @@ from cereal import car -from common.numpy_fast import clip, interp from opendbc.can.packer import CANPacker +from selfdrive.car import apply_std_steer_angle_limits from selfdrive.car.nissan import nissancan from selfdrive.car.nissan.values import CAR, CarControllerParams @@ -14,7 +14,7 @@ class CarController: self.frame = 0 self.lkas_max_torque = 0 - self.last_angle = 0 + self.apply_angle_last = 0 self.packer = CANPacker(dbc_name) @@ -28,18 +28,11 @@ class CarController: ### STEER ### lkas_hud_msg = CS.lkas_hud_msg lkas_hud_info_msg = CS.lkas_hud_info_msg - apply_angle = actuators.steeringAngleDeg - steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0 if CC.latActive: # windup slower - if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle): - angle_rate_lim = interp(CS.out.vEgo, CarControllerParams.ANGLE_DELTA_BP, CarControllerParams.ANGLE_DELTA_V) - else: - angle_rate_lim = interp(CS.out.vEgo, CarControllerParams.ANGLE_DELTA_BP, CarControllerParams.ANGLE_DELTA_VU) - - apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim, self.last_angle + angle_rate_lim) + apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo, CarControllerParams) # Max torque from driver before EPS will give up and not apply torque if not bool(CS.out.steeringPressed): @@ -57,7 +50,7 @@ class CarController: apply_angle = CS.out.steeringAngleDeg self.lkas_max_torque = 0 - self.last_angle = apply_angle + self.apply_angle_last = apply_angle if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and pcm_cancel_cmd: can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg)) diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 09bd7ca838..a6ee27a4a3 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -4,7 +4,7 @@ from enum import Enum from cereal import car from panda.python import uds -from selfdrive.car import dbc_dict +from selfdrive.car import AngleRateLimit, dbc_dict from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries @@ -12,9 +12,8 @@ Ecu = car.CarParams.Ecu class CarControllerParams: - ANGLE_DELTA_BP = [0., 5., 15.] - ANGLE_DELTA_V = [5., .8, .15] # windup limit - ANGLE_DELTA_VU = [5., 3.5, 0.4] # unwind limit + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., .8, .15]) + ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., 3.5, 0.4]) LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower STEER_THRESHOLD = 1.0 diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py index cf43b8ef00..6e2869d1c2 100644 --- a/selfdrive/car/tesla/carcontroller.py +++ b/selfdrive/car/tesla/carcontroller.py @@ -1,5 +1,6 @@ -from common.numpy_fast import clip, interp +from common.numpy_fast import clip from opendbc.can.packer import CANPacker +from selfdrive.car import apply_std_steer_angle_limits from selfdrive.car.tesla.teslacan import TeslaCAN from selfdrive.car.tesla.values import DBC, CANBUS, CarControllerParams @@ -8,7 +9,7 @@ class CarController: def __init__(self, dbc_name, CP, VM): self.CP = CP self.frame = 0 - self.last_angle = 0 + self.apply_angle_last = 0 self.packer = CANPacker(dbc_name) self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt']) self.tesla_can = TeslaCAN(self.packer, self.pt_packer) @@ -24,20 +25,15 @@ class CarController: lkas_enabled = CC.latActive and not hands_on_fault if lkas_enabled: - apply_angle = actuators.steeringAngleDeg - # Angular rate limit based on speed - steer_up = self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle) - rate_limit = CarControllerParams.RATE_LIMIT_UP if steer_up else CarControllerParams.RATE_LIMIT_DOWN - max_angle_diff = interp(CS.out.vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points) - apply_angle = clip(apply_angle, self.last_angle - max_angle_diff, self.last_angle + max_angle_diff) + apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo, CarControllerParams) # To not fault the EPS apply_angle = clip(apply_angle, CS.out.steeringAngleDeg - 20, CS.out.steeringAngleDeg + 20) else: apply_angle = CS.out.steeringAngleDeg - self.last_angle = apply_angle + self.apply_angle_last = apply_angle can_sends.append(self.tesla_can.create_steering_control(apply_angle, lkas_enabled, self.frame)) # Longitudinal control (in sync with stock message, about 40Hz) diff --git a/selfdrive/car/tesla/values.py b/selfdrive/car/tesla/values.py index 750fe885e8..52f2aedf98 100644 --- a/selfdrive/car/tesla/values.py +++ b/selfdrive/car/tesla/values.py @@ -2,14 +2,13 @@ from collections import namedtuple from typing import Dict, List, Union from cereal import car -from selfdrive.car import dbc_dict +from selfdrive.car import AngleRateLimit, dbc_dict from selfdrive.car.docs_definitions import CarInfo from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) -AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_points']) class CAR: @@ -104,8 +103,8 @@ BUTTONS = [ ] class CarControllerParams: - RATE_LIMIT_UP = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., .8, .15]) - RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., .8, .15]) + ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., 3.5, 0.4]) JERK_LIMIT_MAX = 8 JERK_LIMIT_MIN = -8 ACCEL_TO_SPEED_MULTIPLIER = 3 From e6182cb9aac7f7c9214e09db7af53c6128d54d08 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 8 Dec 2022 20:15:37 -0800 Subject: [PATCH 0472/1179] fix dependencies for macOS (#26684) * misc changes * sort and remove duplicates * only linux * upgrade to pip 22.3.1 --- poetry.lock | 6 +----- pyproject.toml | 14 +++++--------- update_requirements.sh | 2 +- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index 39fb78cf2a..6360f6f3ab 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4414,7 +4414,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "331a7b700c17c618a4f0fa7d0ec3e5b585c1dc467f6f03261c3778f729058f55" +content-hash = "82e450801a9a1de9fd98615d7deb3d8f0aa5bd3ccf0cf8b258cd8f6e6e4c5309" [metadata.files] adal = [ @@ -5420,7 +5420,6 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, - {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6795,7 +6794,6 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, - {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -6803,14 +6801,12 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, - {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, - {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, diff --git a/pyproject.toml b/pyproject.toml index d26fc7ff1d..a20868d877 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ documentation = "https://docs.comma.ai" [tool.poetry.dependencies] python = "~3.8" atomicwrites = "^1.4.0" -casadi = { version = "==3.5.5", markers = "platform_system != 'Darwin'" } +casadi = { version = "==3.5.5", platform = "linux" } cffi = "^1.15.1" crcmod = "^1.7" cryptography = "^37.0.4" @@ -29,7 +29,7 @@ libusb1 = "^3.0.0" nose = "^1.3.7" numpy = "^1.23.0" onnx = "^1.12.0" -onnxruntime-gpu = { version = "^1.11.1", markers = "platform_system != 'Darwin'" } +onnxruntime-gpu = { version = "^1.11.1", platform = "linux" } pillow = "^9.2.0" poetry = "==1.2.2" protobuf = "==3.20.1" @@ -50,20 +50,20 @@ setproctitle = "^1.2.3" six = "^1.16.0" smbus2 = "^0.4.2" sounddevice = "^0.4.5" +spidev = { version = "^3.6", platform = "linux" } sympy = "^1.10.1" timezonefinder = "^6.0.1" tqdm = "^4.64.0" urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" -spidev = "^3.6" [tool.poetry.group.dev.dependencies] av = "^9.2.0" azure-storage-blob = "~2.1" breathe = "^4.34.0" -carla = "==0.9.13" +carla = { version = "==0.9.13", platform = "linux" } control = "^0.9.2" coverage = "^6.4.1" dictdiffer = "^0.9.0" @@ -81,7 +81,7 @@ mypy = "^0.961" myst-parser = "^0.18.0" natsort = "^8.1.0" numpy = "^1.23.0" -opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" } +opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl", platform = "linux" } pandas = "^1.4.3" parameterized = "^0.8.1" paramiko = "^2.11.0" @@ -119,7 +119,6 @@ azure-cli-core = "^2.38.0" azure-common = "^1.1.28" azure-core = "^1.24.2" azure-nspkg = "~3.0" -azure-storage-blob = "~2.1" azure-storage-common = "~2.1" azure-storage-nspkg = "~3.1" blosc = "==1.9.2" @@ -143,15 +142,12 @@ jupyter = "^1.0.0" jupyterlab = "^3.4.4" jupyterlab-vim = "^0.15.1" Markdown = "^3.4.1" -mpld3 = "^0.5.8" msgpack-python = "^0.5.6" networkx = "~2.3" nvidia-ml-py3 = "^7.352.0" onnx2torch = "^1.5.4" onnxoptimizer = "^0.3.1" -opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" } osmium = "^3.3.0" -pandas = "^1.4.3" pillow-avif-plugin = "^1.2.2" pipenv = "==2022.10.12" plotly = "^5.9.0" diff --git a/update_requirements.sh b/update_requirements.sh index 9195799ca3..e5dedea7a6 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -45,7 +45,7 @@ fi eval "$(pyenv init --path)" echo "update pip" -pip install pip==22.3 +pip install pip==22.3.1 pip install poetry==1.2.2 poetry config virtualenvs.prefer-active-python true --local From 08b7fa7c4432a5c59e7e733113ebbdcd84f6c152 Mon Sep 17 00:00:00 2001 From: Bin Zhu Date: Thu, 8 Dec 2022 22:33:48 -0600 Subject: [PATCH 0473/1179] Added old firmware version to support Lexus NX 2020 (#26679) Added old firmware version for Lexus NX 2020 --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 56bb2697c7..cda153e89f 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1659,6 +1659,7 @@ FW_VERSIONS = { b'\x018966378B2100\x00\x00\x00\x00', b'\x018966378B3000\x00\x00\x00\x00', b'\x018966378G3000\x00\x00\x00\x00', + b'\x018966378B2000\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'\x01F152678221\x00\x00\x00\x00\x00\x00', From c3b3c102323c6f00812a765702e96f9f47e1f4e7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 8 Dec 2022 20:57:11 -0800 Subject: [PATCH 0474/1179] nav: add mapRenderState (#26734) * nav: add mapRenderState * bump cereal * bump again --- cereal | 2 +- selfdrive/navd/map_renderer.cc | 17 +++++++++++++---- selfdrive/navd/map_renderer.h | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cereal b/cereal index 7765176413..8825337204 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7765176413c0bb14143fe2469d5390ea0ea61a1e +Subproject commit 88253372042197ac92776cddc35a29d0eb384a3e diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index a9c34b5bd5..904768d101 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -65,7 +65,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH, HEIGHT); vipc_server->start_listener(); - pm.reset(new PubMaster({"navThumbnail"})); + pm.reset(new PubMaster({"navThumbnail", "mapRenderState"})); sm.reset(new SubMaster({"liveLocationKalman", "navRoute"}, {"liveLocationKalman"})); timer = new QTimer(this); @@ -122,14 +122,16 @@ bool MapRenderer::loaded() { } void MapRenderer::update() { + double start_t = millis_since_boot(); gl_functions->glClear(GL_COLOR_BUFFER_BIT); m_map->render(); gl_functions->glFlush(); + double end_t = millis_since_boot(); - sendVipc(); + publish((end_t - start_t) / 1000.0); } -void MapRenderer::sendVipc() { +void MapRenderer::publish(const double render_time) { if (!vipc_server || !loaded()) { return; } @@ -139,7 +141,7 @@ void MapRenderer::sendVipc() { VisionBuf* buf = vipc_server->get_buffer(VisionStreamType::VISION_STREAM_MAP); VisionIpcBufExtra extra = { .frame_id = frame_id, - .timestamp_sof = ts, + .timestamp_sof = sm->rcv_time("liveLocationKalman"), .timestamp_eof = ts, }; @@ -173,6 +175,13 @@ void MapRenderer::sendVipc() { pm->send("navThumbnail", msg); } + // Send state msg + MessageBuilder msg; + auto state = msg.initEvent().initMapRenderState(); + state.setLocationMonoTime(sm->rcv_time("liveLocationKalman")); + state.setRenderTime(render_time); + pm->send("mapRenderState", msg); + frame_id++; } diff --git a/selfdrive/navd/map_renderer.h b/selfdrive/navd/map_renderer.h index 7f725c93fe..1c7024361d 100644 --- a/selfdrive/navd/map_renderer.h +++ b/selfdrive/navd/map_renderer.h @@ -34,7 +34,7 @@ private: std::unique_ptr vipc_server; std::unique_ptr pm; std::unique_ptr sm; - void sendVipc(); + void publish(const double render_time); QMapboxGLSettings m_settings; QScopedPointer m_map; From 3cc439ce98312bf558c553b8f9477503a9440e26 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 9 Dec 2022 00:00:45 -0500 Subject: [PATCH 0475/1179] VW MQB: Restore lead car indicator in instrument cluster (#26651) * VW MQB: Lead car indicator in ACC HUD * typo * do this cleanup in another PR --- selfdrive/car/volkswagen/carcontroller.py | 6 +++++- selfdrive/car/volkswagen/carstate.py | 6 ++++++ selfdrive/car/volkswagen/mqbcan.py | 4 ++-- selfdrive/car/volkswagen/pqcan.py | 4 ++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index fff5548671..f9ce2dc326 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -2,6 +2,7 @@ from cereal import car from opendbc.can.packer import CANPacker from common.numpy_fast import clip from common.conversions import Conversions as CV +from common.realtime import DT_CTRL from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.volkswagen import mqbcan, pqcan from selfdrive.car.volkswagen.values import CANBUS, PQ_CARS, CarControllerParams @@ -88,10 +89,13 @@ class CarController: CS.out.steeringPressed, hud_alert, hud_control)) if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.CP.openpilotLongitudinalControl: + lead_distance = 0 + if hud_control.leadVisible and self.frame * DT_CTRL > 1.0: # Don't display lead until we know the scaling factor + lead_distance = 512 if CS.upscale_lead_car_signal else 8 acc_hud_status = self.CCS.acc_hud_status_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive) set_speed = hud_control.setSpeed * CV.MS_TO_KPH # FIXME: follow the recent displayed-speed updates, also use mph_kmh toggle to fix display rounding problem? can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, CANBUS.pt, acc_hud_status, set_speed, - hud_control.leadVisible)) + lead_distance)) # **** Stock ACC Button Controls **************************************** # diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 263edbfc9d..7ea9aa871b 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -13,6 +13,7 @@ class CarState(CarStateBase): self.CCP = CarControllerParams(CP) self.button_states = {button.event_type: False for button in self.CCP.BUTTONS} self.esp_hold_confirmation = False + self.upscale_lead_car_signal = False def create_button_events(self, pt_cp, buttons): button_events = [] @@ -141,6 +142,9 @@ class CarState(CarStateBase): # Additional safety checks performed in CarInterface. ret.espDisabled = pt_cp.vl["ESP_21"]["ESP_Tastung_passiv"] != 0 + # Digital instrument clusters expect the ACC HUD lead car distance to be scaled differently + self.upscale_lead_car_signal = bool(pt_cp.vl["Kombi_03"]["KBI_Variante"]) + return ret def update_pq(self, pt_cp, cam_cp, ext_cp, trans_type): @@ -281,6 +285,7 @@ class CarState(CarStateBase): ("ESP_Tastung_passiv", "ESP_21"), # Stability control disabled ("ESP_Haltebestaetigung", "ESP_21"), # ESP hold confirmation ("KBI_Handbremse", "Kombi_01"), # Manual handbrake applied + ("KBI_Variante", "Kombi_03"), # Digital/full-screen instrument cluster installed ("TSK_Status", "TSK_06"), # ACC engagement status from drivetrain coordinator ("GRA_Hauptschalter", "GRA_ACC_01"), # ACC button, on/off ("GRA_Abbrechen", "GRA_ACC_01"), # ACC button, cancel @@ -312,6 +317,7 @@ class CarState(CarStateBase): ("Airbag_02", 5), # From J234 Airbag control module ("Kombi_01", 2), # From J285 Instrument cluster ("Blinkmodi_02", 1), # From J519 BCM (sent at 1Hz when no lights active, 50Hz when active) + ("Kombi_03", 0), # From J285 instrument cluster (not present on older cars, 1Hz when present) ] if CP.transmissionType == TransmissionType.automatic: diff --git a/selfdrive/car/volkswagen/mqbcan.py b/selfdrive/car/volkswagen/mqbcan.py index 25a710dbb8..30a51f6fe6 100644 --- a/selfdrive/car/volkswagen/mqbcan.py +++ b/selfdrive/car/volkswagen/mqbcan.py @@ -96,13 +96,13 @@ def create_acc_accel_control(packer, bus, acc_type, enabled, accel, acc_control, return commands -def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, lead_visible): +def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, lead_distance): values = { "ACC_Status_Anzeige": acc_hud_status, "ACC_Wunschgeschw_02": set_speed if set_speed < 250 else 327.36, "ACC_Gesetzte_Zeitluecke": 3, "ACC_Display_Prio": 3, - # TODO: ACC_Abstandsindex for lead car distance, must determine analog vs digital cluster for scaling + "ACC_Abstandsindex": lead_distance, } return packer.make_can_msg("ACC_02", bus, values) diff --git a/selfdrive/car/volkswagen/pqcan.py b/selfdrive/car/volkswagen/pqcan.py index 6beb90c092..130f107950 100644 --- a/selfdrive/car/volkswagen/pqcan.py +++ b/selfdrive/car/volkswagen/pqcan.py @@ -77,12 +77,12 @@ def create_acc_accel_control(packer, bus, acc_type, enabled, accel, acc_control, return commands -def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, lead_visible): +def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, lead_distance): values = { "ACA_StaACC": acc_hud_status, "ACA_Zeitluecke": 2, "ACA_V_Wunsch": set_speed, - "ACA_gemZeitl": 8 if lead_visible else 0, + "ACA_gemZeitl": lead_distance, # TODO: ACA_ID_StaACC, ACA_AnzDisplay, ACA_kmh_mph, ACA_PrioDisp, ACA_Aend_Zeitluecke # display/display-prio handling probably needed to stop confusing the instrument cluster # kmh_mph handling probably needed to resolve rounding errors in displayed setpoint From 137beee5560a98ad043208cfbc2628646a12477c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Dec 2022 03:34:29 -0800 Subject: [PATCH 0476/1179] Toyota: don't log standstill for NO_STOP_TIMER_CAR (#26733) * don't log when no stop timer * updated comment * whoops * subtract tss2, their standstill is real --- selfdrive/car/toyota/carstate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index fec006fbb4..3be748c4cf 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -6,7 +6,7 @@ from common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from selfdrive.car.interfaces import CarStateBase -from selfdrive.car.toyota.values import ToyotaFlags, DBC, STEER_THRESHOLD, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR +from selfdrive.car.toyota.values import ToyotaFlags, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR class CarState(CarStateBase): @@ -124,7 +124,9 @@ class CarState(CarStateBase): self.low_speed_lockout = cp.vl["PCM_CRUISE_2"]["LOW_SPEED_LOCKOUT"] == 2 self.pcm_acc_status = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] - ret.cruiseState.standstill = self.pcm_acc_status == 7 + if self.CP.carFingerprint not in (NO_STOP_TIMER_CAR - TSS2_CAR): + # ignore standstill state in certain vehicles, since pcm allows to restart with just an acceleration request + ret.cruiseState.standstill = self.pcm_acc_status == 7 ret.cruiseState.enabled = bool(cp.vl["PCM_CRUISE"]["CRUISE_ACTIVE"]) ret.cruiseState.nonAdaptive = cp.vl["PCM_CRUISE"]["CRUISE_STATE"] in (1, 2, 3, 4, 5, 6) From 767261e61cd9e50cc93941792bc14c8932321150 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 10 Dec 2022 02:42:43 +0800 Subject: [PATCH 0477/1179] Cabana: fix header word wrap issue (#26737) --- tools/cabana/historylog.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 5457555db4..ec9a0b011c 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -68,9 +68,11 @@ void HistoryLogModel::updateState() { // HeaderView QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { + int default_size = qMax(100, rect().width() / model()->columnCount()); const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); - const QRect rect = fontMetrics().boundingRect(QRect(0, 0, sectionSize(logicalIndex), 1000), defaultAlignment(), text); - return rect.size() + QSize{10, 6}; + const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text); + QSize size = rect.size() + QSize{10, 6}; + return {qMax(size.width(), default_size), size.height()}; } void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { @@ -81,7 +83,7 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI painter->fillRect(rect, bg_role.value()); } QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString(); - painter->drawText(rect.adjusted(5, 3, 5, 3), defaultAlignment(), text); + painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text); } // HistoryLog @@ -90,15 +92,13 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { model = new HistoryLogModel(this); setModel(model); setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); - horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); - horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); verticalHeader()->setVisible(false); setFrameShape(QFrame::NoFrame); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); } int HistoryLog::sizeHintForColumn(int column) const { - // sizeHintForColumn is only called for column 0 (ResizeToContents) - return itemDelegate()->sizeHint(viewOptions(), model->index(0, 0)).width() + 5; + return -1; } From 54529aa7f8b663d38e3b2bedc84f80487238a86b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Dec 2022 13:08:15 -0800 Subject: [PATCH 0478/1179] UI: add flag for showing map render (#26740) --- selfdrive/ui/qt/onroad.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index fed59ef123..95ad813dff 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -31,6 +31,11 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) { split->insertWidget(0, arCam); } + if (getenv("MAP_RENDER_VIEW")) { + CameraWidget *map_render = new CameraWidget("navd", VISION_STREAM_MAP, false, this); + split->insertWidget(0, map_render); + } + stacked_layout->addWidget(split_wrapper); alerts = new OnroadAlerts(this); From 27dc9c0e79fc88acf88fff56ed119f4f2dc6105f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Dec 2022 13:24:44 -0800 Subject: [PATCH 0479/1179] nav: add mapRenderState.frameId --- cereal | 2 +- selfdrive/navd/map_renderer.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index 8825337204..609491e539 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 88253372042197ac92776cddc35a29d0eb384a3e +Subproject commit 609491e539cfaf102b23ebb1415cc2d6787cc245 diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 904768d101..9305fdf75c 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -180,6 +180,7 @@ void MapRenderer::publish(const double render_time) { auto state = msg.initEvent().initMapRenderState(); state.setLocationMonoTime(sm->rcv_time("liveLocationKalman")); state.setRenderTime(render_time); + state.setFrameId(frame_id); pm->send("mapRenderState", msg); frame_id++; From 3ff37cca2183e524dbd2f82692b07de324f8bc59 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Dec 2022 14:31:18 -0800 Subject: [PATCH 0480/1179] map renderer: retry when render fails (#26741) * map renderer: retry when render fails * cleanup --- selfdrive/navd/map_renderer.cc | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 9305fdf75c..047e1bd45d 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -56,6 +56,11 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set m_map->setFramebufferObject(fbo->handle(), fbo->size()); gl_functions->glViewport(0, 0, WIDTH, HEIGHT); + QObject::connect(m_map.data(), &QMapboxGL::mapChanged, [=](QMapboxGL::MapChange change) { + // https://github.com/mapbox/mapbox-gl-native/blob/cf734a2fec960025350d8de0d01ad38aeae155a0/platform/qt/include/qmapboxgl.hpp#L116 + //LOGD("new state %d", change); + }); + QObject::connect(m_map.data(), &QMapboxGL::mapLoadingFailed, [=](QMapboxGL::MapLoadingFailure err_code, const QString &reason) { LOGE("Map loading failed with %d: '%s'\n", err_code, reason.toStdString().c_str()); }); @@ -86,6 +91,19 @@ void MapRenderer::msgUpdate() { bool localizer_valid = (location.getStatus() == cereal::LiveLocationKalman::Status::VALID) && pos.getValid(); if (localizer_valid && (sm->rcv_frame("liveLocationKalman") % 10) == 0) { updatePosition(QMapbox::Coordinate(pos.getValue()[0], pos.getValue()[1]), RAD2DEG(orientation.getValue()[2])); + + // TODO: use the static rendering mode + if (!loaded() && frame_id > 0) { + for (int i = 0; i < 5 && !loaded(); i++) { + LOGW("map render retry #%d, %d", i+1, m_map.isNull()); + QApplication::processEvents(QEventLoop::AllEvents, 100); + update(); + } + + if (!loaded()) { + LOGE("failed to render map after retry"); + } + } } } @@ -128,14 +146,12 @@ void MapRenderer::update() { gl_functions->glFlush(); double end_t = millis_since_boot(); - publish((end_t - start_t) / 1000.0); + if ((vipc_server != nullptr) && loaded()) { + publish((end_t - start_t) / 1000.0); + } } void MapRenderer::publish(const double render_time) { - if (!vipc_server || !loaded()) { - return; - } - QImage cap = fbo->toImage().convertToFormat(QImage::Format_RGB888, Qt::AutoColor); uint64_t ts = nanos_since_boot(); VisionBuf* buf = vipc_server->get_buffer(VisionStreamType::VISION_STREAM_MAP); From df6bd0f3924b0bca2b0c0af2b2745675fb27e668 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Dec 2022 18:43:45 -0800 Subject: [PATCH 0481/1179] cleanup: deprecate lqrState field (#26745) * first commit * clean up * bump cereal * revert angle controller * revert * clean up * revert * bump * bumptomaster --- cereal | 2 +- tools/replay/ui.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 609491e539..eaf962bceb 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 609491e539cfaf102b23ebb1415cc2d6787cc245 +Subproject commit eaf962bcebee713d26008db30d95c6a713e9fc59 diff --git a/tools/replay/ui.py b/tools/replay/ui.py index bbcd49061e..43cbef5bd6 100755 --- a/tools/replay/ui.py +++ b/tools/replay/ui.py @@ -128,8 +128,8 @@ def ui_thread(addr): sm.update(0) w = sm['controlsState'].lateralControlState.which() - if w == 'lqrState': - angle_steers_k = sm['controlsState'].lateralControlState.lqrState.steeringAngleDeg + if w == 'lqrStateDEPRECATED': + angle_steers_k = sm['controlsState'].lateralControlState.lqrStateDEPRECATED.steeringAngleDeg elif w == 'indiState': angle_steers_k = sm['controlsState'].lateralControlState.indiState.steeringAngleDeg else: From c1b3d696bc5bdd799a937f569c94e0834230c89e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Dec 2022 21:43:27 -0800 Subject: [PATCH 0482/1179] controlsd: set steer_limited for angle cars (#26748) * Set steer limited for angle cars * closer to torque threshold --- selfdrive/controls/controlsd.py | 8 ++++++-- selfdrive/controls/lib/latcontrol_angle.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 3840d6e0de..59b6b6c6a0 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -21,7 +21,7 @@ from selfdrive.controls.lib.latcontrol import LatControl from selfdrive.controls.lib.longcontrol import LongControl from selfdrive.controls.lib.latcontrol_pid import LatControlPID from selfdrive.controls.lib.latcontrol_indi import LatControlINDI -from selfdrive.controls.lib.latcontrol_angle import LatControlAngle +from selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD from selfdrive.controls.lib.latcontrol_torque import LatControlTorque from selfdrive.controls.lib.events import Events, ET from selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert @@ -722,7 +722,11 @@ class Controls: self.last_actuators, can_sends = self.CI.apply(CC) self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) CC.actuatorsOutput = self.last_actuators - self.steer_limited = abs(CC.actuators.steer - CC.actuatorsOutput.steer) > 1e-2 + if self.CP.steerControlType == car.CarParams.SteerControlType.angle: + self.steer_limited = abs(CC.actuators.steeringAngleDeg - CC.actuatorsOutput.steeringAngleDeg) > \ + STEER_ANGLE_SATURATION_THRESHOLD + else: + self.steer_limited = abs(CC.actuators.steer - CC.actuatorsOutput.steer) > 1e-2 force_decel = (self.sm['driverMonitoringState'].awarenessStatus < 0.) or \ (self.state == State.softDisabling) diff --git a/selfdrive/controls/lib/latcontrol_angle.py b/selfdrive/controls/lib/latcontrol_angle.py index 0e5be4a977..1b74fd4186 100644 --- a/selfdrive/controls/lib/latcontrol_angle.py +++ b/selfdrive/controls/lib/latcontrol_angle.py @@ -19,7 +19,7 @@ class LatControlAngle(LatControl): angle_steers_des += params.angleOffsetDeg angle_control_saturated = abs(angle_steers_des - CS.steeringAngleDeg) > STEER_ANGLE_SATURATION_THRESHOLD - angle_log.saturated = self._check_saturation(angle_control_saturated, CS, steer_limited) + angle_log.saturated = self._check_saturation(angle_control_saturated, CS, False) angle_log.steeringAngleDeg = float(CS.steeringAngleDeg) angle_log.steeringAngleDesiredDeg = angle_steers_des return 0, float(angle_steers_des), angle_log From d5ffb90a048d9a6d727e723e3551d5333abddef7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Dec 2022 21:43:55 -0800 Subject: [PATCH 0483/1179] LatControlAngle: lower saturation check speed (#26749) lower speed for angle --- selfdrive/controls/lib/latcontrol.py | 3 ++- selfdrive/controls/lib/latcontrol_angle.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/latcontrol.py b/selfdrive/controls/lib/latcontrol.py index 78b59fda59..cefbc1078c 100644 --- a/selfdrive/controls/lib/latcontrol.py +++ b/selfdrive/controls/lib/latcontrol.py @@ -11,6 +11,7 @@ class LatControl(ABC): self.sat_count_rate = 1.0 * DT_CTRL self.sat_limit = CP.steerLimitTimer self.sat_count = 0. + self.sat_check_min_speed = 10. # we define the steer torque scale as [-1.0...1.0] self.steer_max = 1.0 @@ -23,7 +24,7 @@ class LatControl(ABC): self.sat_count = 0. def _check_saturation(self, saturated, CS, steer_limited): - if saturated and CS.vEgo > 10. and not steer_limited and not CS.steeringPressed: + if saturated and CS.vEgo > self.sat_check_min_speed and not steer_limited and not CS.steeringPressed: self.sat_count += self.sat_count_rate else: self.sat_count -= self.sat_count_rate diff --git a/selfdrive/controls/lib/latcontrol_angle.py b/selfdrive/controls/lib/latcontrol_angle.py index 1b74fd4186..e2b0c15fff 100644 --- a/selfdrive/controls/lib/latcontrol_angle.py +++ b/selfdrive/controls/lib/latcontrol_angle.py @@ -7,6 +7,8 @@ STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees class LatControlAngle(LatControl): + sat_check_min_speed = 5. + def update(self, active, CS, VM, params, last_actuators, steer_limited, desired_curvature, desired_curvature_rate, llk): angle_log = log.ControlsState.LateralAngleState.new_message() From f3a711953afea1fcebb4c10b1e2462c4032ac147 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 9 Dec 2022 22:56:32 -0800 Subject: [PATCH 0484/1179] navmodel: check images in replay test (#26747) * move position * log images * enable test * update refs * ignore Co-authored-by: Comma Device --- selfdrive/navd/map_renderer.cc | 30 +++++++---- selfdrive/navd/map_renderer.h | 1 + selfdrive/test/process_replay/compare_logs.py | 2 +- selfdrive/test/process_replay/model_replay.py | 50 +++++++++++-------- .../process_replay/model_replay_ref_commit | 2 +- 5 files changed, 52 insertions(+), 33 deletions(-) diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 047e1bd45d..0fed108045 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -17,6 +17,9 @@ const int NUM_VIPC_BUFFERS = 4; const int EARTH_CIRCUMFERENCE_METERS = 40075000; const int PIXELS_PER_TILE = 256; +const bool TEST_MODE = getenv("MAP_RENDER_TEST_MODE"); +const int LLK_DECIMATION = TEST_MODE ? 1 : 10; + float get_zoom_level_for_scale(float lat, float meters_per_pixel) { float meters_per_tile = meters_per_pixel * PIXELS_PER_TILE; float num_tiles = cos(DEG2RAD(lat)) * EARTH_CIRCUMFERENCE_METERS / meters_per_tile; @@ -89,7 +92,7 @@ void MapRenderer::msgUpdate() { auto orientation = location.getCalibratedOrientationNED(); bool localizer_valid = (location.getStatus() == cereal::LiveLocationKalman::Status::VALID) && pos.getValid(); - if (localizer_valid && (sm->rcv_frame("liveLocationKalman") % 10) == 0) { + if (localizer_valid && (sm->rcv_frame("liveLocationKalman") % LLK_DECIMATION) == 0) { updatePosition(QMapbox::Coordinate(pos.getValue()[0], pos.getValue()[1]), RAD2DEG(orientation.getValue()[2])); // TODO: use the static rendering mode @@ -151,6 +154,15 @@ void MapRenderer::update() { } } +void MapRenderer::sendThumbnail(const uint64_t ts, const kj::Array &buf) { + MessageBuilder msg; + auto thumbnaild = msg.initEvent().initNavThumbnail(); + thumbnaild.setFrameId(frame_id); + thumbnaild.setTimestampEof(ts); + thumbnaild.setThumbnail(buf); + pm->send("navThumbnail", msg); +} + void MapRenderer::publish(const double render_time) { QImage cap = fbo->toImage().convertToFormat(QImage::Format_RGB888, Qt::AutoColor); uint64_t ts = nanos_since_boot(); @@ -173,7 +185,12 @@ void MapRenderer::publish(const double render_time) { vipc_server->send(buf, &extra); - if (frame_id % 100 == 0) { + // Send thumbnail + if (TEST_MODE) { + // Full image in thumbnails in test mode + kj::Array buffer_kj = kj::heapArray((const capnp::byte*)cap.bits(), cap.sizeInBytes()); + sendThumbnail(ts, buffer_kj); + } else if (frame_id % 100 == 0) { // Write jpeg into buffer QByteArray buffer_bytes; QBuffer buffer(&buffer_bytes); @@ -181,14 +198,7 @@ void MapRenderer::publish(const double render_time) { cap.save(&buffer, "JPG", 50); kj::Array buffer_kj = kj::heapArray((const capnp::byte*)buffer_bytes.constData(), buffer_bytes.size()); - - // Send thumbnail - MessageBuilder msg; - auto thumbnaild = msg.initEvent().initNavThumbnail(); - thumbnaild.setFrameId(frame_id); - thumbnaild.setTimestampEof(ts); - thumbnaild.setThumbnail(buffer_kj); - pm->send("navThumbnail", msg); + sendThumbnail(ts, buffer_kj); } // Send state msg diff --git a/selfdrive/navd/map_renderer.h b/selfdrive/navd/map_renderer.h index 1c7024361d..0019030b6d 100644 --- a/selfdrive/navd/map_renderer.h +++ b/selfdrive/navd/map_renderer.h @@ -35,6 +35,7 @@ private: std::unique_ptr pm; std::unique_ptr sm; void publish(const double render_time); + void sendThumbnail(const uint64_t ts, const kj::Array &buf); QMapboxGLSettings m_settings; QScopedPointer m_map; diff --git a/selfdrive/test/process_replay/compare_logs.py b/selfdrive/test/process_replay/compare_logs.py index e5e21a6fef..c96e624421 100755 --- a/selfdrive/test/process_replay/compare_logs.py +++ b/selfdrive/test/process_replay/compare_logs.py @@ -80,7 +80,7 @@ def compare_logs(log1, log2, ignore_fields=None, ignore_msgs=None, tolerance=Non diff = [] for msg1, msg2 in zip(log1, log2): if msg1.which() != msg2.which(): - print(msg1, msg2) + print(msg1.which(), msg2.which()) raise Exception("msgs not aligned between logs") msg1 = remove_ignored_fields(msg1, ignore_fields) diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index 1f43bb791a..ce861b37e6 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -23,7 +23,7 @@ from tools.lib.logreader import LogReader TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30" SEGMENT = 6 MAX_FRAMES = 100 if PC else 600 -NAV_FRAMES = 20 +NAV_FRAMES = 50 NO_NAV = "NO_NAV" in os.environ # TODO: make map renderer work in CI SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0")) @@ -43,39 +43,46 @@ def replace_calib(msg, calib): def nav_model_replay(lr): + sm = messaging.SubMaster(['navModel', 'navThumbnail']) pm = messaging.PubMaster(['liveLocationKalman', 'navRoute']) - sock = messaging.sub_sock('navModel', conflate=False, timeout=1000) + + nav = [m for m in lr if m.which() == 'navRoute'] + llk = [m for m in lr if m.which() == 'liveLocationKalman'] + assert len(nav) > 0 and len(llk) >= NAV_FRAMES log_msgs = [] try: + assert "MAPBOX_TOKEN" in os.environ + os.environ['MAP_RENDER_TEST_MODE'] = '1' managed_processes['mapsd'].start() managed_processes['navmodeld'].start() # setup position and route - nav = [m for m in lr if m.which() == 'navRoute'] - llk = [m for m in lr if m.which() == 'liveLocationKalman'] - assert len(nav) > 0 and len(llk) > 0 - - for _ in range(30): + for _ in range(10): for s in (llk, nav): - msg = s[0] - pm.send(msg.which(), msg.as_builder().to_bytes()) - if messaging.recv_one(sock) is not None: + pm.send(s[0].which(), s[0].as_builder().to_bytes()) + sm.update(1000) + if sm.updated['navModel']: break - else: - raise Exception("no navmodeld outputs") + time.sleep(1) + if not sm.updated['navModel']: + raise Exception("no navmodeld outputs, failed to initialize") + + # drain time.sleep(2) - messaging.drain_sock_raw(sock) + sm.update(0) # run replay - for _ in range(NAV_FRAMES): - # 2Hz decimation - for _ in range(10): - pm.send(llk[0].which(), llk[0].as_builder().to_bytes()) - time.sleep(0.1) - with Timeout(5, "timed out waiting for nav model outputs"): - log_msgs.append(messaging.recv_one_retry(sock)) + for n in range(NAV_FRAMES): + pm.send(llk[n].which(), llk[n].as_builder().to_bytes()) + m = messaging.recv_one(sm.sock['navThumbnail']) + assert m is not None, f"no navThumbnail, frame={n}" + log_msgs.append(m) + + m = messaging.recv_one(sm.sock['navModel']) + assert m is not None, f"no navModel response, frame={n}" + log_msgs.append(m) finally: managed_processes['mapsd'].stop() managed_processes['navmodeld'].stop() @@ -212,7 +219,7 @@ if __name__ == "__main__": try: expected_msgs = 2*MAX_FRAMES if not NO_NAV: - expected_msgs += NAV_FRAMES + expected_msgs += NAV_FRAMES*2 cmp_log = list(LogReader(BASE_URL + log_fn))[:expected_msgs] ignore = [ @@ -223,6 +230,7 @@ if __name__ == "__main__": 'driverStateV2.dspExecutionTime', 'navModel.dspExecutionTime', 'navModel.modelExecutionTime', + 'navThumbnail.timestampEof', ] if PC: ignore += [ diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index b58cca1aaf..4dcf0ecbb7 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -4b2c6516cd460ee443b9006f01233168edf3d170 \ No newline at end of file +30dfeed50ac562f99b0aad985bd6b0e6d8188fcb \ No newline at end of file From 84340f07abdef408f3fa29083af2f1a55cd3308e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Dec 2022 23:29:56 -0800 Subject: [PATCH 0485/1179] LatControlAngle: fix setting saturation check speed (#26752) set in init function --- selfdrive/controls/lib/latcontrol_angle.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/latcontrol_angle.py b/selfdrive/controls/lib/latcontrol_angle.py index e2b0c15fff..d692f80b4b 100644 --- a/selfdrive/controls/lib/latcontrol_angle.py +++ b/selfdrive/controls/lib/latcontrol_angle.py @@ -7,7 +7,9 @@ STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees class LatControlAngle(LatControl): - sat_check_min_speed = 5. + def __init__(self, CP, CI): + super().__init__(CP, CI) + self.sat_check_min_speed = 5. def update(self, active, CS, VM, params, last_actuators, steer_limited, desired_curvature, desired_curvature_rate, llk): angle_log = log.ControlsState.LateralAngleState.new_message() From 2545dd195efc164da9561ae9ae2115482eb9f931 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 9 Dec 2022 23:30:41 -0800 Subject: [PATCH 0486/1179] alert: smaller standstill alert (#26751) smaller standstill alert --- selfdrive/controls/lib/events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 5578a83a23..9fbf565328 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -500,9 +500,9 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { EventName.resumeRequired: { ET.WARNING: Alert( - "STOPPED", "Press Resume to Exit Standstill", - AlertStatus.userPrompt, AlertSize.mid, + "", + AlertStatus.userPrompt, AlertSize.small, Priority.LOW, VisualAlert.none, AudibleAlert.none, .2), }, From 709f71d5e0bb886f2c7897b5e4831320bd739525 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Sat, 10 Dec 2022 02:35:10 -0500 Subject: [PATCH 0487/1179] HKG: Add FW for 2022 Kia Telluride (#26750) * HKG: Add FW for 2022 Kia Telluride * only short trans Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1e9d0f7f62..ac441219b2 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -845,6 +845,7 @@ FW_VERSIONS = { b'\xf1\x00LX2_ SCC FHCUP 1.00 1.04 99110-S8100 ', b'\xf1\x00LX2_ SCC FHCUP 1.00 1.05 99110-S8100 ', b'\xf1\x00ON__ FCA FHCUP 1.00 1.02 99110-S9100 ', + b'\xf1\x00ON__ FCA FHCUP 1.00 1.01 99110-S9110 ', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00LX ESC \x01 103\x19\t\x10 58910-S8360', @@ -858,6 +859,7 @@ FW_VERSIONS = { b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360', b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360', b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320', + b'\xf1\x00ON ESC \x01 101\x19\t\x08 58910-S9360', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00', @@ -880,11 +882,13 @@ FW_VERSIONS = { b'\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 181105', b'\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 200720', b'\xf1\x00LX2 MFC AT USA LHD 1.00 1.00 99211-S8110 210226', + b'\xf1\x00ON MFC AT USA LHD 1.00 1.04 99211-S9100 211227', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x00bcsh8p54 U872\x00\x00\x00\x00\x00\x00TON4G38NB1\x96z28', b'\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX4G38NB3X\xa8\xc08', b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6', + b'\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00TON2G38NB5j\x94.\xde', b'\xf1\x87LBLUFN591307KF25vgvw\x97wwwy\x99\xa7\x99\x99\xaa\xa9\x9af\x88\x96h\x95o\xf7\xff\x99f/\xff\xe4c\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB2\xd7\xc1/\xd1', b'\xf1\x87LBLUFN650868KF36\xa9\x98\x89\x88\xa8\x88\x88\x88h\x99\xa6\x89fw\x86gw\x88\x97x\xaa\x7f\xf6\xff\xbb\xbb\x8f\xff+\x82\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', b'\xf1\x87LBLUFN655162KF36\x98\x88\x88\x88\x98\x88\x88\x88x\x99\xa7\x89x\x99\xa7\x89x\x99\x97\x89g\x7f\xf7\xffwU_\xff\xe9!\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8', From f36a3664b056a3500b68f4b5d7955b13bc8d0e4c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 10 Dec 2022 02:03:40 -0800 Subject: [PATCH 0488/1179] CarController: log steer sent to the car (#26743) * log value sent to the car * rename * bump * Update ref_commit --- cereal | 2 +- selfdrive/car/body/carcontroller.py | 1 + selfdrive/car/chrysler/carcontroller.py | 1 + selfdrive/car/gm/carcontroller.py | 1 + selfdrive/car/honda/carcontroller.py | 1 + selfdrive/car/hyundai/carcontroller.py | 1 + selfdrive/car/mazda/carcontroller.py | 1 + selfdrive/car/subaru/carcontroller.py | 1 + selfdrive/car/toyota/carcontroller.py | 1 + selfdrive/car/volkswagen/carcontroller.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 11 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cereal b/cereal index eaf962bceb..439429cad4 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit eaf962bcebee713d26008db30d95c6a713e9fc59 +Subproject commit 439429cad4d1e2ab874520cb5d4db8b8d978cbde diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index 0d5d780bd3..00673a7e28 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -85,6 +85,7 @@ class CarController: new_actuators = CC.actuators.copy() new_actuators.accel = torque_l new_actuators.steer = torque_r + new_actuators.steerOutputCan = torque_r self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 879da88123..31cd01b654 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -78,5 +78,6 @@ class CarController: new_actuators = CC.actuators.copy() new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX + new_actuators.steerOutputCan = self.apply_steer_last return new_actuators, can_sends diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index a6cd2f19b9..d380abf8e3 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -158,6 +158,7 @@ class CarController: new_actuators = actuators.copy() new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX + new_actuators.steerOutputCan = self.apply_steer_last new_actuators.gas = self.apply_gas new_actuators.brake = self.apply_brake diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 66a1485dc6..ab944a30aa 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -262,6 +262,7 @@ class CarController: new_actuators.gas = self.gas new_actuators.brake = self.brake new_actuators.steer = self.last_steer + new_actuators.steerOutputCan = apply_steer self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 3f128b1598..2f95a29e7b 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -186,6 +186,7 @@ class CarController: new_actuators = actuators.copy() new_actuators.steer = apply_steer / self.params.STEER_MAX + new_actuators.steerOutputCan = apply_steer new_actuators.accel = accel self.frame += 1 diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 2add59ccb0..027822cc3f 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -59,6 +59,7 @@ class CarController: new_actuators = CC.actuators.copy() new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX + new_actuators.steerOutputCan = apply_steer self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index b5429daef2..a56e63408e 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -87,6 +87,7 @@ class CarController: new_actuators = actuators.copy() new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX + new_actuators.steerOutputCan = self.apply_steer_last self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 4ec9500171..1f469c72be 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -158,6 +158,7 @@ class CarController: new_actuators = actuators.copy() new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX + new_actuators.steerOutputCan = apply_steer new_actuators.accel = self.accel new_actuators.gas = self.gas diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index f9ce2dc326..628962de75 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -107,6 +107,7 @@ class CarController: new_actuators = actuators.copy() new_actuators.steer = self.apply_steer_last / self.CCP.STEER_MAX + new_actuators.steerOutputCan = self.apply_steer_last self.gra_acc_counter_last = CS.gra_stock_values["COUNTER"] self.frame += 1 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4641299458..64f1c5d472 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f17412941a0e8229eea308c33189a5bdb1a17ae8 +9876d91c77d3f7611398c43c4d79237cadb01c9c From ba7a4747659a1340cfa7605a916466feb1405d05 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 10 Dec 2022 02:25:16 -0800 Subject: [PATCH 0489/1179] Toyota: lower stopping speed (#26274) * lower toyota stopping speed * order * Update selfdrive/car/toyota/interface.py * Update ref_commit --- selfdrive/car/toyota/interface.py | 2 ++ selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index d3835d175b..8e180e2301 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -225,6 +225,8 @@ class CarInterface(CarInterfaceBase): tune.kiBP = [0., 5., 12., 20., 27.] tune.kiV = [.35, .23, .20, .17, .1] if candidate in TSS2_CAR: + ret.vEgoStopping = 0.25 + ret.vEgoStarting = 0.25 ret.stoppingDecelRate = 0.3 # reach stopping target smoothly else: tune.kpBP = [0., 5., 35.] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 64f1c5d472..57c5efd946 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -9876d91c77d3f7611398c43c4d79237cadb01c9c +3523d88432d661ee0d1022e9a4774f3455c832b5 From 4b7b257fdcc7c027993e0d823997305e3f5de284 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 11 Dec 2022 05:09:07 +0800 Subject: [PATCH 0490/1179] Cabana: increase cell height of BinaryView and cleanup code (#26754) * setDefaultSectionSize * cleanup --- tools/cabana/binaryview.cc | 34 +++++++++++----------------------- tools/cabana/binaryview.h | 8 +------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index aa256b4ce1..b98c75d452 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -10,7 +10,7 @@ // BinaryView -const int CELL_HEIGHT = 26; +const int CELL_HEIGHT = 36; inline int get_bit_index(const QModelIndex &index, bool little_endian) { return index.row() * 8 + (little_endian ? 7 - index.column() : index.column()); @@ -24,14 +24,13 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); verticalHeader()->setSectionsClickable(false); verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + verticalHeader()->setDefaultSectionSize(CELL_HEIGHT); horizontalHeader()->hide(); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); setFrameShape(QFrame::NoFrame); setShowGrid(false); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); setMouseTracking(true); + setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } void BinaryView::highlight(const Signal *sig) { @@ -57,7 +56,7 @@ void BinaryView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF } void BinaryView::mousePressEvent(QMouseEvent *event) { - delegate->setSelectionColor(style()->standardPalette().color(QPalette::Active, QPalette::Highlight)); + delegate->selection_color = (palette().color(QPalette::Active, QPalette::Highlight)); if (auto index = indexAt(event->pos()); index.isValid() && index.column() != 8) { anchor_index = index; auto item = (const BinaryViewModel::Item *)anchor_index.internalPointer(); @@ -66,7 +65,7 @@ void BinaryView::mousePressEvent(QMouseEvent *event) { 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); + delegate->selection_color = item->bg_color; break; } } @@ -79,8 +78,7 @@ void BinaryView::highlightPosition(const QPoint &pos) { auto item = (BinaryViewModel::Item *)index.internalPointer(); const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); highlight(sig); - sig ? QToolTip::showText(pos, sig->name.c_str(), this, rect()) - : QToolTip::hideText(); + QToolTip::showText(pos, sig ? sig->name.c_str() : "", this, rect()); } } @@ -214,7 +212,7 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i if (orientation == Qt::Vertical) { switch (role) { case Qt::DisplayRole: return section; - case Qt::SizeHintRole: return QSize(30, CELL_HEIGHT); + case Qt::SizeHintRole: return QSize(30, 0); case Qt::TextAlignmentRole: return Qt::AlignCenter; } } @@ -224,16 +222,9 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i // BinaryItemDelegate BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { - // cache fonts and color - small_font.setPointSize(6); + small_font.setPixelSize(8); hex_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); hex_font.setBold(true); - selection_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 { @@ -245,12 +236,10 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->setFont(hex_font); } else if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, selection_color); - painter->setPen(QApplication::style()->standardPalette().color(QPalette::BrightText)); + painter->setPen(option.palette.color(QPalette::BrightText)); } else if (!item->sigs.isEmpty() && (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig))) { painter->fillRect(option.rect, item->bg_color); - painter->setPen(item->sigs.contains(bin_view->hovered_sig) - ? QApplication::style()->standardPalette().color(QPalette::BrightText) - : Qt::black); + painter->setPen(item->sigs.contains(bin_view->hovered_sig) ? option.palette.color(QPalette::BrightText) : Qt::black); } painter->drawText(option.rect, Qt::AlignCenter, item->val); @@ -258,6 +247,5 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op 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 index c37b378e44..e936efc658 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -9,22 +9,16 @@ #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; void setSelectionColor(const QColor &color) { selection_color = color; } -private: QFont small_font, hex_font; QColor selection_color; }; class BinaryViewModel : public QAbstractTableModel { - Q_OBJECT - public: BinaryViewModel(QObject *parent) : QAbstractTableModel(parent) {} void setMessage(const QString &message_id); @@ -52,7 +46,7 @@ public: private: QString msg_id; - const DBCMsg *dbc_msg; + const DBCMsg *dbc_msg = nullptr; int row_count = 0; const int column_count = 9; }; From 9ffb7a751874ce829b01c23809615a955819b9a6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 11 Dec 2022 05:21:23 +0800 Subject: [PATCH 0491/1179] Cabana: add button to display all cached data in chart (#26575) * display all data btn * remove timer * update toolbar later * dont update axis y in updateSeries faster get_raw_value * faster update * optimize zoom y axis * cleanup * revert changes to get_raw_value * updateState in eventsMerge * cleanup: * cleanup --- tools/cabana/chartswidget.cc | 75 ++++++++++++++++++++++++++++-------- tools/cabana/chartswidget.h | 5 +++ 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 79b40133a5..0fb19681e9 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -19,6 +18,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { title_label = new QLabel(); title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(title_label); + show_all_values_btn = toolbar->addAction(""); toolbar->addWidget(range_label = new QLabel()); reset_zoom_btn = toolbar->addAction("⟲"); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); @@ -26,7 +26,6 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { remove_all_btn->setToolTip(tr("Remove all charts")); dock_btn = toolbar->addAction(""); main_layout->addWidget(toolbar); - updateToolBar(); // charts QWidget *charts_container = new QWidget(this); @@ -37,14 +36,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { charts_scroll->setWidgetResizable(true); charts_scroll->setWidget(charts_container); charts_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - main_layout->addWidget(charts_scroll); + max_chart_range = settings.max_chart_x_range; use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value(); + updateToolBar(); 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(show_all_values_btn, &QAction::triggered, this, &ChartsWidget::showAllData); 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]() { @@ -58,7 +59,7 @@ void ChartsWidget::eventsMerged() { if (auto events = can->events(); events && !events->empty()) { event_range.first = (events->front()->mono_time / (double)1e9) - can->routeStartTime(); event_range.second = (events->back()->mono_time / (double)1e9) - can->routeStartTime(); - updateDisplayRange(); + updateState(); } } @@ -69,8 +70,8 @@ void ChartsWidget::updateDisplayRange() { // reached the end, or seeked to a timestamp out of range. display_range.first = current_sec - 5; } - display_range.first = std::max(display_range.first, event_range.first); - display_range.second = std::min(display_range.first + settings.max_chart_x_range, event_range.second); + display_range.first = std::floor(std::max(display_range.first, event_range.first) * 10.0) / 10.0; + display_range.second = std::floor(std::min(display_range.first + max_chart_range, event_range.second) * 10.0) / 10.0; if (prev_range != display_range) { QFutureSynchronizer future_synchronizer; for (auto c : charts) @@ -100,13 +101,29 @@ void ChartsWidget::updateState() { } const auto &range = is_zoomed ? zoomed_range : display_range; + setUpdatesEnabled(false); for (auto c : charts) { c->setDisplayRange(range.first, range.second); c->scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } + setUpdatesEnabled(true); +} + +void ChartsWidget::showAllData() { + bool switch_to_show_all = max_chart_range == settings.max_chart_x_range; + max_chart_range = switch_to_show_all ? settings.cached_segment_limit * 60 + : settings.max_chart_x_range; + max_chart_range = std::min(max_chart_range, (uint32_t)can->totalSeconds()); + updateToolBar(); + updateState(); } void ChartsWidget::updateToolBar() { + int min_range = std::min(settings.max_chart_x_range, (int)can->totalSeconds()); + bool displaying_all = max_chart_range != min_range; + show_all_values_btn->setText(tr("%1 minutes").arg(max_chart_range / 60)); + show_all_values_btn->setToolTip(tr("Click to display %1 data").arg(displaying_all ? tr("%1 minutes").arg(min_range / 60) : tr("ALL cached"))); + show_all_values_btn->setVisible(!is_zoomed); remove_all_btn->setEnabled(!charts.isEmpty()); reset_zoom_btn->setEnabled(is_zoomed); range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); @@ -232,6 +249,7 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); updateTitle(); updateSeries(sig); + updateAxisY(); } void ChartView::removeSeries(const QString &msg_id, const Signal *sig) { @@ -242,8 +260,7 @@ void ChartView::removeSeries(const QString &msg_id, const Signal *sig) { } 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(); + return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); } QList::iterator ChartView::removeSeries(const QList::iterator &it) { @@ -261,11 +278,11 @@ QList::iterator ChartView::removeSeries(const QListreplace(s.vals); } } - updateAxisY(); } // auto zoom on yaxis @@ -422,11 +437,39 @@ void ChartView::updateAxisY() { 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(); + applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05); } - QTimer::singleShot(0, this, &ChartView::adjustChartMargins); + adjustChartMargins(); +} + +void ChartView::applyNiceNumbers(qreal min, qreal max) { + int tick_count = axis_y->tickCount(); + qreal range = niceNumber((max - min), true); // range with ceiling + qreal step = niceNumber(range / (tick_count - 1), false); + min = qFloor(min / step); + max = qCeil(max / step); + tick_count = int(max - min) + 1; + axis_y->setRange(min * step, max * step); + axis_y->setTickCount(tick_count); +} + +//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n +qreal ChartView::niceNumber(qreal x, bool ceiling) { + qreal z = qPow(10, qFloor(std::log10(x))); //find corresponding number of the form of 10^n than is smaller than x + qreal q = x / z; //q<10 && q>=1; + if (ceiling) { + if (q <= 1.0) q = 1; + else if (q <= 2.0) q = 2; + else if (q <= 5.0) q = 5; + else q = 10; + } else { + if (q < 1.5) q = 1; + else if (q < 3.0) q = 2; + else if (q < 7.0) q = 5; + else q = 10; + } + return q * z; } void ChartView::leaveEvent(QEvent *event) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 3e3277c5b8..b3a4bcf2a0 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -66,6 +66,8 @@ private: void updateTitle(); void updateFromSettings(); void drawForeground(QPainter *painter, const QRectF &rect) override; + void applyNiceNumbers(qreal min, qreal max); + qreal niceNumber(qreal x, bool ceiling); QValueAxis *axis_x; QValueAxis *axis_y; @@ -102,17 +104,20 @@ private: void zoomReset(); void updateToolBar(); void removeAll(); + void showAllData(); bool eventFilter(QObject *obj, QEvent *event) override; ChartView *findChart(const QString &id, const Signal *sig); QLabel *title_label; QLabel *range_label; bool docking = true; + QAction *show_all_values_btn; QAction *dock_btn; QAction *reset_zoom_btn; QAction *remove_all_btn; QVBoxLayout *charts_layout; QList charts; + uint32_t max_chart_range = 0; bool is_zoomed = false; std::pair event_range; std::pair display_range; From c844680a70c371ad9cf15974662b9cb41d9c30bb Mon Sep 17 00:00:00 2001 From: Bruce Wayne Date: Sun, 11 Dec 2022 14:01:49 -0800 Subject: [PATCH 0492/1179] Update measured torque values for EV6 and IONIQ 5 --- selfdrive/car/torque_data/params.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 3b212c6507..eb1a04cee6 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -27,7 +27,7 @@ HONDA PILOT 2017: [1.7262026201812795, 0.9470005614967523, 0.21351430733218763] HONDA RIDGELINE 2017: [1.4146525028237624, 0.7356572861629564, 0.23307177552211328] HYUNDAI ELANTRA 2021: [3.169, 2.1259108157250735, 0.0819] HYUNDAI GENESIS 2015-2016: [1.8466226943929824, 1.5552063647830634, 0.0984484465421171] -HYUNDAI IONIQ 5 2022: [3.172929, 3.0, 0.096019] +HYUNDAI IONIQ 5 2022: [3.172929, 2.713050, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] HYUNDAI IONIQ PLUG-IN HYBRID 2019: [2.970807902012267, 1.6312321830002083, 0.1088964990357482] @@ -42,7 +42,7 @@ HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488 HYUNDAI TUCSON HYBRID 4TH GEN: [2.035545, 2.035545, 0.110272] JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185] JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003] -KIA EV6 2022: [3.2, 3.0, 0.05] +KIA EV6 2022: [3.2, 2.093457, 0.05] KIA K5 2021: [2.405339728085138, 1.460032270828705, 0.11650989850813716] KIA NIRO EV 2020: [2.9215954981365337, 2.1500583840260044, 0.09236802474810267] KIA SORENTO GT LINE 2018: [2.464854685101844, 1.5335274218367956, 0.12056170567599558] From 7548160dcdc932d1dd433d88574332c4c02be8a4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 11 Dec 2022 14:19:07 -0800 Subject: [PATCH 0493/1179] update refs for max lat accel change --- selfdrive/test/process_replay/ref_commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 57c5efd946..80385710a9 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3523d88432d661ee0d1022e9a4774f3455c832b5 +6681ca22053b019a65930e76a396535d0cddf39c \ No newline at end of file From c9b8f6457e8973adb37bb7168871b496cb76f43c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 11 Dec 2022 14:19:53 -0800 Subject: [PATCH 0494/1179] EV6 blinkers (#26618) * right blink * left blink * rm debug * just the support code * revert panda * behind flag --- opendbc | 2 +- selfdrive/car/hyundai/carcontroller.py | 9 +++++++++ selfdrive/car/hyundai/hyundaicanfd.py | 20 +++++++++++++++++++- selfdrive/car/hyundai/interface.py | 4 ++++ selfdrive/car/hyundai/values.py | 2 ++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index 94fff4782b..1f8aa057bc 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 94fff4782be263efad10032a612b3c96a120c0b7 +Subproject commit 1f8aa057bc1c96fcf8a2b612a9897ce91e627381 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 2f95a29e7b..ebb67b0e2e 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -83,11 +83,16 @@ class CarController: # tester present - w/ no response (keeps relevant ECU disabled) if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl: + # for longitudinal control, either radar or ADAS driving ECU addr, bus = 0x7d0, 0 if self.CP.flags & HyundaiFlags.CANFD_HDA2.value: addr, bus = 0x730, 5 can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus]) + # for blinkers + if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS: + can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 5]) + # >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: @@ -118,6 +123,10 @@ class CarController: if self.frame % 5 == 0 and (not hda2 or hda2_long): can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CP, CC.enabled)) + # blinkers + if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS: + can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.frame, False, False)) + if self.CP.openpilotLongitudinalControl: if hda2: can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.frame)) diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index 8b53e7c378..c492e6a5ff 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -1,7 +1,6 @@ from common.numpy_fast import clip from selfdrive.car.hyundai.values import HyundaiFlags - def get_e_can_bus(CP): # On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars # have a different harness than the HDA1 and non-HDA variants in order to split @@ -98,6 +97,25 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove return packer.make_can_msg("SCC_CONTROL", get_e_can_bus(CP), values) +def create_spas_messages(packer, frame, left_blink, right_blink): + ret = [] + + values = { + } + ret.append(packer.make_can_msg("SPAS1", 5, values)) + + blink = 0 + if left_blink: + blink = 3 + elif right_blink: + blink = 4 + values = { + "BLINKER_CONTROL": blink, + } + ret.append(packer.make_can_msg("SPAS2", 5, values)) + + return ret + def create_adrv_messages(packer, frame): # messages needed to car happy after disabling diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index b9f6b8fc58..e271dc0e7d 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -287,6 +287,10 @@ class CarInterface(CarInterfaceBase): addr, bus = 0x730, 5 disable_ecu(logcan, sendcan, bus=bus, addr=addr, com_cont_req=b'\x28\x83\x01') + # for blinkers + if CP.flags & HyundaiFlags.ENABLE_BLINKERS: + disable_ecu(logcan, sendcan, bus=5, addr=0x7B1, com_cont_req=b'\x28\x83\x01') + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index ac441219b2..41b6a58eca 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -58,6 +58,8 @@ class HyundaiFlags(IntFlag): ALT_LIMITS = 16 + ENABLE_BLINKERS = 32 + class CAR: # Hyundai From 4e3598c9f60e16bc48cbbb3152d74a5d89bebbea Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 12 Dec 2022 07:00:58 +0800 Subject: [PATCH 0495/1179] Cabana: use opengl to draw the line series. (#26761) --- tools/cabana/chartswidget.cc | 57 ++++++++++++++++-------------------- tools/cabana/chartswidget.h | 8 +---- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 0fb19681e9..b177bb0b81 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include // ChartsWidget @@ -196,15 +197,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->layout()->setContentsMargins(0, 0, 0, 0); chart->setMargins(QMargins(20, 11, 11, 11)); - track_line = new QGraphicsLineItem(chart); - track_line->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); - track_ellipse = new QGraphicsEllipseItem(chart); - track_ellipse->setBrush(Qt::darkGray); - value_text = new QGraphicsTextItem(chart); - item_group = scene()->createItemGroup({track_line, track_ellipse, value_text}); - item_group->setZValue(chart->zValue() + 10); - - // title QToolButton *remove_btn = new QToolButton(); remove_btn->setText("X"); remove_btn->setAutoRaise(true); @@ -242,6 +234,7 @@ ChartView::~ChartView() { void ChartView::addSeries(const QString &msg_id, const Signal *sig) { QLineSeries *series = new QLineSeries(this); + series->setUseOpenGL(true); chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); @@ -454,7 +447,7 @@ void ChartView::applyNiceNumbers(qreal min, qreal max) { axis_y->setTickCount(tick_count); } -//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n +// nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n qreal ChartView::niceNumber(qreal x, bool ceiling) { qreal z = qPow(10, qFloor(std::log10(x))); //find corresponding number of the form of 10^n than is smaller than x qreal q = x / z; //q<10 && q>=1; @@ -473,7 +466,8 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) { } void ChartView::leaveEvent(QEvent *event) { - item_group->setVisible(false); + track_pt = {0, 0}; + scene()->update(); QChartView::leaveEvent(event); } @@ -504,10 +498,9 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); const auto plot_area = chart()->plotArea(); - + track_pt = {0, 0}; if (!is_zooming && plot_area.contains(ev->pos())) { QStringList text_list; - QPointF pos = {}; const double sec = chart()->mapToValue(ev->pos()).x(); for (auto &s : sigs) { QString value = "--"; @@ -516,35 +509,35 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (it != s.vals.rend() && it->x() >= axis_x->min()) { value = QString::number(it->y()); auto value_pos = chart()->mapToPosition(*it); - if (value_pos.x() > pos.x()) pos = value_pos; + if (value_pos.x() > track_pt.x()) track_pt = value_pos; } text_list.push_back(QString(" %1 : %2 ").arg(sigs.size() > 1 ? s.sig->name.c_str() : "Value").arg(value)); } - if (pos.x() == 0) pos = ev->pos(); - - QString time = QString::number(chart()->mapToValue(pos).x(), 'f', 3); - value_text->setHtml(QString("
 Time: %1  
%2
") - .arg(time).arg(text_list.join("
"))); - - QRectF text_rect = value_text->boundingRect(); - int text_x = pos.x() + 8; - if ((text_x + text_rect.width()) > plot_area.right()) { - text_x = pos.x() - text_rect.width() - 8; - } - value_text->setPos(text_x, pos.y() - text_rect.height() / 2); - track_line->setLine(pos.x(), plot_area.top(), pos.x(), plot_area.bottom()); - track_ellipse->setRect(pos.x() - 5, pos.y() - 5, 10, 10); - item_group->setVisible(true); + if (track_pt.x() == 0) track_pt = ev->pos(); + QString text = QString("
 Time: %1  
%2
") + .arg(chart()->mapToValue(track_pt).x(), 0, 'f', 3) + .arg(text_list.join("
")); + QPoint pt((int)track_pt.x() + 20, plot_area.top() - 20); + QToolTip::showText(mapToGlobal(pt), text, this, plot_area.toRect()); + scene()->update(); } else { - item_group->setVisible(false); + QToolTip::hideText(); } QChartView::mouseMoveEvent(ev); } void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { qreal x = chart()->mapToPosition(QPointF{can->currentSec(), 0}).x(); + qreal y1 = chart()->plotArea().top() - 2; + qreal y2 = chart()->plotArea().bottom() + 2; painter->setPen(QPen(chart()->titleBrush().color(), 2)); - painter->drawLine(QPointF{x, chart()->plotArea().top() - 2}, QPointF{x, chart()->plotArea().bottom() + 2}); + painter->drawLine(QPointF{x, y1}, QPointF{x, y2}); + if (!track_pt.isNull()) { + painter->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); + painter->drawLine(QPointF{track_pt.x(), y1}, QPointF{track_pt.x(), y2}); + painter->setBrush(Qt::darkGray); + painter->drawEllipse(track_pt, 5, 5); + } } // SeriesSelector @@ -613,7 +606,7 @@ void SeriesSelector::addSignal(QListWidgetItem *item) { addSeries(data[0], data[1], data[2]); } -void SeriesSelector::addSeries(const QString &id, const QString& msg_name, const QString &sig_name) { +void SeriesSelector::addSeries(const QString &id, const QString &msg_name, const QString &sig_name) { QStringList data({id, msg_name, sig_name}); for (int i = 0; i < chart_series->count(); ++i) { if (chart_series->item(i)->data(Qt::UserRole).toStringList() == data) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index b3a4bcf2a0..3f9cf877a9 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -4,10 +4,7 @@ #include #include #include -#include -#include #include -#include #include #include #include @@ -71,10 +68,7 @@ private: QValueAxis *axis_x; QValueAxis *axis_y; - QGraphicsItemGroup *item_group; - QGraphicsLineItem *track_line; - QGraphicsEllipseItem *track_ellipse; - QGraphicsTextItem *value_text; + QPointF track_pt; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; std::pair events_range = {0, 0}; From 160c9ba1d24c8f5190708dd79bd2682fdadcd736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sun, 11 Dec 2022 15:25:36 -0800 Subject: [PATCH 0496/1179] Navmodel and driving style: update runner (#26762) * Navmodel and driving style: update runner * No driving style yet * thneedrunner without extra inputs * nav feature ref --- selfdrive/modeld/modeld.cc | 5 +++- selfdrive/modeld/models/driving.cc | 19 ++++++++++++++- selfdrive/modeld/models/driving.h | 10 +++++++- selfdrive/modeld/models/nav.cc | 12 +++++----- selfdrive/modeld/models/nav.h | 23 +++---------------- selfdrive/modeld/models/navmodel.onnx | 4 ++-- selfdrive/modeld/models/navmodel_q.dlc | 4 ++-- selfdrive/modeld/runners/onnxmodel.cc | 18 ++++++++++++++- selfdrive/modeld/runners/onnxmodel.h | 6 +++++ selfdrive/modeld/runners/runmodel.h | 2 ++ selfdrive/modeld/runners/snpemodel.cc | 10 ++++++++ selfdrive/modeld/runners/snpemodel.h | 6 +++++ selfdrive/modeld/runners/thneedmodel.cc | 8 +++++++ selfdrive/modeld/runners/thneedmodel.h | 4 ++++ selfdrive/navd/map_renderer.cc | 10 ++++---- .../process_replay/model_replay_ref_commit | 2 +- 16 files changed, 104 insertions(+), 39 deletions(-) diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index cfc71a0e27..0a8a8d6358 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -15,6 +15,7 @@ #include "common/util.h" #include "system/hardware/hw.h" #include "selfdrive/modeld/models/driving.h" +#include "selfdrive/modeld/models/nav.h" ExitHandler do_exit; @@ -72,6 +73,8 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcCl mat3 model_transform_main = {}; mat3 model_transform_extra = {}; bool live_calib_seen = false; + float driving_style[DRIVING_STYLE_LEN] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; + float nav_features[NAV_FEATURE_LEN] = {0}; VisionBuf *buf_main = nullptr; VisionBuf *buf_extra = nullptr; @@ -151,7 +154,7 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcCl } double mt1 = millis_since_boot(); - ModelOutput *model_output = model_eval_frame(&model, buf_main, buf_extra, model_transform_main, model_transform_extra, vec_desire, is_rhd, prepare_only); + ModelOutput *model_output = model_eval_frame(&model, buf_main, buf_extra, model_transform_main, model_transform_extra, vec_desire, is_rhd, driving_style, nav_features, prepare_only); double mt2 = millis_since_boot(); float model_execution_time = (mt2 - mt1) / 1000.0; diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 9cb216ff19..ac101bfee7 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -46,10 +46,19 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context) { #ifdef TRAFFIC_CONVENTION s->m->addTrafficConvention(s->traffic_convention, TRAFFIC_CONVENTION_LEN); #endif + +#ifdef DRIVING_STYLE + s->m->addDrivingStyle(s->driving_style, DRIVING_STYLE_LEN); +#endif + +#ifdef NAV + s->m->addNavFeatures(s->nav_features, NAV_FEATURE_LEN); +#endif + } ModelOutput* model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* wbuf, - const mat3 &transform, const mat3 &transform_wide, float *desire_in, bool is_rhd, bool prepare_only) { + const mat3 &transform, const mat3 &transform_wide, float *desire_in, bool is_rhd, float *driving_style, float *nav_features, bool prepare_only) { #ifdef DESIRE std::memmove(&s->pulse_desire[0], &s->pulse_desire[DESIRE_LEN], sizeof(float) * DESIRE_LEN*HISTORY_BUFFER_LEN); if (desire_in != NULL) { @@ -67,6 +76,14 @@ ModelOutput* model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* wbuf, LOGT("Desire enqueued"); #endif +#ifdef NAV + std::memcpy(s->nav_features, nav_features, sizeof(float)*NAV_FEATURE_LEN); +#endif + +#ifdef DRIVING_STYLE + std::memcpy(s->driving_style, driving_style, sizeof(float)*DRIVING_STYLE_LEN); +#endif + int rhd_idx = is_rhd; s->traffic_convention[rhd_idx] = 1.0; s->traffic_convention[1-rhd_idx] = 0.0; diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index b23691a56a..5734c68cb9 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -14,6 +14,7 @@ #include "common/modeldata.h" #include "common/util.h" #include "selfdrive/modeld/models/commonmodel.h" +#include "selfdrive/modeld/models/nav.h" #include "selfdrive/modeld/runners/run.h" constexpr int FEATURE_LEN = 128; @@ -21,6 +22,7 @@ constexpr int HISTORY_BUFFER_LEN = 99; constexpr int DESIRE_LEN = 8; constexpr int DESIRE_PRED_LEN = 4; constexpr int TRAFFIC_CONVENTION_LEN = 2; +constexpr int DRIVING_STYLE_LEN = 12; constexpr int MODEL_FREQ = 20; constexpr int DISENGAGE_LEN = 5; @@ -259,11 +261,17 @@ struct ModelState { #ifdef TRAFFIC_CONVENTION float traffic_convention[TRAFFIC_CONVENTION_LEN] = {}; #endif +#ifdef DRIVING_STYLE + float driving_style[DRIVING_STYLE_LEN] = {}; +#endif +#ifdef NAV + float nav_features[NAV_FEATURE_LEN] = {}; +#endif }; void model_init(ModelState* s, cl_device_id device_id, cl_context context); ModelOutput *model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* buf_wide, - const mat3 &transform, const mat3 &transform_wide, float *desire_in, bool is_rhd, bool prepare_only); + const mat3 &transform, const mat3 &transform_wide, float *desire_in, bool is_rhd, float *driving_style, float *nav_features, bool prepare_only); void model_free(ModelState* s); void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_frame_id_extra, uint32_t frame_id, float frame_drop, const ModelOutput &net_outputs, uint64_t timestamp_eof, diff --git a/selfdrive/modeld/models/nav.cc b/selfdrive/modeld/models/nav.cc index dae87c7ce5..861795e172 100644 --- a/selfdrive/modeld/models/nav.cc +++ b/selfdrive/modeld/models/nav.cc @@ -9,11 +9,11 @@ void navmodel_init(NavModelState* s) { -#ifdef USE_ONNX_MODEL - s->m = new ONNXModel("models/navmodel.onnx", &s->output[0], NAV_NET_OUTPUT_SIZE, USE_DSP_RUNTIME, false, true); -#else - s->m = new SNPEModel("models/navmodel_q.dlc", &s->output[0], NAV_NET_OUTPUT_SIZE, USE_DSP_RUNTIME, false, true); -#endif + #ifdef USE_ONNX_MODEL + s->m = new ONNXModel("models/navmodel.onnx", &s->output[0], NAV_NET_OUTPUT_SIZE, USE_DSP_RUNTIME, false, true); + #else + s->m = new SNPEModel("models/navmodel_q.dlc", &s->output[0], NAV_NET_OUTPUT_SIZE, USE_DSP_RUNTIME, false, true); + #endif } NavModelResult* navmodel_eval_frame(NavModelState* s, VisionBuf* buf) { @@ -56,7 +56,7 @@ void navmodel_publish(PubMaster &pm, uint32_t frame_id, const NavModelResult &mo framed.setDspExecutionTime(model_res.dsp_execution_time); framed.setFeatures(to_kj_array_ptr(model_res.features.values)); framed.setDesirePrediction(to_kj_array_ptr(model_res.desire_pred.values)); - fill_plan(framed, model_res.plans.get_best_prediction()); + fill_plan(framed, model_res.plan); pm.send("navModel", msg); } diff --git a/selfdrive/modeld/models/nav.h b/selfdrive/modeld/models/nav.h index b469f75987..b2955ad2c5 100644 --- a/selfdrive/modeld/models/nav.h +++ b/selfdrive/modeld/models/nav.h @@ -10,7 +10,6 @@ constexpr int NAV_INPUT_SIZE = 256*256; constexpr int NAV_FEATURE_LEN = 64; constexpr int NAV_DESIRE_LEN = 32; -constexpr int NAV_PLAN_MHP_N = 5; struct NavModelOutputXY { float x; @@ -21,24 +20,8 @@ static_assert(sizeof(NavModelOutputXY) == sizeof(float)*2); struct NavModelOutputPlan { std::array mean; std::array std; - float prob; }; -static_assert(sizeof(NavModelOutputPlan) == sizeof(NavModelOutputXY)*TRAJECTORY_SIZE*2 + sizeof(float)); - -struct NavModelOutputPlans { - std::array predictions; - - constexpr const NavModelOutputPlan &get_best_prediction() const { - int max_idx = 0; - for (int i = 1; i < predictions.size(); i++) { - if (predictions[i].prob > predictions[max_idx].prob) { - max_idx = i; - } - } - return predictions[max_idx]; - } -}; -static_assert(sizeof(NavModelOutputPlans) == sizeof(NavModelOutputPlan)*NAV_PLAN_MHP_N); +static_assert(sizeof(NavModelOutputPlan) == sizeof(NavModelOutputXY)*TRAJECTORY_SIZE*2); struct NavModelOutputDesirePrediction { std::array values; @@ -51,12 +34,12 @@ struct NavModelOutputFeatures { static_assert(sizeof(NavModelOutputFeatures) == sizeof(float)*NAV_FEATURE_LEN); struct NavModelResult { - const NavModelOutputPlans plans; + const NavModelOutputPlan plan; const NavModelOutputDesirePrediction desire_pred; const NavModelOutputFeatures features; float dsp_execution_time; }; -static_assert(sizeof(NavModelResult) == sizeof(NavModelOutputPlans) + sizeof(NavModelOutputDesirePrediction) + sizeof(NavModelOutputFeatures) + sizeof(float)); +static_assert(sizeof(NavModelResult) == sizeof(NavModelOutputPlan) + sizeof(NavModelOutputDesirePrediction) + sizeof(NavModelOutputFeatures) + sizeof(float)); constexpr int NAV_OUTPUT_SIZE = sizeof(NavModelResult) / sizeof(float); constexpr int NAV_NET_OUTPUT_SIZE = NAV_OUTPUT_SIZE - 1; diff --git a/selfdrive/modeld/models/navmodel.onnx b/selfdrive/modeld/models/navmodel.onnx index 60dd8c0e7f..397b8d90e2 100644 --- a/selfdrive/modeld/models/navmodel.onnx +++ b/selfdrive/modeld/models/navmodel.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eab4b986e14d7d842d6d5487011c329d356fb56995b2ae7dc7188aefe6df9d97 -size 12285002 +oid sha256:9028b36a591763724e95205b48f37f09260b4434fb1f3c6f228db1710a401aa8 +size 12258591 diff --git a/selfdrive/modeld/models/navmodel_q.dlc b/selfdrive/modeld/models/navmodel_q.dlc index 7d9b36ed4d..984cf0a553 100644 --- a/selfdrive/modeld/models/navmodel_q.dlc +++ b/selfdrive/modeld/models/navmodel_q.dlc @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83d53efc40053b02fe7d3da4ef6213a4a5a1ae4d1bd49c121b9beb6a54ea1148 -size 3154868 +oid sha256:bc7ade56bb4f9525c84a46df22252ea1e321a0518cbcef8bdfc76ccd8ad10b41 +size 3154304 diff --git a/selfdrive/modeld/runners/onnxmodel.cc b/selfdrive/modeld/runners/onnxmodel.cc index 447d90fd7e..5616a6c9c7 100644 --- a/selfdrive/modeld/runners/onnxmodel.cc +++ b/selfdrive/modeld/runners/onnxmodel.cc @@ -97,6 +97,16 @@ void ONNXModel::addDesire(float *state, int state_size) { desire_state_size = state_size; } +void ONNXModel::addNavFeatures(float *state, int state_size) { + nav_features_input_buf = state; + nav_features_size = state_size; +} + +void ONNXModel::addDrivingStyle(float *state, int state_size) { + driving_style_input_buf = state; + driving_style_size = state_size; +} + void ONNXModel::addTrafficConvention(float *state, int state_size) { traffic_convention_input_buf = state; traffic_convention_size = state_size; @@ -128,7 +138,13 @@ void ONNXModel::execute() { if (desire_input_buf != NULL) { pwrite(desire_input_buf, desire_state_size); } - if (traffic_convention_input_buf != NULL) { + if (nav_features_input_buf != NULL) { + pwrite(nav_features_input_buf, nav_features_size); + } + if (driving_style_input_buf != NULL) { + pwrite(driving_style_input_buf, driving_style_size); + } + if (traffic_convention_input_buf != NULL) { pwrite(traffic_convention_input_buf, traffic_convention_size); } if (calib_input_buf != NULL) { diff --git a/selfdrive/modeld/runners/onnxmodel.h b/selfdrive/modeld/runners/onnxmodel.h index d5b7bfecf0..9990bf1b45 100644 --- a/selfdrive/modeld/runners/onnxmodel.h +++ b/selfdrive/modeld/runners/onnxmodel.h @@ -10,6 +10,8 @@ public: ~ONNXModel(); void addRecurrent(float *state, int state_size); void addDesire(float *state, int state_size); + void addNavFeatures(float *state, int state_size); + void addDrivingStyle(float *state, int state_size); void addTrafficConvention(float *state, int state_size); void addCalib(float *state, int state_size); void addImage(float *image_buf, int buf_size); @@ -25,6 +27,10 @@ private: int rnn_state_size; float *desire_input_buf = NULL; int desire_state_size; + float *nav_features_input_buf = NULL; + int nav_features_size; + float *driving_style_input_buf = NULL; + int driving_style_size; float *traffic_convention_input_buf = NULL; int traffic_convention_size; float *calib_input_buf = NULL; diff --git a/selfdrive/modeld/runners/runmodel.h b/selfdrive/modeld/runners/runmodel.h index c607811401..673ddb50b5 100644 --- a/selfdrive/modeld/runners/runmodel.h +++ b/selfdrive/modeld/runners/runmodel.h @@ -5,6 +5,8 @@ public: virtual ~RunModel() {} virtual void addRecurrent(float *state, int state_size) {} virtual void addDesire(float *state, int state_size) {} + virtual void addNavFeatures(float *state, int state_size) {} + virtual void addDrivingStyle(float *state, int state_size) {} virtual void addTrafficConvention(float *state, int state_size) {} virtual void addCalib(float *state, int state_size) {} virtual void addImage(float *image_buf, int buf_size) {} diff --git a/selfdrive/modeld/runners/snpemodel.cc b/selfdrive/modeld/runners/snpemodel.cc index ff4adcd8d3..609a7a6657 100644 --- a/selfdrive/modeld/runners/snpemodel.cc +++ b/selfdrive/modeld/runners/snpemodel.cc @@ -153,6 +153,16 @@ void SNPEModel::addDesire(float *state, int state_size) { desireBuffer = this->addExtra(state, state_size, 1); } +void SNPEModel::addNavFeatures(float *state, int state_size) { + navFeatures = state; + navFeaturesBuffer = this->addExtra(state, state_size, 1); +} + +void SNPEModel::addDrivingStyle(float *state, int state_size) { + drivingStyle = state; + drivingStyleBuffer = this->addExtra(state, state_size, 2); +} + void SNPEModel::addCalib(float *state, int state_size) { calib = state; calibBuffer = this->addExtra(state, state_size, 1); diff --git a/selfdrive/modeld/runners/snpemodel.h b/selfdrive/modeld/runners/snpemodel.h index 08ae16c2b1..0d84d1d482 100644 --- a/selfdrive/modeld/runners/snpemodel.h +++ b/selfdrive/modeld/runners/snpemodel.h @@ -28,6 +28,8 @@ public: void addTrafficConvention(float *state, int state_size); void addCalib(float *state, int state_size); void addDesire(float *state, int state_size); + void addDrivingStyle(float *state, int state_size); + void addNavFeatures(float *state, int state_size); void addImage(float *image_buf, int buf_size); void addExtra(float *image_buf, int buf_size); void execute(); @@ -75,6 +77,10 @@ private: std::unique_ptr trafficConventionBuffer; float *desire; std::unique_ptr desireBuffer; + float *navFeatures; + std::unique_ptr navFeaturesBuffer; + float *drivingStyle; + std::unique_ptr drivingStyleBuffer; float *calib; std::unique_ptr calibBuffer; }; diff --git a/selfdrive/modeld/runners/thneedmodel.cc b/selfdrive/modeld/runners/thneedmodel.cc index 67db01bb95..4fdd7ca466 100644 --- a/selfdrive/modeld/runners/thneedmodel.cc +++ b/selfdrive/modeld/runners/thneedmodel.cc @@ -24,6 +24,14 @@ void ThneedModel::addDesire(float *state, int state_size) { desire = state; } +void ThneedModel::addDrivingStyle(float *state, int state_size) { + drivingStyle = state; +} + +void ThneedModel::addNavFeatures(float *state, int state_size) { + navFeatures = state; +} + void ThneedModel::addImage(float *image_input_buf, int buf_size) { input = image_input_buf; } diff --git a/selfdrive/modeld/runners/thneedmodel.h b/selfdrive/modeld/runners/thneedmodel.h index f3f34dc7f4..63712f1d00 100644 --- a/selfdrive/modeld/runners/thneedmodel.h +++ b/selfdrive/modeld/runners/thneedmodel.h @@ -9,6 +9,8 @@ public: void addRecurrent(float *state, int state_size); void addTrafficConvention(float *state, int state_size); void addDesire(float *state, int state_size); + void addNavFeatures(float *state, int state_size); + void addDrivingStyle(float *state, int state_size); void addImage(float *image_buf, int buf_size); void addExtra(float *image_buf, int buf_size); void execute(); @@ -26,6 +28,8 @@ private: // recurrent and desire float *recurrent; float *trafficConvention; + float *drivingStyle; float *desire; + float *navFeatures; }; diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 0fed108045..91f31d06dc 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -70,7 +70,7 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set if (online) { vipc_server.reset(new VisionIpcServer("navd")); - vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH, HEIGHT); + vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH/2, HEIGHT/2); vipc_server->start_listener(); pm.reset(new PubMaster({"navThumbnail", "mapRenderState"})); @@ -177,10 +177,12 @@ void MapRenderer::publish(const double render_time) { uint8_t* dst = (uint8_t*)buf->addr; uint8_t* src = cap.bits(); - // RGB to greyscale + // RGB to greyscale and crop memset(dst, 128, buf->len); - for (int i = 0; i < WIDTH * HEIGHT; i++) { - dst[i] = src[i * 3]; + for (int r = 0; r < HEIGHT/2; r++) { + for (int c = 0; c < WIDTH/2; c++) { + dst[r*WIDTH/2 + c] = src[((HEIGHT/4 + r)*WIDTH + (c+WIDTH/4)) * 3]; + } } vipc_server->send(buf, &extra); diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 4dcf0ecbb7..aa204e0f8a 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -30dfeed50ac562f99b0aad985bd6b0e6d8188fcb \ No newline at end of file +4ff972367fdb9546be68ee0ba0d45cf4f839dae7 From fd91ab6469506ee2afe5db3c8b718433bc9317c6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 02:25:23 +0800 Subject: [PATCH 0497/1179] Cabana: fix "show plot" button state sync issue (#26769) --- tools/cabana/chartswidget.cc | 24 +++++++++++++----------- tools/cabana/chartswidget.h | 9 ++++----- tools/cabana/detailwidget.cc | 10 ++++------ tools/cabana/detailwidget.h | 2 +- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index b177bb0b81..b0e6a2a164 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -152,12 +152,12 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo 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); + QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); + QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); charts_layout->insertWidget(0, chart); charts.push_back(chart); } chart->addSeries(id, sig); - emit chartOpened(id, sig); } else if (ChartView *chart = findChart(id, sig)) { chart->removeSeries(id, sig); } @@ -169,11 +169,16 @@ void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); updateToolBar(); + emit seriesChanged(); } void ChartsWidget::removeAll() { - for (auto c : charts.toVector()) - removeChart(c); + for (auto c : charts) { + c->deleteLater(); + } + charts.clear(); + updateToolBar(); + emit seriesChanged(); } bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { @@ -227,11 +232,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(manage_btn, &QToolButton::clicked, this, &ChartView::manageSeries); } -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); series->setUseOpenGL(true); @@ -243,6 +243,7 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { updateTitle(); updateSeries(sig); updateAxisY(); + emit seriesAdded(msg_id, sig); } void ChartView::removeSeries(const QString &msg_id, const Signal *sig) { @@ -259,9 +260,10 @@ bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { QList::iterator ChartView::removeSeries(const QList::iterator &it) { chart()->removeSeries(it->series); it->series->deleteLater(); - emit seriesRemoved(it->msg_id, it->sig); - + QString msg_id = it->msg_id; + const Signal *sig = it->sig; auto ret = sigs.erase(it); + emit seriesRemoved(msg_id, sig); if (!sigs.isEmpty()) { updateAxisY(); } else { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 3f9cf877a9..1799a25488 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -20,7 +20,6 @@ class ChartView : public QChartView { public: 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; @@ -41,6 +40,7 @@ public: signals: void seriesRemoved(const QString &id, const Signal *sig); + void seriesAdded(const QString &id, const Signal *sig); void zoomIn(double min, double max); void zoomReset(); void remove(); @@ -81,16 +81,15 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); void showChart(const QString &id, const Signal *sig, bool show, bool merge); - void removeChart(ChartView *chart); - inline bool isChartOpened(const QString &id, const Signal *sig) { return findChart(id, sig) != nullptr; } + inline bool hasSignal(const QString &id, const Signal *sig) { return findChart(id, sig) != nullptr; } signals: void dock(bool floating); void rangeChanged(double min, double max, bool is_zommed); - void chartOpened(const QString &id, const Signal *sig); - void chartClosed(const QString &id, const Signal *sig); + void seriesChanged(); private: + void removeChart(ChartView *chart); void eventsMerged(); void updateState(); void updateDisplayRange(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index cd1057f7e1..77302b7d38 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -107,8 +107,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart } }); QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); - QObject::connect(charts, &ChartsWidget::chartOpened, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, true); }); - QObject::connect(charts, &ChartsWidget::chartClosed, [this](const QString &id, const Signal *sig) { updateChartState(id, sig, false); }); + QObject::connect(charts, &ChartsWidget::seriesChanged, this, &DetailWidget::updateChartState); QObject::connect(undo_stack, &QUndoStack::indexChanged, [this]() { if (undo_stack->count() > 0) dbcMsgChanged(); @@ -169,7 +168,7 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { signal_list.push_back(form); } form->setSignal(msg_id, sig); - form->setChartOpened(charts->isChartOpened(msg_id, sig)); + form->setChartOpened(charts->hasSignal(msg_id, sig)); ++i; } if (msg->size != can->lastMessage(msg_id).dat.size()) @@ -212,9 +211,9 @@ void DetailWidget::showForm(const Signal *sig) { setUpdatesEnabled(true); } -void DetailWidget::updateChartState(const QString &id, const Signal *sig, bool opened) { +void DetailWidget::updateChartState() { for (auto f : signal_list) - if (f->msg_id == id && f->sig == sig) f->setChartOpened(opened); + f->setChartOpened(charts->hasSignal(f->msg_id, f->sig)); } void DetailWidget::editMsg() { @@ -334,4 +333,3 @@ WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { setStyleSheet("QLabel{color:darkGray;}"); } - diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 91127c9b74..d90438cab2 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -35,7 +35,7 @@ public: private: void showForm(const Signal *sig); - void updateChartState(const QString &id, const Signal *sig, bool opened); + void updateChartState(); void showTabBarContextMenu(const QPoint &pt); void addSignal(int start_bit, int size, bool little_endian); void resizeSignal(const Signal *sig, int from, int to); From 881c15c2a62135f62cb58c7f317f36365b6e643c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 02:25:49 +0800 Subject: [PATCH 0498/1179] Replay: fix possible segfault on exit (#26768) --- tools/replay/replay.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 339e688be1..33541aeb74 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -51,9 +51,9 @@ void Replay::stop() { stream_thread_->wait(); stream_thread_ = nullptr; } - segments_.clear(); camera_server_.reset(nullptr); timeline_future.waitForFinished(); + segments_.clear(); rInfo("shutdown: done"); } From f9599529720e1168eedcfe3594c2ec2501aaf9dd Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Dec 2022 12:56:33 -0800 Subject: [PATCH 0499/1179] nav: build map renderer python lib by default (#26770) Co-authored-by: Comma Device --- selfdrive/navd/SConscript | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript index b10684eef3..8a2c2a8a91 100644 --- a/selfdrive/navd/SConscript +++ b/selfdrive/navd/SConscript @@ -18,5 +18,4 @@ if arch in ['larch64', 'x86_64']: nav_src = ["main.cc", "map_renderer.cc"] qt_env.Program("map_renderer", nav_src, LIBS=qt_libs + ['common', 'json11']) - if GetOption('extras'): - qt_env.SharedLibrary("map_renderer", ["map_renderer.cc"], LIBS=qt_libs + ['common', 'messaging']) + qt_env.SharedLibrary("map_renderer", ["map_renderer.cc"], LIBS=qt_libs + ['common', 'messaging']) From 151e0d8c39234f44e00ecf69fcd0cbe01b2b910c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Dec 2022 14:03:09 -0800 Subject: [PATCH 0500/1179] controlsd: add blinkers to carControl (#26773) * controlsd: add blinkers to carControl * not actuators * update refs --- cereal | 2 +- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/controls/controlsd.py | 5 +++++ selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 439429cad4..22b1431132 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 439429cad4d1e2ab874520cb5d4db8b8d978cbde +Subproject commit 22b1431132b038253a24ab3fbbe3af36ef93b95b diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index ebb67b0e2e..5582499f25 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -125,7 +125,7 @@ class CarController: # blinkers if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS: - can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.frame, False, False)) + can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.frame, CC.leftBlinker, CC.rightBlinker)) if self.CP.openpilotLongitudinalControl: if hda2: diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 59b6b6c6a0..36f0b559c2 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -577,6 +577,11 @@ class Controls: actuators = CC.actuators actuators.longControlState = self.LoC.long_control_state + # Enable blinkers while lane changing + if self.sm['lateralPlan'].laneChangeState != LaneChangeState.off: + CC.leftBlinker = self.sm['lateralPlan'].laneChangeDirection == LaneChangeDirection.left + CC.rightBlinker = self.sm['lateralPlan'].laneChangeDirection == LaneChangeDirection.right + if CS.leftBlinker or CS.rightBlinker: self.last_blinker_frame = self.sm.frame diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 80385710a9..3f54203f97 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -6681ca22053b019a65930e76a396535d0cddf39c \ No newline at end of file +99e9481d03e18a4dcd1eeebbfb24aca1ceb7e1e1 \ No newline at end of file From b1009c7f7d8bebd2d88867f52e792b39904dbff4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 06:44:04 +0800 Subject: [PATCH 0501/1179] ui: stop vipc thread before the DriverViewWindow is hidden (#26738) --- selfdrive/ui/qt/offroad/driverview.cc | 2 +- selfdrive/ui/qt/widgets/cameraview.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc index 1377bb3b23..2f366a9b38 100644 --- a/selfdrive/ui/qt/offroad/driverview.cc +++ b/selfdrive/ui/qt/offroad/driverview.cc @@ -22,6 +22,7 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) { } void DriverViewWindow::mouseReleaseEvent(QMouseEvent* e) { + cameraView->stopVipcThread(); emit done(); } @@ -35,7 +36,6 @@ void DriverViewScene::showEvent(QShowEvent* event) { } void DriverViewScene::hideEvent(QHideEvent* event) { - // TODO: stop vipc thread ? params.putBool("IsDriverViewEnabled", false); } diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index 7cc3847f99..f8b97be03e 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -35,6 +35,7 @@ public: void setFrameId(int frame_id) { draw_frame_id = frame_id; } void setStreamType(VisionStreamType type) { requested_stream_type = type; } VisionStreamType getStreamType() { return active_stream_type; } + void stopVipcThread(); signals: void clicked(); @@ -51,7 +52,6 @@ protected: void updateCalibration(const mat3 &calib); void vipcThread(); void clearFrames(); - void stopVipcThread(); bool zoomed_view; GLuint frame_vao, frame_vbo, frame_ibo; From 0d8254e95935f27d7c371ecc4c2d6c9ff8c204d0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 06:47:27 +0800 Subject: [PATCH 0502/1179] common: add new class OpenPilotPrefix (#26753) * new class OpenPilotPrefix * move random_string to util * rename file * style Co-authored-by: Adeeb Shihadeh --- common/prefix.h | 34 ++++++++++++++++++++++++++++++++++ common/util.cc | 13 +++++++++++++ common/util.h | 1 + release/files_common | 1 + tools/cabana/cabana.cc | 12 ++---------- 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 common/prefix.h diff --git a/common/prefix.h b/common/prefix.h new file mode 100644 index 0000000000..f5abe14b2b --- /dev/null +++ b/common/prefix.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "common/params.h" +#include "common/util.h" + +class OpenpilotPrefix { +public: + OpenpilotPrefix(std::string prefix = {}) { + if (prefix.empty()) { + prefix = util::random_string(15); + } + msgq_path = "/dev/shm/" + prefix; + bool ret = util::create_directories(msgq_path, 0777); + assert(ret); + setenv("OPENPILOT_PREFIX", prefix.c_str(), 1); + } + + ~OpenpilotPrefix() { + auto param_path = Params().getParamPath(); + if (util::file_exists(param_path)) { + std::string real_path = util::readlink(param_path); + system(util::string_format("rm %s -rf", real_path.c_str()).c_str()); + unlink(param_path.c_str()); + } + system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str()); + unsetenv("OPENPILOT_PREFIX"); + } + +private: + std::string msgq_path; +}; diff --git a/common/util.cc b/common/util.cc index 010fe8a11a..10dff6a9ea 100644 --- a/common/util.cc +++ b/common/util.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #ifdef __linux__ @@ -228,6 +229,18 @@ std::string hexdump(const uint8_t* in, const size_t size) { return ss.str(); } +std::string random_string(std::string::size_type length) { + const char* chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::mt19937 rg{std::random_device{}()}; + std::uniform_int_distribution pick(0, sizeof(chrs) - 2); + std::string s; + s.reserve(length); + while (length--) { + s += chrs[pick(rg)]; + } + return s; +} + std::string dir_name(std::string const &path) { size_t pos = path.find_last_of("/"); if (pos == std::string::npos) return ""; diff --git a/common/util.h b/common/util.h index b46f7bde4a..028074384e 100644 --- a/common/util.h +++ b/common/util.h @@ -75,6 +75,7 @@ int getenv(const char* key, int default_val); float getenv(const char* key, float default_val); std::string hexdump(const uint8_t* in, const size_t size); +std::string random_string(std::string::size_type length); std::string dir_name(std::string const& path); // **** file fhelpers ***** diff --git a/release/files_common b/release/files_common index 297a7a808e..f438904118 100644 --- a/release/files_common +++ b/release/files_common @@ -146,6 +146,7 @@ selfdrive/debug/vw_mqb_config.py common/SConscript common/version.h +common/prefix.h common/swaglog.h common/swaglog.cc common/statlog.h diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 5e9b255731..51418e293f 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -1,8 +1,7 @@ #include -#include #include -#include +#include "common/prefix.h" #include "selfdrive/ui/qt/util.h" #include "tools/cabana/mainwin.h" @@ -23,12 +22,6 @@ int main(int argc, char *argv[]) { cmd_parser.showHelp(); } - QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); - QString msgq_path = "/dev/shm/" + uuid; - - QDir dir; - dir.mkdir(msgq_path); - setenv("OPENPILOT_PREFIX", qPrintable(uuid), 1); const QString route = args.empty() ? DEMO_ROUTE : args.first(); uint32_t replay_flags = REPLAY_FLAG_NONE; @@ -38,6 +31,7 @@ int main(int argc, char *argv[]) { replay_flags |= REPLAY_FLAG_QCAMERA; } + OpenpilotPrefix op_prefix; CANMessages p(&app); int ret = 0; if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { @@ -45,7 +39,5 @@ int main(int argc, char *argv[]) { w.showMaximized(); ret = app.exec(); } - - dir.rmdir(msgq_path); return ret; } From f49520db0fd343ccca5975ee62d602d09f98d8b0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 06:47:45 +0800 Subject: [PATCH 0503/1179] Cabana: display all logs in log view (#26659) * fetch more * clear log in showevent * fix wrong time value * check list size * fix canmessages::process * cache all events * improve segment cache * cleanup --- tools/cabana/canmessages.cc | 33 ++++------------ tools/cabana/canmessages.h | 6 +-- tools/cabana/dbcmanager.cc | 1 + tools/cabana/historylog.cc | 75 ++++++++++++++++++++++++++++--------- tools/cabana/historylog.h | 20 ++++++++-- tools/cabana/settings.cc | 9 ----- tools/cabana/settings.h | 2 - tools/replay/replay.cc | 29 +++++++------- tools/replay/replay.h | 7 ++-- 9 files changed, 103 insertions(+), 79 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 9959ba7313..ded8be5fa3 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -1,7 +1,4 @@ #include "tools/cabana/canmessages.h" - -#include - #include "tools/cabana/dbcmanager.h" CANMessages *can = nullptr; @@ -25,6 +22,7 @@ bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint3 replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); replay->setSegmentCacheLimit(settings.cached_segment_limit); replay->installEventFilter(event_filter, this); + QObject::connect(replay, &Replay::seekedTo, this, &CANMessages::seekedTo); QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); QObject::connect(replay, &Replay::streamStarted, this, &CANMessages::streamStarted); if (replay->load()) { @@ -69,17 +67,13 @@ void CANMessages::process(QHash *messages) { } bool CANMessages::eventFilter(const Event *event) { - static std::unique_ptr> new_msgs; + static std::unique_ptr new_msgs = std::make_unique>(); static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { - if (!new_msgs) { - new_msgs.reset(new QHash); - new_msgs->reserve(1000); - } - double current_sec = replay->currentSeconds(); if (counters_begin_sec == 0 || counters_begin_sec >= current_sec) { + new_msgs->clear(); counters.clear(); counters_begin_sec = current_sec; } @@ -87,40 +81,29 @@ bool CANMessages::eventFilter(const Event *event) { auto can_events = event->event.getCan(); for (const auto &c : can_events) { QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); - - std::lock_guard lk(lock); - auto &list = received_msgs[id]; - while (list.size() > settings.can_msg_log_size) { - list.pop_back(); - } - CanData &data = list.emplace_front(); + CanData &data = (*new_msgs)[id]; data.ts = current_sec; - data.dat.append((char *)c.getDat().begin(), c.getDat().size()); - + data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); data.count = ++counters[id]; if (double delta = (current_sec - counters_begin_sec); delta > 0) { data.freq = data.count / delta; } - (*new_msgs)[id] = data; } double ts = millis_since_boot(); - if ((ts - prev_update_ts) > (1000.0 / settings.fps) && !processing) { + if ((ts - prev_update_ts) > (1000.0 / settings.fps) && !processing && !new_msgs->isEmpty()) { // delay posting CAN message if UI thread is busy processing = true; prev_update_ts = ts; // use pointer to avoid data copy in queued connection. emit received(new_msgs.release()); + new_msgs.reset(new QHash); + new_msgs->reserve(100); } } return true; } -const std::deque CANMessages::messages(const QString &id) { - std::lock_guard lk(lock); - return received_msgs[id]; -} - void CANMessages::seekTo(double ts) { replay->seekTo(std::max(double(0), ts), false); counters_begin_sec = 0; diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index f9103aa96b..47f6008686 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -1,8 +1,6 @@ #pragma once #include -#include -#include #include #include @@ -37,7 +35,6 @@ public: inline double totalSeconds() const { return replay->totalSeconds(); } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } inline double currentSec() const { return replay->currentSeconds(); } - const std::deque messages(const QString &id); inline const CanData &lastMessage(const QString &id) { return can_msgs[id]; } inline const Route* route() const { return replay->route(); } @@ -48,6 +45,7 @@ public: inline const std::vector> getTimeline() { return replay->getTimeline(); } signals: + void seekedTo(double sec); void streamStarted(); void eventsMerged(); void updated(); @@ -62,11 +60,9 @@ protected: void settingChanged(); Replay *replay = nullptr; - std::mutex lock; std::atomic counters_begin_sec = 0; std::atomic processing = false; QHash counters; - QHash> received_msgs; }; inline QString toHex(const QByteArray &dat) { diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 1b33c4cc42..6d59cba7b6 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -99,6 +99,7 @@ void DBCManager::removeSignal(const QString &id, const QString &sig_name) { std::pair DBCManager::parseId(const QString &id) { const auto list = id.split(':'); + if (list.size() != 2) return {0, 0}; return {list[0].toInt(), list[1].toUInt(nullptr, 16)}; } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index ec9a0b011c..37001dd582 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -5,14 +5,19 @@ // HistoryLogModel +HistoryLogModel::HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) { + QObject::connect(can, &CANMessages::seekedTo, [this]() { + if (!msg_id.isEmpty()) setMessage(msg_id); + }); +} + QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { const auto &m = messages[index.row()]; if (index.column() == 0) { - return QString::number(m.ts, 'f', 2); + return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } - return !sigs.empty() ? QString::number(get_raw_value((uint8_t *)m.dat.data(), m.dat.size(), *sigs[index.column() - 1])) - : toHex(m.dat); + return !sigs.empty() ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); } else if (role == Qt::FontRole && index.column() == 1 && sigs.empty()) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); } @@ -24,6 +29,7 @@ void HistoryLogModel::setMessage(const QString &message_id) { msg_id = message_id; sigs.clear(); messages.clear(); + has_more_data = true; if (auto dbc_msg = dbc()->msg(message_id)) { sigs = dbc_msg->getSignals(); } @@ -48,23 +54,60 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i } void HistoryLogModel::updateState() { - int prev_row_count = messages.size(); if (!msg_id.isEmpty()) { - messages = can->messages(msg_id); - } - int delta = messages.size() - prev_row_count; - if (delta > 0) { - beginInsertRows({}, prev_row_count, messages.size() - 1); - endInsertRows(); - } else if (delta < 0) { - beginRemoveRows({}, messages.size(), prev_row_count - 1); - endRemoveRows(); + uint64_t last_mono_time = messages.empty() ? 0 : messages.front().mono_time; + auto new_msgs = fetchData(last_mono_time, (can->currentSec() + can->routeStartTime()) * 1e9); + if ((has_more_data = !new_msgs.empty())) { + beginInsertRows({}, 0, new_msgs.size() - 1); + messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); + endInsertRows(); + } } +} + +void HistoryLogModel::fetchMore(const QModelIndex &parent) { if (!messages.empty()) { - emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1), {Qt::DisplayRole}); + auto new_msgs = fetchData(0, messages.back().mono_time); + if ((has_more_data = !new_msgs.empty())) { + beginInsertRows({}, messages.size(), messages.size() + new_msgs.size() - 1); + messages.insert(messages.end(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); + endInsertRows(); + } } } +std::deque HistoryLogModel::fetchData(uint64_t min_mono_time, uint64_t max_mono_time) { + auto events = can->events(); + auto it = std::lower_bound(events->begin(), events->end(), max_mono_time, [=](auto &e, uint64_t ts) { + return e->mono_time < ts; + }); + if (it == events->end() || it == events->begin()) + return {}; + + std::deque msgs; + const auto [src, address] = DBCManager::parseId(msg_id); + uint32_t cnt = 0; + for (--it; it != events->begin() && (*it)->mono_time > min_mono_time; --it) { + if ((*it)->which == cereal::Event::Which::CAN) { + for (const auto &c : (*it)->event.getCan()) { + if (src == c.getSrc() && address == c.getAddress()) { + const auto dat = c.getDat(); + auto &m = msgs.emplace_back(); + m.mono_time = (*it)->mono_time; + m.data.append((char *)dat.begin(), dat.size()); + m.sig_values.reserve(sigs.size()); + for (const Signal *sig : sigs) { + m.sig_values.push_back(get_raw_value((uint8_t *)dat.begin(), dat.size(), *sig)); + } + if (++cnt >= batch_size && min_mono_time == 0) + return msgs; + } + } + } + } + return msgs; +} + // HeaderView QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { @@ -98,7 +141,3 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { setFrameShape(QFrame::NoFrame); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); } - -int HistoryLog::sizeHintForColumn(int column) const { - return -1; -} diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 9ca6f427c7..5a9903823f 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -15,17 +16,27 @@ public: class HistoryLogModel : public QAbstractTableModel { public: - HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} + HistoryLogModel(QObject *parent); void setMessage(const QString &message_id); void updateState(); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + void fetchMore(const QModelIndex &parent) override; + inline bool canFetchMore(const QModelIndex &parent) const override { return has_more_data; } int rowCount(const QModelIndex &parent = QModelIndex()) const override { return messages.size(); } int columnCount(const QModelIndex &parent = QModelIndex()) const override { return std::max(1ul, sigs.size()) + 1; } -private: + struct Message { + uint64_t mono_time = 0; + QVector sig_values; + QByteArray data; + }; + + std::deque fetchData(uint64_t min_mono_time, uint64_t max_mono_time); QString msg_id; - std::deque messages; + bool has_more_data = true; + const int batch_size = 50; + std::deque messages; std::vector sigs; }; @@ -36,6 +47,7 @@ public: void updateState() { model->updateState(); } private: - int sizeHintForColumn(int column) const override; + int sizeHintForColumn(int column) const override { return -1; }; + void showEvent(QShowEvent *event) override { model->setMessage(model->msg_id); }; HistoryLogModel *model; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index c90830973b..63e26f3808 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -15,7 +15,6 @@ Settings::Settings() { void Settings::save() { QSettings s("settings", QSettings::IniFormat); 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); s.setValue("max_chart_x_range", max_chart_x_range); @@ -26,7 +25,6 @@ void Settings::save() { void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); - can_msg_log_size = s.value("log_size", 50).toInt(); cached_segment_limit = s.value("cached_segment", 3).toInt(); chart_height = s.value("chart_height", 200).toInt(); max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); @@ -46,12 +44,6 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { fps->setValue(settings.fps); form_layout->addRow("FPS", fps); - log_size = new QSpinBox(this); - log_size->setRange(50, 500); - log_size->setSingleStep(10); - log_size->setValue(settings.can_msg_log_size); - form_layout->addRow(tr("Signal history log size"), log_size); - cached_segment = new QSpinBox(this); cached_segment->setRange(3, 60); cached_segment->setSingleStep(1); @@ -80,7 +72,6 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { 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.max_chart_x_range = max_chart_x_range->value() * 60; diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index ee6541798d..1db92fe231 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -14,7 +14,6 @@ public: void load(); int fps = 10; - int can_msg_log_size = 50; int cached_segment_limit = 3; int chart_height = 200; int max_chart_x_range = 3 * 60; // 3 minutes @@ -32,7 +31,6 @@ public: SettingsDlg(QWidget *parent); void save(); QSpinBox *fps; - QSpinBox *log_size ; QSpinBox *cached_segment; QSpinBox *chart_height; QSpinBox *max_chart_x_range; diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 33541aeb74..a01371abe1 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -109,6 +109,7 @@ void Replay::seekTo(double seconds, bool relative) { cur_mono_time_ = route_start_ts_ + seconds * 1e9; return isSegmentMerged(seg); }); + emit seekedTo(seconds); queueSegment(); } @@ -209,11 +210,17 @@ void Replay::segmentLoadFinished(bool success) { void Replay::queueSegment() { if (segments_.empty()) return; - SegmentMap::iterator cur, end; - cur = end = segments_.lower_bound(std::min(current_segment_.load(), segments_.rbegin()->first)); - for (int i = 0; end != segments_.end() && i <= segment_cache_limit + FORWARD_FETCH_SEGS; ++i) { + SegmentMap::iterator begin, cur; + begin = cur = segments_.lower_bound(std::min(current_segment_.load(), segments_.rbegin()->first)); + int distance = std::max(std::ceil(segment_cache_limit / 2.0) - 1, segment_cache_limit - std::distance(cur, segments_.end())); + for (int i = 0; begin != segments_.begin() && i < distance; ++i) { + --begin; + } + auto end = begin; + for (int i = 0; end != segments_.end() && i < segment_cache_limit; ++i) { ++end; } + // load one segment at a time for (auto it = cur; it != end; ++it) { auto &[n, seg] = *it; @@ -227,12 +234,6 @@ void Replay::queueSegment() { } } - const auto &cur_segment = cur->second; - // merge the previous adjacent segment if it's loaded - auto begin = segments_.find(cur_segment->seg_num - 1); - if (begin == segments_.end() || !(begin->second && begin->second->isLoaded())) { - begin = cur; - } mergeSegments(begin, end); // free segments out of current semgnt window. @@ -240,6 +241,7 @@ void Replay::queueSegment() { std::for_each(end, segments_.end(), [](auto &e) { e.second.reset(nullptr); }); // start stream thread + const auto &cur_segment = cur->second; if (stream_thread_ == nullptr && cur_segment->isLoaded()) { startStream(cur_segment.get()); emit streamStarted(); @@ -247,12 +249,13 @@ void Replay::queueSegment() { } void Replay::mergeSegments(const SegmentMap::iterator &begin, const SegmentMap::iterator &end) { - // merge 3 segments in sequence. std::vector segments_need_merge; size_t new_events_size = 0; - for (auto it = begin; it != end && it->second && it->second->isLoaded() && segments_need_merge.size() < segment_cache_limit; ++it) { - segments_need_merge.push_back(it->first); - new_events_size += it->second->log->events.size(); + for (auto it = begin; it != end; ++it) { + if (it->second && it->second->isLoaded()) { + segments_need_merge.push_back(it->first); + new_events_size += it->second->log->events.size(); + } } if (segments_need_merge != segments_merged_) { diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 88c285125a..2c68443df0 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -10,7 +10,7 @@ const QString DEMO_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36"; // one segment uses about 100M of memory -constexpr int FORWARD_FETCH_SEGS = 3; +constexpr int MIN_SEGMENTS_CACHE = 5; enum REPLAY_FLAGS { REPLAY_FLAG_NONE = 0x0000, @@ -58,7 +58,7 @@ public: event_filter = filter; } inline int segmentCacheLimit() const { return segment_cache_limit; } - inline void setSegmentCacheLimit(int n) { segment_cache_limit = std::max(3, n); } + inline void setSegmentCacheLimit(int n) { segment_cache_limit = std::max(MIN_SEGMENTS_CACHE, n); } inline bool hasFlag(REPLAY_FLAGS flag) const { return flags_ & flag; } inline void addFlag(REPLAY_FLAGS flag) { flags_ |= flag; } inline void removeFlag(REPLAY_FLAGS flag) { flags_ &= ~flag; } @@ -79,6 +79,7 @@ public: signals: void streamStarted(); void segmentsMerged(); + void seekedTo(double sec); protected slots: void segmentLoadFinished(bool success); @@ -133,5 +134,5 @@ protected: float speed_ = 1.0; replayEventFilter event_filter = nullptr; void *filter_opaque = nullptr; - int segment_cache_limit = 3; + int segment_cache_limit = MIN_SEGMENTS_CACHE; }; From 6acf4e26b85b649fa2b239f5958e208fab8cf62c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 07:00:07 +0800 Subject: [PATCH 0504/1179] sensord: add helper function verify_chip_id to I2CSensor (#25830) --- selfdrive/sensord/sensors/bmx055_accel.cc | 16 ++------------- selfdrive/sensord/sensors/bmx055_gyro.cc | 16 ++------------- selfdrive/sensord/sensors/bmx055_magn.cc | 15 +++----------- selfdrive/sensord/sensors/bmx055_temp.cc | 18 +---------------- selfdrive/sensord/sensors/i2c_sensor.h | 16 ++++++++++++++- selfdrive/sensord/sensors/lsm6ds3_accel.cc | 17 +++------------- selfdrive/sensord/sensors/lsm6ds3_gyro.cc | 17 +++------------- selfdrive/sensord/sensors/lsm6ds3_temp.cc | 22 ++++----------------- selfdrive/sensord/sensors/mmc5603nj_magn.cc | 16 ++------------- 9 files changed, 35 insertions(+), 118 deletions(-) diff --git a/selfdrive/sensord/sensors/bmx055_accel.cc b/selfdrive/sensord/sensors/bmx055_accel.cc index 78b3ac526d..78f5d64e79 100644 --- a/selfdrive/sensord/sensors/bmx055_accel.cc +++ b/selfdrive/sensord/sensors/bmx055_accel.cc @@ -9,20 +9,8 @@ BMX055_Accel::BMX055_Accel(I2CBus *bus) : I2CSensor(bus) {} int BMX055_Accel::init() { - int ret = 0; - uint8_t buffer[1]; - - ret = read_register(BMX055_ACCEL_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } - - if(buffer[0] != BMX055_ACCEL_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], BMX055_ACCEL_CHIP_ID); - ret = -1; - goto fail; - } + int ret = verify_chip_id(BMX055_ACCEL_I2C_REG_ID, {BMX055_ACCEL_CHIP_ID}); + if (ret == -1) return -1; ret = set_register(BMX055_ACCEL_I2C_REG_PMU, BMX055_ACCEL_NORMAL_MODE); if (ret < 0) { diff --git a/selfdrive/sensord/sensors/bmx055_gyro.cc b/selfdrive/sensord/sensors/bmx055_gyro.cc index 9d70b9e431..2a938044f3 100644 --- a/selfdrive/sensord/sensors/bmx055_gyro.cc +++ b/selfdrive/sensord/sensors/bmx055_gyro.cc @@ -12,20 +12,8 @@ BMX055_Gyro::BMX055_Gyro(I2CBus *bus) : I2CSensor(bus) {} int BMX055_Gyro::init() { - int ret = 0; - uint8_t buffer[1]; - - ret =read_register(BMX055_GYRO_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } - - if(buffer[0] != BMX055_GYRO_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], BMX055_GYRO_CHIP_ID); - ret = -1; - goto fail; - } + int ret = verify_chip_id(BMX055_GYRO_I2C_REG_ID, {BMX055_GYRO_CHIP_ID}); + if (ret == -1) return -1; ret = set_register(BMX055_GYRO_I2C_REG_LPM1, BMX055_GYRO_NORMAL_MODE); if (ret < 0) { diff --git a/selfdrive/sensord/sensors/bmx055_magn.cc b/selfdrive/sensord/sensors/bmx055_magn.cc index 394b1e83d3..2f0d10412c 100644 --- a/selfdrive/sensord/sensors/bmx055_magn.cc +++ b/selfdrive/sensord/sensors/bmx055_magn.cc @@ -66,8 +66,6 @@ static int16_t compensate_z(trim_data_t trim_data, int16_t mag_data_z, uint16_t BMX055_Magn::BMX055_Magn(I2CBus *bus) : I2CSensor(bus) {} int BMX055_Magn::init() { - int ret; - uint8_t buffer[1]; uint8_t trim_x1y1[2] = {0}; uint8_t trim_x2y2[2] = {0}; uint8_t trim_xy1xy2[2] = {0}; @@ -78,25 +76,18 @@ int BMX055_Magn::init() { uint8_t trim_xyz1[2] = {0}; // suspend -> sleep - ret = set_register(BMX055_MAGN_I2C_REG_PWR_0, 0x01); + int ret = set_register(BMX055_MAGN_I2C_REG_PWR_0, 0x01); if(ret < 0) { LOGE("Enabling power failed: %d", ret); goto fail; } util::sleep_for(5); // wait until the chip is powered on - // read chip ID - ret = read_register(BMX055_MAGN_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); + ret = verify_chip_id(BMX055_MAGN_I2C_REG_ID, {BMX055_MAGN_CHIP_ID}); + if (ret == -1) { goto fail; } - if(buffer[0] != BMX055_MAGN_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], BMX055_MAGN_CHIP_ID); - return -1; - } - // Load magnetometer trim ret = read_register(BMX055_MAGN_I2C_REG_DIG_X1, trim_x1y1, 2); if(ret < 0) goto fail; diff --git a/selfdrive/sensord/sensors/bmx055_temp.cc b/selfdrive/sensord/sensors/bmx055_temp.cc index bdb34f1508..95b8068ac1 100644 --- a/selfdrive/sensord/sensors/bmx055_temp.cc +++ b/selfdrive/sensord/sensors/bmx055_temp.cc @@ -9,23 +9,7 @@ BMX055_Temp::BMX055_Temp(I2CBus *bus) : I2CSensor(bus) {} int BMX055_Temp::init() { - int ret = 0; - uint8_t buffer[1]; - - ret = read_register(BMX055_ACCEL_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } - - if(buffer[0] != BMX055_ACCEL_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], BMX055_ACCEL_CHIP_ID); - ret = -1; - goto fail; - } - -fail: - return ret; + return verify_chip_id(BMX055_ACCEL_I2C_REG_ID, {BMX055_ACCEL_CHIP_ID}) == -1 ? -1 : 0; } bool BMX055_Temp::get_event(MessageBuilder &msg, uint64_t ts) { diff --git a/selfdrive/sensord/sensors/i2c_sensor.h b/selfdrive/sensord/sensors/i2c_sensor.h index 0de2a98738..08ca6f09cd 100644 --- a/selfdrive/sensord/sensors/i2c_sensor.h +++ b/selfdrive/sensord/sensors/i2c_sensor.h @@ -2,12 +2,12 @@ #include #include - #include "cereal/gen/cpp/log.capnp.h" #include "common/i2c.h" #include "common/gpio.h" +#include "common/swaglog.h" #include "selfdrive/sensord/sensors/constants.h" #include "selfdrive/sensord/sensors/sensor.h" @@ -33,4 +33,18 @@ public: virtual int init() = 0; virtual bool get_event(MessageBuilder &msg, uint64_t ts = 0) = 0; virtual int shutdown() = 0; + + int verify_chip_id(uint8_t address, const std::vector &expected_ids) { + uint8_t chip_id = 0; + int ret = read_register(address, &chip_id, 1); + if (ret < 0) { + LOGE("Reading chip ID failed: %d", ret); + return -1; + } + for (int i = 0; i < expected_ids.size(); ++i) { + if (chip_id == expected_ids[i]) return chip_id; + } + LOGE("Chip ID wrong. Got: %d, Expected %d", chip_id, expected_ids[0]); + return -1; + } }; diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.cc b/selfdrive/sensord/sensors/lsm6ds3_accel.cc index c19e3de7ed..c8eeb6e5dc 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_accel.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_accel.cc @@ -118,8 +118,6 @@ int LSM6DS3_Accel::self_test(int test_type) { } int LSM6DS3_Accel::init() { - int ret = 0; - uint8_t buffer[1]; uint8_t value = 0; bool do_self_test = false; @@ -128,19 +126,10 @@ int LSM6DS3_Accel::init() { do_self_test = true; } - ret = read_register(LSM6DS3_ACCEL_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } + int ret = verify_chip_id(LSM6DS3_ACCEL_I2C_REG_ID, {LSM6DS3_ACCEL_CHIP_ID, LSM6DS3TRC_ACCEL_CHIP_ID}); + if (ret == -1) return -1; - if(buffer[0] != LSM6DS3_ACCEL_CHIP_ID && buffer[0] != LSM6DS3TRC_ACCEL_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], LSM6DS3_ACCEL_CHIP_ID); - ret = -1; - goto fail; - } - - if (buffer[0] == LSM6DS3TRC_ACCEL_CHIP_ID) { + if (ret == LSM6DS3TRC_ACCEL_CHIP_ID) { source = cereal::SensorEventData::SensorSource::LSM6DS3TRC; } diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc b/selfdrive/sensord/sensors/lsm6ds3_gyro.cc index f306be0fe8..d9f5b4cb6a 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_gyro.cc @@ -107,8 +107,6 @@ int LSM6DS3_Gyro::self_test(int test_type) { } int LSM6DS3_Gyro::init() { - int ret = 0; - uint8_t buffer[1]; uint8_t value = 0; bool do_self_test = false; @@ -117,19 +115,10 @@ int LSM6DS3_Gyro::init() { do_self_test = true; } - ret = read_register(LSM6DS3_GYRO_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } + int ret = verify_chip_id(LSM6DS3_GYRO_I2C_REG_ID, {LSM6DS3_GYRO_CHIP_ID, LSM6DS3TRC_GYRO_CHIP_ID}); + if (ret == -1) return -1; - if(buffer[0] != LSM6DS3_GYRO_CHIP_ID && buffer[0] != LSM6DS3TRC_GYRO_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], LSM6DS3_GYRO_CHIP_ID); - ret = -1; - goto fail; - } - - if (buffer[0] == LSM6DS3TRC_GYRO_CHIP_ID) { + if (ret == LSM6DS3TRC_GYRO_CHIP_ID) { source = cereal::SensorEventData::SensorSource::LSM6DS3TRC; } diff --git a/selfdrive/sensord/sensors/lsm6ds3_temp.cc b/selfdrive/sensord/sensors/lsm6ds3_temp.cc index 7e1c4d4c81..c2e2c83c1d 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_temp.cc +++ b/selfdrive/sensord/sensors/lsm6ds3_temp.cc @@ -8,27 +8,13 @@ LSM6DS3_Temp::LSM6DS3_Temp(I2CBus *bus) : I2CSensor(bus) {} int LSM6DS3_Temp::init() { - int ret = 0; - uint8_t buffer[1]; + int ret = verify_chip_id(LSM6DS3_TEMP_I2C_REG_ID, {LSM6DS3_TEMP_CHIP_ID, LSM6DS3TRC_TEMP_CHIP_ID}); + if (ret == -1) return -1; - ret = read_register(LSM6DS3_TEMP_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } - - if(buffer[0] != LSM6DS3_TEMP_CHIP_ID && buffer[0] != LSM6DS3TRC_TEMP_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], LSM6DS3_TEMP_CHIP_ID); - ret = -1; - goto fail; - } - - if (buffer[0] == LSM6DS3TRC_TEMP_CHIP_ID) { + if (ret == LSM6DS3TRC_TEMP_CHIP_ID) { source = cereal::SensorEventData::SensorSource::LSM6DS3TRC; } - -fail: - return ret; + return 0; } bool LSM6DS3_Temp::get_event(MessageBuilder &msg, uint64_t ts) { diff --git a/selfdrive/sensord/sensors/mmc5603nj_magn.cc b/selfdrive/sensord/sensors/mmc5603nj_magn.cc index 7a9b7a298b..cdb82a4a12 100644 --- a/selfdrive/sensord/sensors/mmc5603nj_magn.cc +++ b/selfdrive/sensord/sensors/mmc5603nj_magn.cc @@ -8,20 +8,8 @@ MMC5603NJ_Magn::MMC5603NJ_Magn(I2CBus *bus) : I2CSensor(bus) {} int MMC5603NJ_Magn::init() { - int ret = 0; - uint8_t buffer[1]; - - ret = read_register(MMC5603NJ_I2C_REG_ID, buffer, 1); - if(ret < 0) { - LOGE("Reading chip ID failed: %d", ret); - goto fail; - } - - if(buffer[0] != MMC5603NJ_CHIP_ID) { - LOGE("Chip ID wrong. Got: %d, Expected %d", buffer[0], MMC5603NJ_CHIP_ID); - ret = -1; - goto fail; - } + int ret = verify_chip_id(MMC5603NJ_I2C_REG_ID, {MMC5603NJ_CHIP_ID}); + if (ret == -1) return -1; // Set 100 Hz ret = set_register(MMC5603NJ_I2C_REG_ODR, 100); From d9fb64f0a15164e323c34f8c59a6950859719167 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Mon, 12 Dec 2022 18:02:15 -0500 Subject: [PATCH 0505/1179] Multilang: add German (#26411) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initialize de_DE file * German translation (#83) Formatting will be an issue! * update de_DE qm file * Update main_de.ts Fixed the German translations * regen translations * Fix typo (#84) * regen translations * Update selfdrive/ui/translations/main_de.ts Co-authored-by: Kurt Nistelberger * we don't keep these in-tree anymore? * Update main_de.ts Neue Strings ergänzt * update plurals * remove vanished, add new strings * don't translate a brand/service name * capitalize some things, cleanup * capitalize * more cleanup, mark too-long strings * proper (no) capitalization, line wrap * Update selfdrive/ui/translations/main_de.ts Co-authored-by: Shane Smiskol * update translation strings * Updating the German translation (#89) Added new strings and shortened others to fit the UI * compromises for better button fit Co-authored-by: Vrabetz Co-authored-by: CzokNorris Co-authored-by: Kurt Nistelberger Co-authored-by: Shane Smiskol --- selfdrive/ui/translations/languages.json | 1 + selfdrive/ui/translations/main_de.ts | 1113 ++++++++++++++++++++++ 2 files changed, 1114 insertions(+) create mode 100644 selfdrive/ui/translations/main_de.ts diff --git a/selfdrive/ui/translations/languages.json b/selfdrive/ui/translations/languages.json index 072d320c13..86d3e62d87 100644 --- a/selfdrive/ui/translations/languages.json +++ b/selfdrive/ui/translations/languages.json @@ -1,5 +1,6 @@ { "English": "main_en", + "Deutsch": "main_de", "Português": "main_pt-BR", "中文(繁體)": "main_zh-CHT", "中文(简体)": "main_zh-CHS", diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts new file mode 100644 index 0000000000..ecb44557c9 --- /dev/null +++ b/selfdrive/ui/translations/main_de.ts @@ -0,0 +1,1113 @@ + + + + + AbstractAlert + + Close + Schließen + + + Snooze Update + Update pausieren + + + Reboot and Update + Aktualisieren und neu starten + + + + AdvancedNetworking + + Back + Zurück + + + Enable Tethering + Tethering aktivieren + + + Tethering Password + Tethering Passwort + + + EDIT + ÄNDERN + + + Enter new tethering password + Neues tethering Passwort eingeben + + + IP Address + IP Adresse + + + Enable Roaming + Roaming aktivieren + + + APN Setting + APN Einstellungen + + + Enter APN + APN eingeben + + + leave blank for automatic configuration + für automatische Konfiguration leer lassen + + + Cellular Metered + Getaktete Verbindung + + + Prevent large data uploads when on a metered connection + Hochladen großer Dateien über getaktete Verbindungen unterbinden + + + + AnnotatedCameraWidget + + km/h + km/h + + + mph + mph + + + MAX + MAX + + + SPEED + Geschwindigkeit + + + LIMIT + LIMIT + + + + ConfirmationDialog + + Ok + Ok + + + Cancel + Abbrechen + + + + DeclinePage + + You must accept the Terms and Conditions in order to use openpilot. + Du musst die Nutzungsbedingungen akzeptieren, um Openpilot zu benutzen. + + + Back + Zurück + + + Decline, uninstall %1 + Ablehnen, deinstallieren %1 + + + + DevicePanel + + Dongle ID + Dongle ID + + + N/A + Nicht verfügbar + + + Serial + Seriennummer + + + Driver Camera + Fahrerkamera + + + PREVIEW + VORSCHAU + + + Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) + Vorschau der auf den Fahrer gerichteten Kamera, um sicherzustellen, dass die Fahrerüberwachung eine gute Sicht hat. (Fahrzeug muss aus sein) + + + Reset Calibration + Neu kalibrieren + + + RESET + RESET + + + Are you sure you want to reset calibration? + Bist du sicher, dass du die Kalibrierung zurücksetzen möchtest? + + + Review Training Guide + Trainingsanleitung wiederholen + + + REVIEW + TRAINING + + + Review the rules, features, and limitations of openpilot + Wiederhole die Regeln, Fähigkeiten und Limitierungen von Openpilot + + + Are you sure you want to review the training guide? + Bist du sicher, dass du die Trainingsanleitung wiederholen möchtest? + + + Regulatory + Rechtliche Hinweise + + + VIEW + ANSEHEN + + + Change Language + Sprache ändern + + + CHANGE + ÄNDERN + + + Select a language + Sprache wählen + + + Reboot + Neustart + + + Power Off + Ausschalten + + + openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. + Damit Openpilot funktioniert, darf die Installationsposition nicht mehr als 4° nach rechts/links, 5° nach oben und 8° nach unten abweichen. Openpilot kalibriert sich durchgehend, ein Zurücksetzen ist selten notwendig. + + + Your device is pointed %1° %2 and %3° %4. + Deine Geräteausrichtung ist %1° %2 und %3° %4. + + + down + unten + + + up + oben + + + left + links + + + right + rechts + + + Are you sure you want to reboot? + Bist du sicher, dass du das Gerät neu starten möchtest? + + + Disengage to Reboot + Für Neustart deaktivieren + + + Are you sure you want to power off? + Bist du sicher, dass du das Gerät ausschalten möchtest? + + + Disengage to Power Off + Zum Ausschalten deaktivieren + + + Reset + Zurücksetzen + + + Review + Überprüfen + + + + DriveStats + + Drives + Fahrten + + + Hours + Stunden + + + ALL TIME + Gesamtzeit + + + PAST WEEK + Letzte Woche + + + KM + KM + + + Miles + Meilen + + + + DriverViewScene + + camera starting + Kamera startet + + + + ExperimentalModeButton + + EXPERIMENTAL MODE ON + EXPERIMENTELLER MODUS AN + + + CHILL MODE ON + ENTSPANNTER MODUS AN + + + + InputDialog + + Cancel + Abbrechen + + + Need at least %n character(s)! + + Mindestens %n Buchstabe benötigt! + Mindestens %n Buchstaben benötigt! + + + + + Installer + + Installing... + Installiere... + + + Receiving objects: + Empfange Objekte: + + + Resolving deltas: + Unterschiede verarbeiten: + + + Updating files: + Dateien aktualisieren: + + + + MapETA + + eta + Ankunft + + + min + min + + + hr + std + + + km + km + + + mi + mi + + + + MapInstructions + + km + km + + + m + m + + + mi + mi + + + ft + fuß + + + + MapPanel + + Current Destination + Aktuelles Ziel + + + CLEAR + LÖSCHEN + + + Recent Destinations + Letzte Ziele + + + Try the Navigation Beta + Beta Navigation ausprobieren + + + Get turn-by-turn directions displayed and more with a comma +prime subscription. Sign up now: https://connect.comma.ai + Erhalte echtzeit Wegführung und mehr mit dem comma prime +Abonnement. Melde dich jetzt an: https://connect.comma.ai + + + No home +location set + Keine Heimadresse gesetzt + + + No work +location set + Keine Arbeitsadresse gesetzt + + + no recent destinations + Keine kürzlich gewählten Ziele + + + + MapWindow + + Map Loading + Karte wird geladen + + + Waiting for GPS + Warten auf GPS + + + + MultiOptionDialog + + Select + Auswählen + + + Cancel + Abbrechen + + + + Networking + + Advanced + Erweitert + + + Enter password + Passwort eingeben + + + for "%1" + für "%1" + + + Wrong password + Falsches Passwort + + + + OffroadHome + + UPDATE + Aktualisieren + + + ALERTS + HINWEISE + + + ALERT + HINWEIS + + + + PairingPopup + + Pair your device to your comma account + Verbinde dein Gerät mit deinem comma Konto + + + Go to https://connect.comma.ai on your phone + Gehe zu https://connect.comma.ai auf deinem Handy + + + Click "add new device" and scan the QR code on the right + Klicke auf "neues Gerät hinzufügen" und scanne den QR code rechts + + + Bookmark connect.comma.ai to your home screen to use it like an app + Füge connect.comma.ai als Lesezeichen auf deinem Homescreen hinzu um es wie eine App zu verwenden + + + + ParamControl + + Cancel + Abbrechen + + + Enable + Aktivieren + + + + PrimeAdWidget + + Upgrade Now + Jetzt abonieren + + + Become a comma prime member at connect.comma.ai + Werde Comma Prime Mitglied auf connect.comma.ai + + + PRIME FEATURES: + PRIME FUNKTIONEN: + + + Remote access + Fernzugriff + + + 1 year of storage + 1 Jahr Speicherplatz + + + Developer perks + Entwickler Vorteile + + + + PrimeUserWidget + + ✓ SUBSCRIBED + ✓ ABBONIERT + + + comma prime + comma prime + + + CONNECT.COMMA.AI + CONNECT.COMMA.AI + + + COMMA POINTS + COMMA PUNKTE + + + + QObject + + Reboot + Neustart + + + Exit + Verlassen + + + dashcam + dashcam + + + openpilot + openpilot + + + %n minute(s) ago + + vor %n Minute + vor %n Minuten + + + + %n hour(s) ago + + vor %n Stunde + vor %n Stunden + + + + %n day(s) ago + + vor %n Tag + vor %n Tagen + + + + + Reset + + Reset failed. Reboot to try again. + Zurücksetzen fehlgeschlagen. Starte das Gerät neu und versuche es wieder. + + + Are you sure you want to reset your device? + Bist du sicher, dass du das Gerät auf Werkseinstellungen zurücksetzen möchtest? + + + Resetting device... + Gerät wird zurückgesetzt... + + + System Reset + System auf Werkseinstellungen zurücksetzen + + + System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. + Zurücksetzen auf Werkseinstellungen wurde ausgewählt. Drücke Annehmen, um alle Inhalte und Einstellungen zu löschen. Drücke Abbrechen, um mit dem Starten des Gerätes fortzufahren. + + + Cancel + Abbrechen + + + Reboot + Neustart + + + Confirm + Bestätigen + + + Unable to mount data partition. Press confirm to reset your device. + Datenpartition kann nicht geöffnet werden. Drücke Annehmen, um dein Gerät auf Werkseinstellungen zurückzusetzen. + + + + SettingsWindow + + × + x + + + Device + Gerät + + + Network + Netzwerk + + + Toggles + Schalter + + + Software + Software + + + Navigation + Navigation + + + + Setup + + WARNING: Low Voltage + Warnung: Batteriespannung niedrig + + + Power your device in a car with a harness or proceed at your own risk. + Versorge dein Gerät über einen Kabelbaum im Auto mit Strom, oder fahre auf eigene Gefahr fort. + + + Power off + Ausschalten + + + Continue + Fortsetzen + + + Getting Started + Loslegen + + + Before we get on the road, let’s finish installation and cover some details. + Bevor wir uns auf die Straße begeben, lass uns die Installation fertigstellen und einige Details prüfen. + + + Connect to Wi-Fi + Mit WLAN verbinden + + + Back + Zurück + + + Continue without Wi-Fi + Ohne WLAN fortsetzen + + + Waiting for internet + Auf Internet warten + + + Choose Software to Install + Software zum installieren auswählen + + + Dashcam + Dashcam + + + Custom Software + Spezifische Software + + + Enter URL + URL eingeben + + + for Custom Software + für spezifische Software + + + Downloading... + Herunterladen... + + + Download Failed + Herunterladen fehlgeschlagen + + + Ensure the entered URL is valid, and the device’s internet connection is good. + Stelle sicher, dass die eingegebene URL korrekt ist und dein Gerät eine stabile Internetverbindung hat. + + + Reboot device + Gerät neustarten + + + Start over + Von neuem beginnen + + + + SetupWidget + + Finish Setup + Einrichtung beenden + + + Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. + Koppele dein Gerät mit Comma Connect (connect.comma.ai) und sichere dir dein Comma Prime Angebot. + + + Pair device + Gerät koppeln + + + + Sidebar + + CONNECT + This is a brand/service name for comma connect, don't translate + CONNECT + + + OFFLINE + OFFLINE + + + ONLINE + ONLINE + + + ERROR + FEHLER + + + TEMP + TEMP + + + HIGH + HOCH + + + GOOD + GUT + + + OK + OK + + + VEHICLE + FAHRZEUG + + + NO + KEIN + + + PANDA + PANDA + + + GPS + GPS + + + SEARCH + SUCHEN + + + -- + -- + + + Wi-Fi + WLAN + + + ETH + LAN + + + 2G + 2G + + + 3G + 3G + + + LTE + LTE + + + 5G + 5G + + + + SoftwarePanel + + UNINSTALL + Too long for UI + DEINSTALL + + + Uninstall %1 + Deinstalliere %1 + + + Are you sure you want to uninstall? + Bist du sicher, dass du Openpilot entfernen möchtest? + + + CHECK + ÜBERPRÜFEN + + + Updates are only downloaded while the car is off. + Updates werden nur heruntergeladen, wenn das Auto aus ist. + + + Current Version + Aktuelle Version + + + Download + Download + + + Install Update + Update installieren + + + INSTALL + INSTALLIEREN + + + Target Branch + Ziel Branch + + + SELECT + AUSWÄHLEN + + + Select a branch + Wähle einen Branch + + + Uninstall + Deinstallieren + + + + SshControl + + SSH Keys + SSH Schlüssel + + + Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. + Warnung: Dies ermöglicht SSH zugriff für alle öffentlichen Schlüssel in deinen Github Einstellungen. Gib niemals einen anderen Benutzernamen, als deinen Eigenen an. Comma Angestellte fragen dich niemals danach ihren Github Benutzernamen hinzuzufügen. + + + ADD + HINZUFÜGEN + + + Enter your GitHub username + Gib deinen GitHub Benutzernamen ein + + + LOADING + LADEN + + + REMOVE + LÖSCHEN + + + Username '%1' has no keys on GitHub + Benutzername '%1' hat keine Schlüssel auf GitHub + + + Request timed out + Zeitüberschreitung der Anforderung + + + Username '%1' doesn't exist on GitHub + Benutzername '%1' existiert nicht auf GitHub + + + + SshToggle + + Enable SSH + SSH aktivieren + + + + TermsPage + + Terms & Conditions + Benutzungsbedingungen + + + Decline + Ablehnen + + + Scroll to accept + Scrolle herunter um zu akzeptieren + + + Agree + Zustimmen + + + + TogglesPanel + + Enable openpilot + Openpilot aktivieren + + + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + Benutze das Openpilot System als adaptiven Tempomaten und Spurhalteassistenten. Deine Aufmerksamkeit ist jederzeit erforderlich, um diese Funktion zu nutzen. Diese Einstellung wird übernommen, wenn das Auto aus ist. + + + Enable Lane Departure Warnings + Spurverlassenswarnungen aktivieren + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + Erhalte Warnungen, zurück in die Spur zu lenken, wenn dein Auto über eine erkannte Fahrstreifenmarkierung ohne aktivierten Blinker mit mehr als 50 km/h fährt. + + + Use Metric System + Benutze das metrische System + + + Display speed in km/h instead of mph. + Zeige die Geschwindigkeit in km/h anstatt von mph. + + + Record and Upload Driver Camera + Fahrerkamera aufnehmen und hochladen + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + Lade Daten der Fahreraufmerksamkeitsüberwachungskamera hoch, um die Fahreraufmerksamkeitsüberwachungsalgorithmen zu verbessern. + + + When enabled, pressing the accelerator pedal will disengage openpilot. + Wenn aktiviert, deaktiviert sich Openpilot sobald das Gaspedal betätigt wird. + + + Use 24h format instead of am/pm + Benutze das 24Stunden Format anstatt am/pm + + + Show Map on Left Side of UI + Too long for UI + Zeige die Karte auf der linken Seite + + + Show map on left side when in split screen view. + Zeige die Karte auf der linken Seite der Benutzeroberfläche bei geteilten Bildschirm. + + + Show ETA in 24h Format + Too long for UI + Zeige die Ankunftszeit im 24 Stunden Format + + + Experimental Mode + Experimenteller Modus + + + Experimental openpilot Longitudinal Control + Experimenteller Openpilot Tempomat + + + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). + WARNUNG: Der Openpilot Tempomat ist für dieses Auto experimentell und deaktiviert den Notbremsassistenten. + + + Disengage on Accelerator Pedal + Bei Gasbetätigung ausschalten + + + 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. + Bei diesem auto wird standardmäßig der im Auto eingebaute adaptive Tempomat anstelle des Openpilot Tempomats benutzt. Aktiviere diesen Schalter, um zum Openpilot Tempomaten zu wechseln. Es ist empfohlen den Experimentellen Modus bei Nutzung des Openpilot Tempomats zu aktivieren. + + + 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: + Openpilot fährt standardmäßig im <b>entspannten Modus</b>. Der Experimentelle Modus aktiviert<b>Alpha-level Funktionen</b>, die noch nicht für den entspannten Modus bereit sind. Die experimentellen Funktionen sind die Folgenden: + + + 🌮 End-to-End Longitudinal Control 🌮 + 🌮 Ende-zu-Ende Tempomat 🌮 + + + 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. + Lass das Fahrmodell Gas und Bremse kontrollieren. Openpilot wird so fahren, wie es dies von einem Menschen erwarten würde; inklusive des Anhaltens für Ampeln und Stoppschildern. Da das Fahrmodell entscheidet wie schnell es fährt stellt die gesetzte Geschwindigkeit lediglich das obere Limit dar. Dies ist ein Alpha-level Funktion. Fehler sind zu erwarten. + + + New Driving Visualization + Neue Fahrvisualisierung + + + 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. + Die Fahrvisualisierung wechselt bei niedrigen Geschwindigkeiten zur Straßengewandten Weitwinkelkamera, um manche Kurven besser zu zeigen. Außerdem wird das Experimenteller Modus logo oben rechts angezeigt. + + + Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. + Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar, da es den eingebauten adaptiven Tempomaten des Autos benutzt. + + + Enable experimental longitudinal control to allow experimental mode. + Aktiviere den experimentellen Openpilot Tempomaten für experimentelle Funktionen. + + + + Updater + + Update Required + Aktualisierung notwendig + + + An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. + Eine Aktualisierung des Betriebssystems ist notwendig. Verbinde dein Gerät mit WLAN für ein schnelleres Update. Die Download Größe ist ungefähr 1GB. + + + Connect to Wi-Fi + Mit WLAN verbinden + + + Install + Installieren + + + Back + Zurück + + + Loading... + Laden... + + + Reboot + Neustart + + + Update failed + Aktualisierung fehlgeschlagen + + + + WifiUI + + Scanning for networks... + Suche nach Netzwerken... + + + CONNECTING... + VERBINDEN... + + + FORGET + VERGESSEN + + + Forget Wi-Fi Network "%1"? + WLAN Netzwerk "%1" vergessen? + + + Forget + Vergessen + + + From 91dd9b12cc4e4cd032489ef6a372ce3d81c1c55c Mon Sep 17 00:00:00 2001 From: ajith339 <87100636+ajith339@users.noreply.github.com> Date: Tue, 13 Dec 2022 12:05:48 +1300 Subject: [PATCH 0506/1179] Corolla 2019 GX New Zealand: add missing FW versions (#26746) Update values.py Added Missing FW --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index cda153e89f..6a92540f00 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -741,6 +741,7 @@ FW_VERSIONS = { b'\x018966312Q8000\x00\x00\x00\x00', b'\x018966312R0000\x00\x00\x00\x00', b'\x018966312R0100\x00\x00\x00\x00', + b'\x018966312R0200\x00\x00\x00\x00', b'\x018966312R1000\x00\x00\x00\x00', b'\x018966312R1100\x00\x00\x00\x00', b'\x018966312R3100\x00\x00\x00\x00', @@ -794,6 +795,7 @@ FW_VERSIONS = { b'\x01F152612B60\x00\x00\x00\x00\x00\x00', b'\x01F152612B61\x00\x00\x00\x00\x00\x00', b'\x01F152612B62\x00\x00\x00\x00\x00\x00', + b'\x01F152612B70\x00\x00\x00\x00\x00\x00', b'\x01F152612B71\x00\x00\x00\x00\x00\x00', b'\x01F152612B81\x00\x00\x00\x00\x00\x00', b'\x01F152612B90\x00\x00\x00\x00\x00\x00', From 1478aab005b3cd59b3494ad7edc16057cb542999 Mon Sep 17 00:00:00 2001 From: Chris Hart Date: Mon, 12 Dec 2022 15:13:13 -0800 Subject: [PATCH 0507/1179] SANTA_FE_2022: add missing FW versions (#26759) * added fingerprint for unrecognized 2021 Santa Fe * sorted fingerprints for SANTA_FE_2022 * missed some db56bda387c66164|2022-12-11--10-25-12--0 * revert unnecessary changes * just the shorter query responses Co-authored-by: Chris Hart Co-authored-by: Cameron Clough Co-authored-by: Shane Smiskol --- 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 41b6a58eca..c50b65f101 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -713,12 +713,14 @@ FW_VERSIONS = { b'\xf1\x8758910-S1DA0\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0', b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0', b'\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0', + b'\xf1\x00TM ESC \x04 101 \x08\x04 58910-S2GA0', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x82TACVN5GMI3XXXH0A', b'\xf1\x82TMBZN5TMD3XXXG2E', b'\xf1\x82TACVN5GSI3XXXH0A', b'\xf1\x82TMCFD5MMCXXXXG0A', + b'\xf1\x81HM6M1_0a0_G20', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82TMDWN5TMD3TXXJ1A', b'\xf1\x81HM6M2_0a0_G00', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M1_0a0_J10', @@ -743,6 +745,7 @@ FW_VERSIONS = { b'\xf1\x00HT6TA290BLHT6TAF00A1STM0M25GS1\x00\x00\x00\x00\x00\x006\xd8\x97\x15', b'\xf1\x00T02601BL T02900A1 VTMPT25XXX900NS8\xb7\xaa\xfe\xfc', b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02900A1 \xf1\x00T02601BL T02900A1 VTMPT25XXX900NS8\xb7\xaa\xfe\xfc', + b'\xf1\x00T02601BL T02800A1 VTMPT25XXX800NS4\xed\xaf\xed\xf5', ], }, CAR.SANTA_FE_HEV_2022: { From cc7c2157e51dcb9fec6b76c117f54f80f589de0e Mon Sep 17 00:00:00 2001 From: Michael Burns Date: Mon, 12 Dec 2022 18:26:35 -0500 Subject: [PATCH 0508/1179] Add missing FW versions for Audi S3/A3 (#26555) * Added fingerprint for Audi S3/A3 * Fixed inconsistent spacing issue * Fixed unit test error due to duplicate value * Changing fwdRadar value back to 00101 from x0101 Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 18a444bf7c..208d146e2f 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -807,6 +807,7 @@ FW_VERSIONS = { b'\xf1\x875G0906259L \xf1\x890002', b'\xf1\x875G0906259Q \xf1\x890002', b'\xf1\x878V0906259F \xf1\x890002', + b'\xf1\x878V0906259H \xf1\x890002', b'\xf1\x878V0906259J \xf1\x890002', b'\xf1\x878V0906259K \xf1\x890001', b'\xf1\x878V0906264B \xf1\x890003', @@ -817,6 +818,7 @@ FW_VERSIONS = { b'\xf1\x870CW300044T \xf1\x895245', b'\xf1\x870CW300048 \xf1\x895201', b'\xf1\x870D9300012 \xf1\x894912', + b'\xf1\x870D9300012 \xf1\x894931', b'\xf1\x870D9300012K \xf1\x894513', b'\xf1\x870D9300013B \xf1\x894931', b'\xf1\x870D9300041N \xf1\x894512', @@ -839,12 +841,14 @@ FW_VERSIONS = { b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\x13111112111111--241115141112221291163221', b'\xf1\x875Q0959655J \xf1\x890825\xf1\x82\023111112111111--171115141112221291163221', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\023121111111211--261117141112231291163221', + b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13111112111111--241115141112221291163221', b'\xf1\x875Q0959655J \xf1\x890830\xf1\x82\x13121111111111--341117141212231291163221', b'\xf1\x875Q0959655N \xf1\x890361\xf1\x82\0211212001112110004110411111421149114', b'\xf1\x875Q0959655N \xf1\x890361\xf1\x82\0211212001112111104110411111521159114', ], (Ecu.eps, 0x712, None): [ b'\xf1\x873Q0909144H \xf1\x895061\xf1\x82\00566G0HA14A1', + b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566G0HA14A1', b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571G01A16A1', b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571G0HA16A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571G0JA14A1', From e6e33531cad4f50c94d5522dc430900828467317 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Mon, 12 Dec 2022 16:35:25 -0800 Subject: [PATCH 0509/1179] camerad: lower cost for OX high gain idxs (#26775) --- system/camerad/cameras/camera_qcom2.cc | 10 +++++++++- system/camerad/cameras/camera_qcom2.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index df5b9e8bf0..091b0d91d9 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -97,11 +97,15 @@ const int ANALOG_GAIN_MIN_IDX_AR0231 = 0x1; // 0.25x const int ANALOG_GAIN_REC_IDX_AR0231 = 0x6; // 0.8x const int ANALOG_GAIN_MAX_IDX_AR0231 = 0xD; // 4.0x const int ANALOG_GAIN_COST_DELTA_AR0231 = 0; +const float ANALOG_GAIN_COST_LOW_AR0231 = 0.1; +const float ANALOG_GAIN_COST_HIGH_AR0231 = 5.0; const int ANALOG_GAIN_MIN_IDX_OX03C10 = 0x0; const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x11; // 2.5x const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0x36; const int ANALOG_GAIN_COST_DELTA_OX03C10 = -1; +const float ANALOG_GAIN_COST_LOW_OX03C10 = 0.05; +const float ANALOG_GAIN_COST_HIGH_OX03C10 = 0.8; const int EXPOSURE_TIME_MIN_AR0231 = 2; // with HDR, fastest ss const int EXPOSURE_TIME_MAX_AR0231 = 0x0855; // with HDR, slowest ss, 40ms @@ -535,6 +539,8 @@ void CameraState::camera_set_parameters() { analog_gain_rec_idx = ANALOG_GAIN_REC_IDX_AR0231; analog_gain_max_idx = ANALOG_GAIN_MAX_IDX_AR0231; analog_gain_cost_delta = ANALOG_GAIN_COST_DELTA_AR0231; + analog_gain_cost_low = ANALOG_GAIN_COST_LOW_AR0231; + analog_gain_cost_high = ANALOG_GAIN_COST_HIGH_AR0231; for (int i=0; i<=analog_gain_max_idx; i++) { sensor_analog_gains[i] = sensor_analog_gains_AR0231[i]; } @@ -552,6 +558,8 @@ void CameraState::camera_set_parameters() { analog_gain_rec_idx = ANALOG_GAIN_REC_IDX_OX03C10; analog_gain_max_idx = ANALOG_GAIN_MAX_IDX_OX03C10; analog_gain_cost_delta = ANALOG_GAIN_COST_DELTA_OX03C10; + analog_gain_cost_low = ANALOG_GAIN_COST_LOW_OX03C10; + analog_gain_cost_high = ANALOG_GAIN_COST_HIGH_OX03C10; for (int i=0; i<=analog_gain_max_idx; i++) { sensor_analog_gains[i] = sensor_analog_gains_OX03C10[i]; } @@ -1108,7 +1116,7 @@ void CameraState::set_camera_exposure(float grey_frac) { float score = std::abs(desired_ev - (t * gain)) * 10; // Going below recommended gain needs lower penalty to not overexpose - float m = g > analog_gain_rec_idx ? 5.0 : 0.1; + float m = g > analog_gain_rec_idx ? analog_gain_cost_high : analog_gain_cost_low; score += std::abs(g - (int)analog_gain_rec_idx) * m; // LOGE("cam: %d - gain: %d, t: %d (%.2f), score %.2f, score + gain %.2f, %.3f, %.3f", camera_num, g, t, desired_ev / gain, score, score + std::abs(g - gain_idx) * (score + 1.0) / 10.0, desired_ev, min_ev); diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 150ea0a1c0..9f0c3743f1 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -42,6 +42,8 @@ public: int analog_gain_max_idx; int analog_gain_rec_idx; int analog_gain_cost_delta; + float analog_gain_cost_low; + float analog_gain_cost_high; float cur_ev[3]; float min_ev, max_ev; From e1c739f7091942cf4108b3cc3564c09a7b0404d7 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Tue, 13 Dec 2022 01:15:37 +0000 Subject: [PATCH 0510/1179] athenad: more types (#25877) * add typing hints * missed these * revert functional changes and changes to uploader * remove * try any * add types to test code * try dataclass instead * mypy needs this * comments * remove Any type * remove unused method * cleanup Co-authored-by: Adeeb Shihadeh --- selfdrive/athena/athenad.py | 223 +++++++++++++++---------- selfdrive/athena/tests/test_athenad.py | 10 +- 2 files changed, 140 insertions(+), 93 deletions(-) diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 5b351ca0f5..d1cc4cea83 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import base64 import bz2 import hashlib @@ -14,14 +16,15 @@ import sys import tempfile import threading import time -from collections import namedtuple +from dataclasses import asdict, dataclass, replace from datetime import datetime from functools import partial -from typing import Any, Dict +from queue import Queue +from typing import BinaryIO, Callable, Dict, List, Optional, Set, Union, cast import requests from jsonrpc import JSONRPCResponseManager, dispatcher -from websocket import (ABNF, WebSocketException, WebSocketTimeoutException, +from websocket import (ABNF, WebSocket, WebSocketException, WebSocketTimeoutException, create_connection) import cereal.messaging as messaging @@ -54,19 +57,54 @@ WS_FRAME_SIZE = 4096 NetworkType = log.DeviceState.NetworkType +UploadFileDict = Dict[str, Union[str, int, float, bool]] +UploadItemDict = Dict[str, Union[str, bool, int, float, Dict[str, str]]] + +UploadFilesToUrlResponse = Dict[str, Union[int, List[UploadItemDict], List[str]]] + + +@dataclass +class UploadFile: + fn: str + url: str + headers: Dict[str, str] + allow_cellular: bool + + @classmethod + def from_dict(cls, d: Dict) -> UploadFile: + return cls(d.get("fn", ""), d.get("url", ""), d.get("headers", {}), d.get("allow_cellular", False)) + + +@dataclass +class UploadItem: + path: str + url: str + headers: Dict[str, str] + created_at: int + id: Optional[str] + retry_count: int = 0 + current: bool = False + progress: float = 0 + allow_cellular: bool = False + + @classmethod + def from_dict(cls, d: Dict) -> UploadItem: + return cls(d["path"], d["url"], d["headers"], d["created_at"], d["id"], d["retry_count"], d["current"], + d["progress"], d["allow_cellular"]) + + dispatcher["echo"] = lambda s: s -recv_queue: Any = queue.Queue() -send_queue: Any = queue.Queue() -upload_queue: Any = queue.Queue() -low_priority_send_queue: Any = queue.Queue() -log_recv_queue: Any = queue.Queue() -cancelled_uploads: Any = set() -UploadItem = namedtuple('UploadItem', ['path', 'url', 'headers', 'created_at', 'id', 'retry_count', 'current', 'progress', 'allow_cellular'], defaults=(0, False, 0, False)) +recv_queue: Queue[str] = queue.Queue() +send_queue: Queue[str] = queue.Queue() +upload_queue: Queue[UploadItem] = queue.Queue() +low_priority_send_queue: Queue[str] = queue.Queue() +log_recv_queue: Queue[str] = queue.Queue() +cancelled_uploads: Set[str] = set() -cur_upload_items: Dict[int, Any] = {} +cur_upload_items: Dict[int, Optional[UploadItem]] = {} -def strip_bz2_extension(fn): +def strip_bz2_extension(fn: str) -> str: if fn.endswith('.bz2'): return fn[:-4] return fn @@ -76,29 +114,30 @@ class AbortTransferException(Exception): pass -class UploadQueueCache(): +class UploadQueueCache: params = Params() @staticmethod - def initialize(upload_queue): + def initialize(upload_queue: Queue[UploadItem]) -> None: try: upload_queue_json = UploadQueueCache.params.get("AthenadUploadQueue") if upload_queue_json is not None: for item in json.loads(upload_queue_json): - upload_queue.put(UploadItem(**item)) + upload_queue.put(UploadItem.from_dict(item)) except Exception: cloudlog.exception("athena.UploadQueueCache.initialize.exception") @staticmethod - def cache(upload_queue): + def cache(upload_queue: Queue[UploadItem]) -> None: try: - items = [i._asdict() for i in upload_queue.queue if i.id not in cancelled_uploads] + queue: List[Optional[UploadItem]] = list(upload_queue.queue) + items = [asdict(i) for i in queue if i is not None and (i.id not in cancelled_uploads)] UploadQueueCache.params.put("AthenadUploadQueue", json.dumps(items)) except Exception: cloudlog.exception("athena.UploadQueueCache.cache.exception") -def handle_long_poll(ws): +def handle_long_poll(ws: WebSocket) -> None: end_event = threading.Event() threads = [ @@ -126,7 +165,7 @@ def handle_long_poll(ws): thread.join() -def jsonrpc_handler(end_event): +def jsonrpc_handler(end_event: threading.Event) -> None: dispatcher["startLocalProxy"] = partial(startLocalProxy, end_event) while not end_event.is_set(): try: @@ -147,11 +186,12 @@ def jsonrpc_handler(end_event): def retry_upload(tid: int, end_event: threading.Event, increase_count: bool = True) -> None: - if cur_upload_items[tid].retry_count < MAX_RETRY_COUNT: - item = cur_upload_items[tid] + item = cur_upload_items[tid] + if item is not None and item.retry_count < MAX_RETRY_COUNT: new_retry_count = item.retry_count + 1 if increase_count else item.retry_count - item = item._replace( + item = replace( + item, retry_count=new_retry_count, progress=0, current=False @@ -175,44 +215,44 @@ def upload_handler(end_event: threading.Event) -> None: cur_upload_items[tid] = None try: - cur_upload_items[tid] = upload_queue.get(timeout=1)._replace(current=True) + cur_upload_items[tid] = item = replace(upload_queue.get(timeout=1), current=True) - if cur_upload_items[tid].id in cancelled_uploads: - cancelled_uploads.remove(cur_upload_items[tid].id) + if item.id in cancelled_uploads: + cancelled_uploads.remove(item.id) continue # Remove item if too old - age = datetime.now() - datetime.fromtimestamp(cur_upload_items[tid].created_at / 1000) + age = datetime.now() - datetime.fromtimestamp(item.created_at / 1000) if age.total_seconds() > MAX_AGE: - cloudlog.event("athena.upload_handler.expired", item=cur_upload_items[tid], error=True) + cloudlog.event("athena.upload_handler.expired", item=item, error=True) continue # Check if uploading over metered connection is allowed sm.update(0) metered = sm['deviceState'].networkMetered network_type = sm['deviceState'].networkType.raw - if metered and (not cur_upload_items[tid].allow_cellular): + if metered and (not item.allow_cellular): retry_upload(tid, end_event, False) continue try: - def cb(sz, cur): + def cb(sz: int, cur: int) -> None: # Abort transfer if connection changed to metered after starting upload sm.update(0) metered = sm['deviceState'].networkMetered - if metered and (not cur_upload_items[tid].allow_cellular): + if metered and (not item.allow_cellular): raise AbortTransferException - cur_upload_items[tid] = cur_upload_items[tid]._replace(progress=cur / sz if sz else 1) + cur_upload_items[tid] = replace(item, progress=cur / sz if sz else 1) - fn = cur_upload_items[tid].path + fn = item.path try: sz = os.path.getsize(fn) except OSError: sz = -1 - cloudlog.event("athena.upload_handler.upload_start", fn=fn, sz=sz, network_type=network_type, metered=metered, retry_count=cur_upload_items[tid].retry_count) - response = _do_upload(cur_upload_items[tid], cb) + cloudlog.event("athena.upload_handler.upload_start", fn=fn, sz=sz, network_type=network_type, metered=metered, retry_count=item.retry_count) + response = _do_upload(item, cb) if response.status_code not in (200, 201, 401, 403, 412): cloudlog.event("athena.upload_handler.retry", status_code=response.status_code, fn=fn, sz=sz, network_type=network_type, metered=metered) @@ -234,7 +274,7 @@ def upload_handler(end_event: threading.Event) -> None: cloudlog.exception("athena.upload_handler.exception") -def _do_upload(upload_item, callback=None): +def _do_upload(upload_item: UploadItem, callback: Optional[Callable] = None) -> requests.Response: path = upload_item.path compress = False @@ -244,27 +284,25 @@ def _do_upload(upload_item, callback=None): compress = True with open(path, "rb") as f: + data: BinaryIO if compress: cloudlog.event("athena.upload_handler.compress", fn=path, fn_orig=upload_item.path) - data = bz2.compress(f.read()) - size = len(data) - data = io.BytesIO(data) + compressed = bz2.compress(f.read()) + size = len(compressed) + data = io.BytesIO(compressed) else: size = os.fstat(f.fileno()).st_size data = f - if callback: - data = CallbackReader(data, callback, size) - return requests.put(upload_item.url, - data=data, + data=CallbackReader(data, callback, size) if callback else data, headers={**upload_item.headers, 'Content-Length': str(size)}, timeout=30) # security: user should be able to request any message from their car @dispatcher.add_method -def getMessage(service=None, timeout=1000): +def getMessage(service: str, timeout: int = 1000) -> Dict: if service is None or service not in service_list: raise Exception("invalid service") @@ -274,7 +312,8 @@ def getMessage(service=None, timeout=1000): if ret is None: raise TimeoutError - return ret.to_dict() + # this is because capnp._DynamicStructReader doesn't have typing information + return cast(Dict, ret.to_dict()) @dispatcher.add_method @@ -288,7 +327,7 @@ def getVersion() -> Dict[str, str]: @dispatcher.add_method -def setNavDestination(latitude=0, longitude=0, place_name=None, place_details=None): +def setNavDestination(latitude: int = 0, longitude: int = 0, place_name: Optional[str] = None, place_details: Optional[str] = None) -> Dict[str, int]: destination = { "latitude": latitude, "longitude": longitude, @@ -300,8 +339,8 @@ def setNavDestination(latitude=0, longitude=0, place_name=None, place_details=No return {"success": 1} -def scan_dir(path, prefix): - files = list() +def scan_dir(path: str, prefix: str) -> List[str]: + files = [] # only walk directories that match the prefix # (glob and friends traverse entire dir tree) with os.scandir(path) as i: @@ -320,18 +359,18 @@ def scan_dir(path, prefix): return files @dispatcher.add_method -def listDataDirectory(prefix=''): +def listDataDirectory(prefix='') -> List[str]: return scan_dir(ROOT, prefix) @dispatcher.add_method -def reboot(): +def reboot() -> Dict[str, int]: sock = messaging.sub_sock("deviceState", timeout=1000) ret = messaging.recv_one(sock) if ret is None or ret.deviceState.started: raise Exception("Reboot unavailable") - def do_reboot(): + def do_reboot() -> None: time.sleep(2) HARDWARE.reboot() @@ -341,50 +380,53 @@ def reboot(): @dispatcher.add_method -def uploadFileToUrl(fn, url, headers): - return uploadFilesToUrls([{ +def uploadFileToUrl(fn: str, url: str, headers: Dict[str, str]) -> UploadFilesToUrlResponse: + # this is because mypy doesn't understand that the decorator doesn't change the return type + response: UploadFilesToUrlResponse = uploadFilesToUrls([{ "fn": fn, "url": url, "headers": headers, }]) + return response @dispatcher.add_method -def uploadFilesToUrls(files_data): - items = [] - failed = [] - for file in files_data: - fn = file.get('fn', '') - if len(fn) == 0 or fn[0] == '/' or '..' in fn or 'url' not in file: - failed.append(fn) +def uploadFilesToUrls(files_data: List[UploadFileDict]) -> UploadFilesToUrlResponse: + files = map(UploadFile.from_dict, files_data) + + items: List[UploadItemDict] = [] + failed: List[str] = [] + for file in files: + if len(file.fn) == 0 or file.fn[0] == '/' or '..' in file.fn or len(file.url) == 0: + failed.append(file.fn) continue - path = os.path.join(ROOT, fn) + path = os.path.join(ROOT, file.fn) if not os.path.exists(path) and not os.path.exists(strip_bz2_extension(path)): - failed.append(fn) + failed.append(file.fn) continue # Skip item if already in queue - url = file['url'].split('?')[0] + url = file.url.split('?')[0] if any(url == item['url'].split('?')[0] for item in listUploadQueue()): continue item = UploadItem( path=path, - url=file['url'], - headers=file.get('headers', {}), + url=file.url, + headers=file.headers, created_at=int(time.time() * 1000), id=None, - allow_cellular=file.get('allow_cellular', False), + allow_cellular=file.allow_cellular, ) upload_id = hashlib.sha1(str(item).encode()).hexdigest() - item = item._replace(id=upload_id) + item = replace(item, id=upload_id) upload_queue.put_nowait(item) - items.append(item._asdict()) + items.append(asdict(item)) UploadQueueCache.cache(upload_queue) - resp = {"enqueued": len(items), "items": items} + resp: UploadFilesToUrlResponse = {"enqueued": len(items), "items": items} if failed: resp["failed"] = failed @@ -392,32 +434,32 @@ def uploadFilesToUrls(files_data): @dispatcher.add_method -def listUploadQueue(): +def listUploadQueue() -> List[UploadItemDict]: items = list(upload_queue.queue) + list(cur_upload_items.values()) - return [i._asdict() for i in items if (i is not None) and (i.id not in cancelled_uploads)] + return [asdict(i) for i in items if (i is not None) and (i.id not in cancelled_uploads)] @dispatcher.add_method -def cancelUpload(upload_id): +def cancelUpload(upload_id: Union[str, List[str]]) -> Dict[str, Union[int, str]]: if not isinstance(upload_id, list): upload_id = [upload_id] uploading_ids = {item.id for item in list(upload_queue.queue)} cancelled_ids = uploading_ids.intersection(upload_id) if len(cancelled_ids) == 0: - return 404 + return {"success": 0, "error": "not found"} cancelled_uploads.update(cancelled_ids) return {"success": 1} @dispatcher.add_method -def primeActivated(activated): +def primeActivated(activated: bool) -> Dict[str, int]: return {"success": 1} @dispatcher.add_method -def setBandwithLimit(upload_speed_kbps, download_speed_kbps): +def setBandwithLimit(upload_speed_kbps: int, download_speed_kbps: int) -> Dict[str, Union[int, str]]: if not AGNOS: return {"success": 0, "error": "only supported on AGNOS"} @@ -428,7 +470,7 @@ def setBandwithLimit(upload_speed_kbps, download_speed_kbps): return {"success": 0, "error": "failed to set limit", "stdout": e.stdout, "stderr": e.stderr} -def startLocalProxy(global_end_event, remote_ws_uri, local_port): +def startLocalProxy(global_end_event: threading.Event, remote_ws_uri: str, local_port: int) -> Dict[str, int]: try: if local_port not in LOCAL_PORT_WHITELIST: raise Exception("Requested local port not whitelisted") @@ -462,7 +504,7 @@ def startLocalProxy(global_end_event, remote_ws_uri, local_port): @dispatcher.add_method -def getPublicKey(): +def getPublicKey() -> Optional[str]: if not os.path.isfile(PERSIST + '/comma/id_rsa.pub'): return None @@ -471,7 +513,7 @@ def getPublicKey(): @dispatcher.add_method -def getSshAuthorizedKeys(): +def getSshAuthorizedKeys() -> str: return Params().get("GithubSshKeys", encoding='utf8') or '' @@ -486,7 +528,7 @@ def getNetworkType(): @dispatcher.add_method -def getNetworkMetered(): +def getNetworkMetered() -> bool: network_type = HARDWARE.get_network_type() return HARDWARE.get_network_metered(network_type) @@ -497,7 +539,7 @@ def getNetworks(): @dispatcher.add_method -def takeSnapshot(): +def takeSnapshot() -> Optional[Union[str, Dict[str, str]]]: from system.camerad.snapshot.snapshot import jpeg_write, snapshot ret = snapshot() if ret is not None: @@ -514,16 +556,19 @@ def takeSnapshot(): raise Exception("not available while camerad is started") -def get_logs_to_send_sorted(): +def get_logs_to_send_sorted() -> List[str]: # TODO: scan once then use inotify to detect file creation/deletion curr_time = int(time.time()) logs = [] for log_entry in os.listdir(SWAGLOG_DIR): log_path = os.path.join(SWAGLOG_DIR, log_entry) + time_sent = 0 try: - time_sent = int.from_bytes(getxattr(log_path, LOG_ATTR_NAME), sys.byteorder) + value = getxattr(log_path, LOG_ATTR_NAME) + if value is not None: + time_sent = int.from_bytes(value, sys.byteorder) except (ValueError, TypeError): - time_sent = 0 + pass # assume send failed and we lost the response if sent more than one hour ago if not time_sent or curr_time - time_sent > 3600: logs.append(log_entry) @@ -531,7 +576,7 @@ def get_logs_to_send_sorted(): return sorted(logs)[:-1] -def log_handler(end_event): +def log_handler(end_event: threading.Event) -> None: if PC: return @@ -593,7 +638,7 @@ def log_handler(end_event): cloudlog.exception("athena.log_handler.exception") -def stat_handler(end_event): +def stat_handler(end_event: threading.Event) -> None: while not end_event.is_set(): last_scan = 0 curr_scan = sec_since_boot() @@ -619,7 +664,7 @@ def stat_handler(end_event): time.sleep(0.1) -def ws_proxy_recv(ws, local_sock, ssock, end_event, global_end_event): +def ws_proxy_recv(ws: WebSocket, local_sock: socket.socket, ssock: socket.socket, end_event: threading.Event, global_end_event: threading.Event) -> None: while not (end_event.is_set() or global_end_event.is_set()): try: data = ws.recv() @@ -638,7 +683,7 @@ def ws_proxy_recv(ws, local_sock, ssock, end_event, global_end_event): end_event.set() -def ws_proxy_send(ws, local_sock, signal_sock, end_event): +def ws_proxy_send(ws: WebSocket, local_sock: socket.socket, signal_sock: socket.socket, end_event: threading.Event) -> None: while not end_event.is_set(): try: r, _, _ = select.select((local_sock, signal_sock), (), ()) @@ -663,7 +708,7 @@ def ws_proxy_send(ws, local_sock, signal_sock, end_event): cloudlog.debug("athena.ws_proxy_send done closing sockets") -def ws_recv(ws, end_event): +def ws_recv(ws: WebSocket, end_event: threading.Event) -> None: last_ping = int(sec_since_boot() * 1e9) while not end_event.is_set(): try: @@ -685,7 +730,7 @@ def ws_recv(ws, end_event): end_event.set() -def ws_send(ws, end_event): +def ws_send(ws: WebSocket, end_event: threading.Event) -> None: while not end_event.is_set(): try: try: @@ -704,7 +749,7 @@ def ws_send(ws, end_event): end_event.set() -def backoff(retries): +def backoff(retries: int) -> int: return random.randrange(0, min(128, int(2 ** retries))) diff --git a/selfdrive/athena/tests/test_athenad.py b/selfdrive/athena/tests/test_athenad.py index 5e86a2e821..128fde0319 100755 --- a/selfdrive/athena/tests/test_athenad.py +++ b/selfdrive/athena/tests/test_athenad.py @@ -8,6 +8,7 @@ import time import threading import queue import unittest +from dataclasses import asdict, replace from datetime import datetime, timedelta from typing import Optional @@ -226,7 +227,7 @@ class TestAthenadMethods(unittest.TestCase): """When an upload times out or fails to connect it should be placed back in the queue""" 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) + item_no_retry = replace(item, retry_count=MAX_RETRY_COUNT) end_event = threading.Event() thread = threading.Thread(target=athenad.upload_handler, args=(end_event,)) @@ -296,7 +297,7 @@ class TestAthenadMethods(unittest.TestCase): self.assertEqual(len(items), 0) @with_http_server - def test_listUploadQueueCurrent(self, host): + def test_listUploadQueueCurrent(self, host: str): 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) @@ -321,7 +322,7 @@ class TestAthenadMethods(unittest.TestCase): items = dispatcher["listUploadQueue"]() self.assertEqual(len(items), 1) - self.assertDictEqual(items[0], item._asdict()) + self.assertDictEqual(items[0], asdict(item)) self.assertFalse(items[0]['current']) athenad.cancelled_uploads.add(item.id) @@ -346,7 +347,7 @@ class TestAthenadMethods(unittest.TestCase): athenad.UploadQueueCache.initialize(athenad.upload_queue) self.assertEqual(athenad.upload_queue.qsize(), 1) - self.assertDictEqual(athenad.upload_queue.queue[-1]._asdict(), item1._asdict()) + self.assertDictEqual(asdict(athenad.upload_queue.queue[-1]), asdict(item1)) @mock.patch('selfdrive.athena.athenad.create_connection') def test_startLocalProxy(self, mock_create_connection): @@ -417,5 +418,6 @@ class TestAthenadMethods(unittest.TestCase): sl = athenad.get_logs_to_send_sorted() self.assertListEqual(sl, fl[:-1]) + if __name__ == '__main__': unittest.main() From 2f83b9872fe991d21e07a95cc518f91f140a856a Mon Sep 17 00:00:00 2001 From: Jason Shuler Date: Mon, 12 Dec 2022 20:26:30 -0500 Subject: [PATCH 0511/1179] GM: add checksum to button message (#26014) * Add GM button msg checksum * checksum that works for both, fix missing bit * bump opendbc * update comment Co-authored-by: Shane Smiskol --- opendbc | 2 +- selfdrive/car/gm/gmcan.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/opendbc b/opendbc index 1f8aa057bc..bb71829028 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 1f8aa057bc1c96fcf8a2b612a9897ce91e627381 +Subproject commit bb7182902847b84aa572733edfd8e7073bb02aeb diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 56c981326f..63189bcd89 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -6,7 +6,16 @@ def create_buttons(packer, bus, idx, button): values = { "ACCButtons": button, "RollingCounter": idx, + "ACCAlwaysOne": 1, + "DistanceButton": 0, } + + checksum = 240 + int(values["ACCAlwaysOne"] * 0xf) + checksum += values["RollingCounter"] * (0x4ef if values["ACCAlwaysOne"] != 0 else 0x3f0) + checksum -= int(values["ACCButtons"] - 1) << 4 # not correct if value is 0 + checksum -= 2 * values["DistanceButton"] + + values["SteeringButtonChecksum"] = checksum return packer.make_can_msg("ASCMSteeringButton", bus, values) From 7bfb63b93c1c2094931fff9054e1fa09268a1739 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Dec 2022 19:10:03 -0800 Subject: [PATCH 0512/1179] update refs for GM checksum change --- selfdrive/test/process_replay/ref_commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 3f54203f97..a32eba928e 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -99e9481d03e18a4dcd1eeebbfb24aca1ceb7e1e1 \ No newline at end of file +2f83b9872fe991d21e07a95cc518f91f140a856a \ No newline at end of file From c954634ac0dc622600b43757fcbbce1e66a68961 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 12 Dec 2022 23:33:16 -0500 Subject: [PATCH 0513/1179] HKG CAN-FD: common distance unit signal (#26758) * Check DISTANCE_UNIT on CRUISE_BUTTONS for all CAN-FD HKG * update refs * move down Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/carstate.py | 17 +++++++---------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index bd6b72f461..cc8fbe3f08 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -199,9 +199,7 @@ class CarState(CarStateBase): ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0 ret.cruiseState.available = True - cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" - distance_unit_msg = cruise_btn_msg if self.CP.carFingerprint == CAR.KIA_SORENTO_PHEV_4TH_GEN else "CLUSTER_INFO" - self.is_metric = cp.vl[distance_unit_msg]["DISTANCE_UNIT"] != 1 + self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1 if not self.CP.openpilotLongitudinalControl: speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp @@ -210,6 +208,7 @@ class CarState(CarStateBase): ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"]) + cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" self.prev_cruise_buttons = self.cruise_buttons[-1] self.cruise_buttons.extend(cp.vl_all[cruise_btn_msg]["CRUISE_BUTTONS"]) self.main_buttons.extend(cp.vl_all[cruise_btn_msg]["ADAPTIVE_CRUISE_MAIN_BTN"]) @@ -439,8 +438,7 @@ class CarState(CarStateBase): ("COUNTER", cruise_btn_msg), ("CRUISE_BUTTONS", cruise_btn_msg), ("ADAPTIVE_CRUISE_MAIN_BTN", cruise_btn_msg), - - ("DISTANCE_UNIT", "CLUSTER_INFO"), + ("DISTANCE_UNIT", "CRUISE_BUTTONS_ALT"), ("LEFT_LAMP", "BLINKERS"), ("RIGHT_LAMP", "BLINKERS"), @@ -449,21 +447,20 @@ class CarState(CarStateBase): ("DRIVER_SEATBELT_LATCHED", "DOORS_SEATBELTS"), ] - if CP.carFingerprint == CAR.KIA_SORENTO_PHEV_4TH_GEN: - signals.append(("DISTANCE_UNIT", cruise_btn_msg)) - checks = [ ("WHEEL_SPEEDS", 100), (gear_msg, 100), ("STEERING_SENSORS", 100), ("MDPS", 100), ("TCS", 50), - (cruise_btn_msg, 50), - ("CLUSTER_INFO", 4), + ("CRUISE_BUTTONS_ALT", 50), ("BLINKERS", 4), ("DOORS_SEATBELTS", 4), ] + if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS): + checks.append(("CRUISE_BUTTONS", 50)) + if CP.enableBsm: signals += [ ("FL_INDICATOR", "BLINDSPOTS_REAR_CORNERS"), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a32eba928e..57e3a05f4d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -2f83b9872fe991d21e07a95cc518f91f140a856a \ No newline at end of file +faa85c0cb3609fc43674b263ae885c60f136ba6c \ No newline at end of file From 4b2ecdcce76743e868d8668b5f704dddfed88198 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Dec 2022 21:21:39 -0800 Subject: [PATCH 0514/1179] deprecate carControl gas + brake fields --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 22b1431132..94fca76c42 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 22b1431132b038253a24ab3fbbe3af36ef93b95b +Subproject commit 94fca76c42dedc55f419ce813c6b0513fce2fe12 From 945415981d3d496efcd62bdc800c9014d4df3712 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 12 Dec 2022 21:23:32 -0800 Subject: [PATCH 0515/1179] Revert "deprecate carControl gas + brake fields" This reverts commit 4b2ecdcce76743e868d8668b5f704dddfed88198. --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 94fca76c42..22b1431132 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 94fca76c42dedc55f419ce813c6b0513fce2fe12 +Subproject commit 22b1431132b038253a24ab3fbbe3af36ef93b95b From 0aada196e0c0ec75d6d8a1b9d96c41576aff88a1 Mon Sep 17 00:00:00 2001 From: royjr Date: Tue, 13 Dec 2022 00:44:48 -0500 Subject: [PATCH 0516/1179] Honda Radarless: clean up disabled radar check (#26776) * exclude radarless cars * this was never an issue, but clean up some stuff * better Co-authored-by: Shane Smiskol --- selfdrive/car/honda/hondacan.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py index 87f8e6c5de..6861198158 100644 --- a/selfdrive/car/honda/hondacan.py +++ b/selfdrive/car/honda/hondacan.py @@ -13,7 +13,8 @@ def get_pt_bus(car_fingerprint): def get_lkas_cmd_bus(car_fingerprint, radar_disabled=False): - if radar_disabled: + no_radar = car_fingerprint in HONDA_BOSCH_RADARLESS + if radar_disabled or no_radar: # when radar is disabled, steering commands are sent directly to powertrain bus return get_pt_bus(car_fingerprint) # normally steering commands are sent to radar, which forwards them to powertrain bus @@ -104,7 +105,7 @@ def create_bosch_supplemental_1(packer, car_fingerprint): def create_ui_commands(packer, CP, enabled, pcm_speed, hud, is_metric, acc_hud, lkas_hud): commands = [] bus_pt = get_pt_bus(CP.carFingerprint) - radar_disabled = CP.carFingerprint in HONDA_BOSCH and CP.openpilotLongitudinalControl + radar_disabled = CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl bus_lkas = get_lkas_cmd_bus(CP.carFingerprint, radar_disabled) if CP.openpilotLongitudinalControl: @@ -153,7 +154,7 @@ def create_ui_commands(packer, CP, enabled, pcm_speed, hud, is_metric, acc_hud, else: commands.append(packer.make_can_msg('LKAS_HUD', bus_lkas, lkas_hud_values)) - if radar_disabled and CP.carFingerprint in HONDA_BOSCH: + if radar_disabled: radar_hud_values = { 'CMBS_OFF': 0x01, 'SET_TO_1': 0x01, From cecef89124be03eae55b6ee3bc33b3d5cdf7f93c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 14:31:36 +0800 Subject: [PATCH 0517/1179] Cabana: add signal value filters to the logs view (#26779) add filter to logs view --- tools/cabana/canmessages.cc | 24 --------- tools/cabana/canmessages.h | 3 -- tools/cabana/detailwidget.cc | 2 +- tools/cabana/detailwidget.h | 2 +- tools/cabana/historylog.cc | 100 ++++++++++++++++++++++++++++++----- tools/cabana/historylog.h | 28 ++++++++-- tools/cabana/signaledit.cc | 75 -------------------------- tools/cabana/signaledit.h | 7 --- 8 files changed, 113 insertions(+), 128 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index ded8be5fa3..767ed51d5e 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -32,30 +32,6 @@ bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint3 return false; } -QList CANMessages::findSignalValues(const QString &id, const Signal *signal, double value, FindFlags flag, int max_count) { - auto evts = events(); - if (!evts) return {}; - - QList ret; - ret.reserve(max_count); - auto [bus, address] = DBCManager::parseId(id); - for (auto &evt : *evts) { - if (evt->which != cereal::Event::Which::CAN) continue; - - for (const auto &c : evt->event.getCan()) { - if (bus == c.getSrc() && address == c.getAddress()) { - double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), *signal); - if ((flag == EQ && val == value) || (flag == LT && val < value) || (flag == GT && val > value)) { - ret.push_back({(evt->mono_time / (double)1e9) - can->routeStartTime(), val}); - if (ret.size() >= max_count) - return ret; - } - } - } - } - return ret; -} - void CANMessages::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { can_msgs[it.key()] = it.value(); diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 47f6008686..4dac4fe9df 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -4,7 +4,6 @@ #include #include -#include #include "opendbc/can/common_dbc.h" #include "tools/cabana/settings.h" @@ -21,12 +20,10 @@ class CANMessages : public QObject { Q_OBJECT public: - enum FindFlags{ EQ, LT, GT }; CANMessages(QObject *parent); ~CANMessages(); bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); void seekTo(double ts); - QList findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); bool eventFilter(const Event *event); inline QString routeName() const { return replay->route()->name(); } diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 77302b7d38..108aa8776e 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -86,7 +86,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget = new QTabWidget(this); tab_widget->setTabPosition(QTabWidget::South); tab_widget->addTab(scroll, "&Msg"); - history_log = new HistoryLog(this); + history_log = new LogsWidget(this); tab_widget->addTab(history_log, "&Logs"); main_layout->addWidget(tab_widget); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index d90438cab2..18c58ab6bf 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -53,7 +53,7 @@ private: QTabWidget *tab_widget; QToolBar *toolbar; QAction *remove_msg_act; - HistoryLog *history_log; + LogsWidget *history_log; BinaryView *binary_view; QScrollArea *scroll; ChartsWidget *charts; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 37001dd582..7cd974ad08 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -2,6 +2,8 @@ #include #include +#include +#include // HistoryLogModel @@ -17,7 +19,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { if (index.column() == 0) { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } - return !sigs.empty() ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); + return !sigs.empty() ? QString::number(m.sig_values[index.column() - 1]) : m.data; } else if (role == Qt::FontRole && index.column() == 1 && sigs.empty()) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); } @@ -26,15 +28,18 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { void HistoryLogModel::setMessage(const QString &message_id) { beginResetModel(); - msg_id = message_id; sigs.clear(); messages.clear(); has_more_data = true; if (auto dbc_msg = dbc()->msg(message_id)) { sigs = dbc_msg->getSignals(); } - endResetModel(); + if (msg_id != message_id || sigs.empty()) { + filter_cmp = nullptr; + } + msg_id = message_id; updateState(); + endResetModel(); } QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -53,6 +58,18 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i return {}; } +void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function cmp) { + if (sig_idx < sigs.size()) { + filter_sig_idx = sig_idx; + filter_value = value.toDouble(); + filter_cmp = value.isEmpty() ? nullptr : cmp; + beginResetModel(); + messages.clear(); + updateState(); + endResetModel(); + } +} + void HistoryLogModel::updateState() { if (!msg_id.isEmpty()) { uint64_t last_mono_time = messages.empty() ? 0 : messages.front().mono_time; @@ -87,20 +104,23 @@ std::deque HistoryLogModel::fetchData(uint64_t min_mon std::deque msgs; const auto [src, address] = DBCManager::parseId(msg_id); uint32_t cnt = 0; + QVector values(sigs.size()); for (--it; it != events->begin() && (*it)->mono_time > min_mono_time; --it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { if (src == c.getSrc() && address == c.getAddress()) { const auto dat = c.getDat(); - auto &m = msgs.emplace_back(); - m.mono_time = (*it)->mono_time; - m.data.append((char *)dat.begin(), dat.size()); - m.sig_values.reserve(sigs.size()); - for (const Signal *sig : sigs) { - m.sig_values.push_back(get_raw_value((uint8_t *)dat.begin(), dat.size(), *sig)); + for (int i = 0; i < sigs.size(); ++i) { + values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i])); + } + if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { + auto &m = msgs.emplace_back(); + m.mono_time = (*it)->mono_time; + m.data = toHex(QByteArray((char *)dat.begin(), dat.size())); + m.sig_values = values; + if (++cnt >= batch_size && min_mono_time == 0) + return msgs; } - if (++cnt >= batch_size && min_mono_time == 0) - return msgs; } } } @@ -132,12 +152,64 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI // HistoryLog HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { - model = new HistoryLogModel(this); - setModel(model); setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); verticalHeader()->setVisible(false); - setFrameShape(QFrame::NoFrame); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); } + +// LogsWidget + +LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + + filter_container = new QWidget(this); + QHBoxLayout *h = new QHBoxLayout(filter_container); + signals_cb = new QComboBox(this); + h->addWidget(signals_cb); + comp_box = new QComboBox(); + comp_box->addItems({">", "=", "<"}); + h->addWidget(comp_box); + value_edit = new QLineEdit(this); + value_edit->setClearButtonEnabled(true); + value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); + h->addWidget(value_edit); + main_layout->addWidget(filter_container); + + model = new HistoryLogModel(this); + logs = new HistoryLog(this); + logs->setModel(model); + main_layout->addWidget(logs); + + QObject::connect(signals_cb, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilter())); + QObject::connect(comp_box, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilter())); + QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); +} + +void LogsWidget::setMessage(const QString &message_id) { + blockSignals(true); + value_edit->setText(""); + signals_cb->clear(); + comp_box->setCurrentIndex(0); + sigs.clear(); + if (auto dbc_msg = dbc()->msg(message_id)) { + sigs = dbc_msg->getSignals(); + for (auto s : sigs) { + signals_cb->addItem(s->name.c_str()); + } + } + filter_container->setVisible(!sigs.empty()); + model->setMessage(message_id); + blockSignals(false); +} + +void LogsWidget::setFilter() { + std::function cmp; + switch (comp_box->currentIndex()) { + case 0: cmp = std::greater{}; break; + case 1: cmp = std::equal_to{}; break; + case 2: cmp = std::less{}; break; + } + model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); +} diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 5a9903823f..d5ae47192e 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include "tools/cabana/canmessages.h" @@ -19,6 +21,7 @@ public: HistoryLogModel(QObject *parent); void setMessage(const QString &message_id); void updateState(); + void setFilter(int sig_idx, const QString &value, std::function cmp); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void fetchMore(const QModelIndex &parent) override; @@ -29,13 +32,16 @@ public: struct Message { uint64_t mono_time = 0; QVector sig_values; - QByteArray data; + QString data; }; std::deque fetchData(uint64_t min_mono_time, uint64_t max_mono_time); QString msg_id; bool has_more_data = true; const int batch_size = 50; + int filter_sig_idx = -1; + double filter_value = 0; + std::function filter_cmp = nullptr; std::deque messages; std::vector sigs; }; @@ -43,11 +49,27 @@ public: class HistoryLog : public QTableView { public: HistoryLog(QWidget *parent); - void setMessage(const QString &message_id) { model->setMessage(message_id); } + int sizeHintForColumn(int column) const override { return -1; }; +}; + +class LogsWidget : public QWidget { + Q_OBJECT + +public: + LogsWidget(QWidget *parent); + void setMessage(const QString &message_id); void updateState() { model->updateState(); } +private slots: + void setFilter(); + private: - int sizeHintForColumn(int column) const override { return -1; }; void showEvent(QShowEvent *event) override { model->setMessage(model->msg_id); }; + + HistoryLog *logs; HistoryLogModel *model; + QWidget *filter_container; + QComboBox *signals_cb, *comp_box; + QLineEdit *value_edit; + std::vector sigs; }; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 85476c2302..b2491d5b1f 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -4,12 +4,8 @@ #include #include #include -#include -#include #include -#include "selfdrive/ui/qt/util.h" - // SignalForm SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { @@ -94,11 +90,6 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa plot_btn->setCheckable(true); plot_btn->setAutoRaise(true); title_layout->addWidget(plot_btn); - auto seek_btn = new QToolButton(this); - seek_btn->setText("🔍"); - seek_btn->setAutoRaise(true); - seek_btn->setToolTip(tr("Find signal values")); - title_layout->addWidget(seek_btn); auto remove_btn = new QToolButton(this); remove_btn->setAutoRaise(true); remove_btn->setText("x"); @@ -126,7 +117,6 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa 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(); }); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); @@ -212,68 +202,3 @@ void SignalEdit::leaveEvent(QEvent *event) { emit highlight(nullptr); QWidget::leaveEvent(event); } - -// SignalFindDlg - -SignalFindDlg::SignalFindDlg(const QString &id, const Signal *signal, QWidget *parent) : QDialog(parent) { - setWindowTitle(tr("Find signal values")); - QVBoxLayout *main_layout = new QVBoxLayout(this); - - QHBoxLayout *h = new QHBoxLayout(); - h->addWidget(new QLabel(signal->name.c_str())); - QComboBox *comp_box = new QComboBox(); - comp_box->addItems({">", "=", "<"}); - h->addWidget(comp_box); - QLineEdit *value_edit = new QLineEdit("0", this); - value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); - h->addWidget(value_edit, 1); - QPushButton *search_btn = new QPushButton(tr("Find"), this); - h->addWidget(search_btn); - main_layout->addLayout(h); - - QWidget *container = new QWidget(this); - QVBoxLayout *signals_layout = new QVBoxLayout(container); - QScrollArea *scroll = new QScrollArea(this); - scroll->setWidget(container); - scroll->setWidgetResizable(true); - scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - main_layout->addWidget(scroll); - - QObject::connect(search_btn, &QPushButton::clicked, [=]() { - clearLayout(signals_layout); - - CANMessages::FindFlags comp = CANMessages::EQ; - if (comp_box->currentIndex() == 0) { - comp = CANMessages::GT; - } else if (comp_box->currentIndex() == 2) { - comp = CANMessages::LT; - } - double value = value_edit->text().toDouble(); - - const int limit_results = 50; - auto values = can->findSignalValues(id, signal, value, comp, limit_results); - for (auto &v : values) { - QHBoxLayout *item_layout = new QHBoxLayout(); - item_layout->addWidget(new QLabel(QString::number(v.x(), 'f', 2))); - item_layout->addWidget(new QLabel(QString::number(v.y()))); - item_layout->addStretch(1); - - QPushButton *goto_btn = new QPushButton(tr("Goto"), this); - QObject::connect(goto_btn, &QPushButton::clicked, [sec = v.x()]() { can->seekTo(sec); }); - item_layout->addWidget(goto_btn); - signals_layout->addLayout(item_layout); - } - if (values.size() == limit_results) { - QFrame *hline = new QFrame(); - hline->setFrameShape(QFrame::HLine); - hline->setFrameShadow(QFrame::Sunken); - signals_layout->addWidget(hline); - QLabel *info = new QLabel(tr("Only display the first %1 results").arg(limit_results)); - info->setAlignment(Qt::AlignCenter); - signals_layout->addWidget(info); - } - if (values.size() * 30 > container->height()) { - scroll->setFixedHeight(std::min(values.size() * 30, 300)); - } - }); -} diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 205be4bb78..eec943226e 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -9,7 +8,6 @@ #include #include "selfdrive/ui/qt/widgets/controls.h" - #include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" @@ -59,8 +57,3 @@ protected: QToolButton *plot_btn; QTimer *save_timer; }; - -class SignalFindDlg : public QDialog { -public: - SignalFindDlg(const QString &id, const Signal *signal, QWidget *parent); -}; From 1e596f964c65ddec1303cebf9128e26df2379d90 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 15:04:36 +0800 Subject: [PATCH 0518/1179] Cabana: add not equal (!=) filter (#26780) add not equal filter --- tools/cabana/historylog.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 7cd974ad08..3e456e44e9 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -169,7 +169,7 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { signals_cb = new QComboBox(this); h->addWidget(signals_cb); comp_box = new QComboBox(); - comp_box->addItems({">", "=", "<"}); + comp_box->addItems({">", "=", "!=", "<"}); h->addWidget(comp_box); value_edit = new QLineEdit(this); value_edit->setClearButtonEnabled(true); @@ -204,12 +204,17 @@ void LogsWidget::setMessage(const QString &message_id) { blockSignals(false); } +static bool not_equal(double l, double r) { + return l != r; +} + void LogsWidget::setFilter() { std::function cmp; switch (comp_box->currentIndex()) { case 0: cmp = std::greater{}; break; case 1: cmp = std::equal_to{}; break; - case 2: cmp = std::less{}; break; + case 2: cmp = not_equal; break; + case 3: cmp = std::less{}; break; } model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); } From 72bf819ef06ee81f37d33f45979dfcf8d88b0ad3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 12 Dec 2022 23:41:29 -0800 Subject: [PATCH 0519/1179] HKG CAN-FD: log brake errors/ACC faults (#26781) * log brake_error * bumpopendbc * add signal to can parser --- opendbc | 2 +- selfdrive/car/hyundai/carstate.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/opendbc b/opendbc index bb71829028..4a7ad636ff 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit bb7182902847b84aa572733edfd8e7073bb02aeb +Subproject commit 4a7ad636ff806146a93f7ae541e463a7dfa5696d diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index cc8fbe3f08..91ec64538b 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -213,6 +213,7 @@ class CarState(CarStateBase): self.cruise_buttons.extend(cp.vl_all[cruise_btn_msg]["CRUISE_BUTTONS"]) self.main_buttons.extend(cp.vl_all[cruise_btn_msg]["ADAPTIVE_CRUISE_MAIN_BTN"]) self.buttons_counter = cp.vl[cruise_btn_msg]["COUNTER"] + self.brake_error = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED if self.CP.flags & HyundaiFlags.CANFD_HDA2: self.cam_0x2a4 = copy.copy(cp_cam.vl["CAM_0x2a4"]) @@ -434,6 +435,7 @@ class CarState(CarStateBase): ("LKA_FAULT", "MDPS"), ("DriverBraking", "TCS"), + ("ACCEnable", "TCS"), ("COUNTER", cruise_btn_msg), ("CRUISE_BUTTONS", cruise_btn_msg), From 9e9600a4f4fb69dd99cc24b791ccdd62540348f1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Dec 2022 00:16:36 -0800 Subject: [PATCH 0520/1179] Events: actionable accFaulted alert text (#26783) same alert text as steer and brake unavailable --- selfdrive/controls/lib/events.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 9fbf565328..3036828662 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -806,9 +806,9 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { }, EventName.accFaulted: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Faulted"), - ET.PERMANENT: NormalPermanentAlert("Cruise Faulted", ""), - ET.NO_ENTRY: NoEntryAlert("Cruise Faulted"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Fault: Restart the Car"), + ET.PERMANENT: NormalPermanentAlert("Cruise Fault: Restart the car to engage"), + ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), }, EventName.accFaultedTemp: { From 322dec1ec835e18a162b32dc75a293f57130ee62 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 16:19:04 +0800 Subject: [PATCH 0521/1179] Cabana: warn and exit if no rlogs in route (#26784) warn and exit if no rlogs in route --- tools/cabana/canmessages.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 767ed51d5e..ad3ee80e3d 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -26,6 +26,11 @@ bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint3 QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); QObject::connect(replay, &Replay::streamStarted, this, &CANMessages::streamStarted); if (replay->load()) { + const auto &segments = replay->route()->segments(); + if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { + qWarning() << "no rlogs in route" << route; + return false; + } replay->start(); return true; } From 6431f79fd27518ffe645fd35b11da92e32a74066 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 13 Dec 2022 16:20:51 +0800 Subject: [PATCH 0522/1179] Replay: add option -c to set segment cache size (#26782) add option to set cache size --- tools/replay/main.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/replay/main.cc b/tools/replay/main.cc index 40dace0c91..8621a9b978 100644 --- a/tools/replay/main.cc +++ b/tools/replay/main.cc @@ -23,6 +23,7 @@ int main(int argc, char *argv[]) { parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai"); parser.addOption({{"a", "allow"}, "whitelist of services to send", "allow"}); parser.addOption({{"b", "block"}, "blacklist of services to send", "block"}); + parser.addOption({{"c", "cache"}, "cache segments in memory. default is 5", "n"}); parser.addOption({{"s", "start"}, "start from ", "seconds"}); parser.addOption({"demo", "use a demo route instead of providing your own"}); parser.addOption({"data_dir", "local directory with routes", "data_dir"}); @@ -47,6 +48,9 @@ int main(int argc, char *argv[]) { } } Replay *replay = new Replay(route, allow, block, nullptr, replay_flags, parser.value("data_dir"), &app); + if (!parser.value("c").isEmpty()) { + replay->setSegmentCacheLimit(parser.value("c").toInt()); + } if (!replay->load()) { return 0; } From 1f774e4ec39d6f1ef7f8cb4224c0dbfd4dd4fe62 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Tue, 13 Dec 2022 03:21:58 -0500 Subject: [PATCH 0523/1179] HKG: Car Port for Genesis GV60 2022 (#26777) * HKG: Car Port for Genesis GV60 2022 * Ugh, keeps forgetting torque params * Update docs * Test route * more interesting segment Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/hyundai/interface.py | 4 ++++ selfdrive/car/hyundai/values.py | 15 +++++++++++++-- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 211e63a755..7d55887ec4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3,6 +3,7 @@ Version 0.9.1 (2022-12-XX) * Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! +* Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! diff --git a/docs/CARS.md b/docs/CARS.md index c92c0b2270..68d4442f91 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 219 Supported Cars +# 220 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -32,6 +32,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| +|Genesis|GV60 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index e271dc0e7d..aa6d88b55f 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -191,6 +191,10 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 13.27 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sorento-phev/2022/specifications # Genesis + elif candidate == CAR.GENESIS_GV60_EV_1ST_GEN: + ret.mass = 2205 + STD_CARGO_KG + ret.wheelbase = 2.9 + ret.steerRatio = 12.6 # https://www.motor1.com/reviews/586376/2023-genesis-gv60-first-drive/#:~:text=Relative%20to%20the%20related%20Ioniq,5%2FEV6%27s%2014.3%3A1. elif candidate == CAR.GENESIS_G70: ret.steerActuatorDelay = 0.1 ret.mass = 1640.0 + STD_CARGO_KG diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index c50b65f101..6e00802584 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -112,6 +112,7 @@ class CAR: KIA_EV6 = "KIA EV6 2022" # Genesis + GENESIS_GV60_EV_1ST_GEN = "GENESIS GV60 ELECTRIC 1ST GEN" GENESIS_G70 = "GENESIS G70 2018" GENESIS_G70_2020 = "GENESIS G70 2020" GENESIS_GV70_1ST_GEN = "GENESIS GV70 1ST GEN" @@ -218,6 +219,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { ], # Genesis + CAR.GENESIS_GV60_EV_1ST_GEN: HyundaiCarInfo("Genesis GV60 2023", "All", harness=Harness.hyundai_k), CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f), CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l), @@ -1512,6 +1514,14 @@ FW_VERSIONS = { b'\xf1\x00JK1_ SCC FHCUP 1.00 1.02 99110-AR000 ', ], }, + CAR.GENESIS_GV60_EV_1ST_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ', + ], + }, } CHECKSUM = { @@ -1529,7 +1539,7 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN} # The radar does SCC on these cars when HDA I, rather than the camera CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} @@ -1538,7 +1548,7 @@ CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # these cars use a different gas signal -EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5} +EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5, CAR.GENESIS_GV60_EV_1ST_GEN} # these cars require a special panda safety mode due to missing counters and checksums in the messages LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022} @@ -1596,4 +1606,5 @@ DBC = { CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None), CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None), + CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 89b895864a..3edc406e19 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -80,6 +80,7 @@ routes = [ CarTestRoute("f44aa96ace22f34a|2021-12-22--06-22-31", HONDA.CIVIC_2022), CarTestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS), + CarTestRoute("b5d6dc830ad63071|2022-12-12--21-28-25", HYUNDAI.GENESIS_GV60_EV_1ST_GEN, segment=12), CarTestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70), CarTestRoute("ca4de5b12321bd98|2022-10-18--21-15-59", HYUNDAI.GENESIS_GV70_1ST_GEN), CarTestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 1eda931e3e..d7b2ec4079 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -35,6 +35,7 @@ KIA SPORTAGE 5TH GEN: [2.7, 2.7, 0.1] KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.1] GENESIS GV70 1ST GEN: [2.42, 2.42, 0.1] KIA SORENTO PLUG-IN HYBRID 4TH GEN: [2.5, 2.5, 0.1] +GENESIS GV60 ELECTRIC 1ST GEN: [2.5, 2.5, 0.1] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From 6b36cfaf7e08fed204422f7faf37da1014d817c3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Dec 2022 00:37:13 -0800 Subject: [PATCH 0524/1179] HKG: log accFaulted (#26785) log accFaulted for HKG --- selfdrive/car/hyundai/carstate.py | 7 +++---- selfdrive/car/hyundai/interface.py | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 91ec64538b..6d471071d6 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -32,7 +32,6 @@ class CarState(CarStateBase): self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"] self.is_metric = False - self.brake_error = False self.buttons_counter = 0 self.cruise_info = {} @@ -105,8 +104,9 @@ class CarState(CarStateBase): # TODO: Find brake pressure ret.brake = 0 ret.brakePressed = cp.vl["TCS13"]["DriverBraking"] != 0 - ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY + ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1 + ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR): if self.CP.carFingerprint in HYBRID_CAR: @@ -147,7 +147,6 @@ class CarState(CarStateBase): self.lkas11 = copy.copy(cp_cam.vl["LKAS11"]) self.clu11 = copy.copy(cp.vl["CLU11"]) self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE - self.brake_error = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED self.prev_cruise_buttons = self.cruise_buttons[-1] self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"]) self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"]) @@ -213,7 +212,7 @@ class CarState(CarStateBase): self.cruise_buttons.extend(cp.vl_all[cruise_btn_msg]["CRUISE_BUTTONS"]) self.main_buttons.extend(cp.vl_all[cruise_btn_msg]["ADAPTIVE_CRUISE_MAIN_BTN"]) self.buttons_counter = cp.vl[cruise_btn_msg]["COUNTER"] - self.brake_error = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED + ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED if self.CP.flags & HyundaiFlags.CANFD_HDA2: self.cam_0x2a4 = copy.copy(cp_cam.vl["CAM_0x2a4"]) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index aa6d88b55f..811d629f70 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -312,9 +312,6 @@ class CarInterface(CarInterfaceBase): allow_enable = any(btn in ENABLE_BUTTONS for btn in self.CS.cruise_buttons) or any(self.CS.main_buttons) events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise, allow_enable=allow_enable) - if self.CS.brake_error: - events.add(EventName.brakeUnavailable) - # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s) if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.: self.low_speed_alert = True From bac56f78c9877daf56ff0edd413a14d4b04343c4 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Tue, 13 Dec 2022 03:42:50 -0500 Subject: [PATCH 0525/1179] Hyundai: Add FW Versions for 2017 i30 PD (Elantra GT) (#26760) * Hyundai: Add FW Versions for 2017 i30 PD * Update docs * Update docs * Update selfdrive/car/hyundai/values.py Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 68d4442f91..5c7fe57a89 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -61,7 +61,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| -|Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| |Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 6e00802584..cdcaf629af 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -140,7 +140,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.ELANTRA: [ HyundaiCarInfo("Hyundai Elantra 2017-19", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_b), HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e), - HyundaiCarInfo("Hyundai i30 2019", harness=Harness.hyundai_e), + HyundaiCarInfo("Hyundai i30 2017-19", harness=Harness.hyundai_e), ], CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), @@ -1281,18 +1281,23 @@ FW_VERSIONS = { CAR.ELANTRA: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00PD LKAS AT USA LHD 1.01 1.01 95740-G3100 A54', + b'\xf1\x00PD LKAS AT KOR LHD 1.00 1.02 95740-G3000 A51', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x006U2V0_C2\x00\x006U2VA051\x00\x00DPD0H16NS0e\x0e\xcd\x8e', + b'\xf1\x006U2U0_C2\x00\x006U2T0051\x00\x00DPD0D16KS0u\xce\x1fk', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00PD MDPS C 1.00 1.04 56310/G3300 4PDDC104', + b'\xf1\x00PD MDPS C 1.00 1.00 56310G3300\x00 4PDDC100', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00PD ESC \x0b 104\x18\t\x03 58920-G3350', + b'\xf1\x00PD ESC \t 104\x18\t\x03 58920-G3350', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00PD__ SCC F-CUP 1.00 1.00 96400-G3300 ', + b'\xf1\x00PD__ SCC FNCUP 1.01 1.00 96400-G3000 ', ], }, CAR.ELANTRA_2021: { From 9be7e527a908274522020481d3275b1ab6790c2e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 13 Dec 2022 14:33:20 -0800 Subject: [PATCH 0526/1179] HKG CAN-FD: steering pressed filter (#26789) * steering pressed filter * use a counter * parameterize * double * filter doesn't instantly reset on falling edge of true steering pressed * Update selfdrive/car/interfaces.py * Update selfdrive/car/interfaces.py * Update selfdrive/car/hyundai/carstate.py * add comment * the pain of committing without pycharm * more like a filter * Update ref_commit --- selfdrive/car/hyundai/carstate.py | 2 +- selfdrive/car/interfaces.py | 9 ++++++++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 6d471071d6..fc196528d7 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -188,7 +188,7 @@ class CarState(CarStateBase): ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1 ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"] ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"] - ret.steeringPressed = abs(ret.steeringTorque) > self.params.STEER_THRESHOLD + ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5) ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0 ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"]["LEFT_LAMP"], diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 0458178ee3..ad1fd22b90 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -8,7 +8,7 @@ from cereal import car from common.basedir import BASEDIR from common.conversions import Conversions as CV from common.kalman.simple_kalman import KF1D -from common.numpy_fast import interp +from common.numpy_fast import clip, interp from common.realtime import DT_CTRL from selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, apply_center_deadzone @@ -327,6 +327,7 @@ class CarStateBase(ABC): self.cruise_buttons = 0 self.left_blinker_cnt = 0 self.right_blinker_cnt = 0 + self.steering_pressed_cnt = 0 self.left_blinker_prev = False self.right_blinker_prev = False self.cluster_speed_hyst_gap = 0.0 @@ -364,6 +365,12 @@ class CarStateBase(ABC): self.right_blinker_cnt = blinker_time if right_blinker_lamp else max(self.right_blinker_cnt - 1, 0) return self.left_blinker_cnt > 0, self.right_blinker_cnt > 0 + def update_steering_pressed(self, steering_pressed, steering_pressed_min_count): + """Applies filtering on steering pressed for noisy driver torque signals.""" + self.steering_pressed_cnt += 1 if steering_pressed else -1 + self.steering_pressed_cnt = clip(self.steering_pressed_cnt, 0, steering_pressed_min_count * 2) + return self.steering_pressed_cnt > steering_pressed_min_count + def update_blinker_from_stalk(self, blinker_time: int, left_blinker_stalk: bool, right_blinker_stalk: bool): """Update blinkers from stalk position. When stalk is seen the blinker will be on for at least blinker_time, or until the stalk is turned off, whichever is longer. If the opposite stalk direction is seen the blinker diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 57e3a05f4d..342ab98b57 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -faa85c0cb3609fc43674b263ae885c60f136ba6c \ No newline at end of file +5f83a3ba20ec757ea7a5ef9b4159ac99cb77af0f From 2f80580fee32d25857eac605a7eb88e63fa1126f Mon Sep 17 00:00:00 2001 From: cydia2020 <12470297+cydia2020@users.noreply.github.com> Date: Wed, 14 Dec 2022 10:42:54 +1100 Subject: [PATCH 0527/1179] Toyota: keep Lane Sway Warning system (#24782) * Toyota: pass through sway warning system signals * signal doesn't seem to exist on the Prius V bad log? * remove duplicated checks * syntax * Revert "syntax" This reverts commit 6c30c30d46e55a3595d7e2519b448d49c2f08a66. * Revert "remove duplicated checks" This reverts commit 6a364984eb8adfb0ee61b87452730da389dd5ff1. * Revert "signal doesn't seem to exist on the Prius V" This reverts commit 57fa571fde79336a48c50b617755fb2f68b2f124. * Revert "Revert "signal doesn't seem to exist on the Prius V"" This reverts commit 9b1c3f6cacea74aa12a472bf02c469ffcd88eb24. * Revert "Revert "remove duplicated checks"" This reverts commit 38bc7f3de6011e81c8e5f825a15dc9ec2fdcf5b0. * Revert "Revert "syntax"" This reverts commit f81f93631f9a04406f818a2528680017635f229c. * hard code values for Prius V * send ui once every 25 frames remove send ui logic * send UI immediately on pcm_cancel_cmd * draft * clean that up * same order as toyotacan * update refs Co-authored-by: Shane Smiskol --- selfdrive/car/toyota/carcontroller.py | 2 +- selfdrive/car/toyota/carstate.py | 20 +++++++++++++++++++- selfdrive/car/toyota/toyotacan.py | 9 +++++++-- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 1f469c72be..6dbdd4b5d9 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -146,7 +146,7 @@ class CarController: if self.frame % 100 == 0 or send_ui: can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneDepart, - hud_control.rightLaneDepart, CC.enabled)) + hud_control.rightLaneDepart, CC.enabled, CS.lkas_hud)) if (self.frame % 100 == 0 or send_ui) and self.CP.enableDsu: can_sends.append(create_fcw_command(self.packer, fcw_alert)) diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 3be748c4cf..050f8747a2 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -1,3 +1,5 @@ +import copy + from cereal import car from common.conversions import Conversions as CV from common.numpy_fast import mean @@ -6,7 +8,7 @@ from common.realtime import DT_CTRL from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from selfdrive.car.interfaces import CarStateBase -from selfdrive.car.toyota.values import ToyotaFlags, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR +from selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR class CarState(CarStateBase): @@ -26,6 +28,7 @@ class CarState(CarStateBase): self.low_speed_lockout = False self.acc_type = 1 + self.lkas_hud = {} def update(self, cp, cp_cam): ret = car.CarState.new_message() @@ -140,6 +143,9 @@ class CarState(CarStateBase): ret.leftBlindspot = (cp.vl["BSM"]["L_ADJACENT"] == 1) or (cp.vl["BSM"]["L_APPROACHING"] == 1) ret.rightBlindspot = (cp.vl["BSM"]["R_ADJACENT"] == 1) or (cp.vl["BSM"]["R_APPROACHING"] == 1) + if self.CP.carFingerprint != CAR.PRIUS_V: + self.lkas_hud = copy.copy(cp_cam.vl["LKAS_HUD"]) + return ret @staticmethod @@ -254,6 +260,18 @@ class CarState(CarStateBase): signals = [] checks = [] + if CP.carFingerprint != CAR.PRIUS_V: + signals += [ + ("LANE_SWAY_FLD", "LKAS_HUD"), + ("LANE_SWAY_BUZZER", "LKAS_HUD"), + ("LANE_SWAY_WARNING", "LKAS_HUD"), + ("LANE_SWAY_SENSITIVITY", "LKAS_HUD"), + ("LANE_SWAY_TOGGLE", "LKAS_HUD"), + ] + checks += [ + ("LKAS_HUD", 1), + ] + if CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR): signals += [ ("PRECOLLISION_ACTIVE", "PRE_COLLISION"), diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index 7ab3ab3e78..7e360cc4e1 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -66,13 +66,13 @@ def create_fcw_command(packer, fcw): return packer.make_can_msg("ACC_HUD", 0, values) -def create_ui_command(packer, steer, chime, left_line, right_line, left_lane_depart, right_lane_depart, enabled): +def create_ui_command(packer, steer, chime, left_line, right_line, left_lane_depart, right_lane_depart, enabled, stock_lkas_hud): values = { "TWO_BEEPS": chime, "LDA_ALERT": steer, "RIGHT_LINE": 3 if right_lane_depart else 1 if right_line else 2, "LEFT_LINE": 3 if left_lane_depart else 1 if left_line else 2, - "BARRIERS" : 1 if enabled else 0, + "BARRIERS": 1 if enabled else 0, # static signals "SET_ME_X02": 2, @@ -96,4 +96,9 @@ def create_ui_command(packer, steer, chime, left_line, right_line, left_lane_dep "ADJUSTING_CAMERA": 0, "LDW_EXIST": 1, } + + # lane sway functionality + # not all cars have LKAS_HUD — update with camera values if available + values.update(stock_lkas_hud) + return packer.make_can_msg("LKAS_HUD", 0, values) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 342ab98b57..4f06673e97 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5f83a3ba20ec757ea7a5ef9b4159ac99cb77af0f +67a4bd615017128ce04d0836608d2c7f32432e3e \ No newline at end of file From 1b9771528b8d6b2c14e486ecda938ee7c13d36da Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 13 Dec 2022 20:24:12 -0800 Subject: [PATCH 0528/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 4edd1a6021..9e5c28e568 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 4edd1a602131ec2f09a604a4bd28e7d00e334458 +Subproject commit 9e5c28e568a1efe4bac340b48b3c16aafc82e84c From ffb709e6a68c8dd254f96bbf05f6799370352e7f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 14 Dec 2022 12:25:29 +0800 Subject: [PATCH 0529/1179] Cabana: add auto completion for Msg selector (#26788) --- tools/cabana/chartswidget.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index b0e6a2a164..bc28666a34 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,5 +1,7 @@ #include "tools/cabana/chartswidget.h" +#include +#include #include #include #include @@ -550,7 +552,14 @@ SeriesSelector::SeriesSelector(QWidget *parent) { QVBoxLayout *left_layout = new QVBoxLayout(); left_layout->addWidget(new QLabel(tr("Select Signals:"))); + msgs_combo = new QComboBox(this); + msgs_combo->setEditable(true); + msgs_combo->lineEdit()->setPlaceholderText(tr("Select Msg")); + msgs_combo->setInsertPolicy(QComboBox::NoInsert); + msgs_combo->completer()->setCompletionMode(QCompleter::PopupCompletion); + msgs_combo->completer()->setFilterMode(Qt::MatchContains); + left_layout->addWidget(msgs_combo); sig_list = new QListWidget(this); sig_list->setSortingEnabled(true); From 68272449e1775df2326f7f62d1f4868c701dff29 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 14 Dec 2022 12:25:50 +0800 Subject: [PATCH 0530/1179] Cabana: improve DBC file selector (#26787) --- tools/cabana/dbcmanager.cc | 2 -- tools/cabana/mainwin.cc | 53 ++++++++++++++++++++++++-------------- tools/cabana/mainwin.h | 2 ++ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 6d59cba7b6..01bdff17a1 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -32,8 +32,6 @@ void DBCManager::initMsgMap() { } QString DBCManager::generateDBC() { - if (!dbc) return {}; - QString dbc_string; for (auto &[address, m] : msgs) { dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 70297f9978..f14d522c20 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -18,8 +18,6 @@ #include #include -#include "tools/replay/util.h" - static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (type == QtDebugMsg) std::cout << msg.toStdString() << std::endl; @@ -36,19 +34,13 @@ MainWindow::MainWindow() : QMainWindow() { splitter = new QSplitter(Qt::Horizontal, this); splitter->setHandleWidth(11); - // DBC file selector QWidget *messages_container = new QWidget(this); QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); messages_layout->setContentsMargins(0, 0, 0, 0); - dbc_combo = new QComboBox(this); - auto dbc_names = dbc()->allDBCNames(); - for (const auto &name : dbc_names) { - dbc_combo->addItem(QString::fromStdString(name)); - } - dbc_combo->model()->sort(0); - dbc_combo->setInsertPolicy(QComboBox::NoInsert); - messages_layout->addWidget(dbc_combo); + // left panel + dbc_combo = createDBCSelector(); + messages_layout->addWidget(dbc_combo); messages_widget = new MessagesWidget(this); messages_layout->addWidget(messages_widget); splitter->addWidget(messages_container); @@ -109,11 +101,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); QObject::connect(can, &CANMessages::streamStarted, this, &MainWindow::loadDBCFromFingerprint); - QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { - detail_widget->undo_stack->clear(); - dbc_combo->setCurrentText(QFileInfo(dbc()->name()).baseName()); - setWindowTitle(tr("%1 - Cabana").arg(dbc()->name())); - }); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(detail_widget->undo_stack, &QUndoStack::indexChanged, [this](int index) { setWindowTitle(tr("%1%2 - Cabana").arg(index > 0 ? "* " : "").arg(dbc()->name())); }); @@ -149,6 +137,23 @@ void MainWindow::createActions() { help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } +QComboBox *MainWindow::createDBCSelector() { + QComboBox *c = new QComboBox(this); + c->setEditable(true); + c->lineEdit()->setPlaceholderText(tr("Select from an existing DBC file")); + c->setInsertPolicy(QComboBox::NoInsert); + c->completer()->setCompletionMode(QCompleter::PopupCompletion); + c->completer()->setFilterMode(Qt::MatchContains); + + auto dbc_names = dbc()->allDBCNames(); + std::sort(dbc_names.begin(), dbc_names.end()); + for (const auto &name : dbc_names) { + c->addItem(QString::fromStdString(name)); + } + c->setCurrentIndex(-1); + return c; +} + void MainWindow::createStatusBar() { progress_bar = new QProgressBar(); progress_bar->setRange(0, 100); @@ -164,9 +169,17 @@ void MainWindow::createShortcuts() { // TODO: add more shortcuts here. } +void MainWindow::DBCFileChanged() { + detail_widget->undo_stack->clear(); + int index = dbc_combo->findText(QFileInfo(dbc()->name()).baseName()); + dbc_combo->setCurrentIndex(index); + setWindowTitle(tr("%1 - Cabana").arg(dbc()->name())); +} + void MainWindow::loadDBCFromName(const QString &name) { - if (name != dbc()->name()) + if (name != dbc()->name()) { dbc()->open(name); + } } void MainWindow::loadDBCFromFile() { @@ -189,13 +202,15 @@ void MainWindow::loadDBCFromClipboard() { void MainWindow::loadDBCFromFingerprint() { auto fingerprint = can->carFingerprint(); - fingerprint_label->setText(fingerprint); - if (!fingerprint.isEmpty() && dbc()->name().isEmpty()) { + fingerprint_label->setText(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint); + if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { loadDBCFromName(dbc_name.toString()); + return; } } + dbc()->open("New_DBC", ""); } void MainWindow::saveDBCToFile() { diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 5d377c44ca..17c513d809 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -34,9 +34,11 @@ signals: protected: void createActions(); + QComboBox *createDBCSelector(); void createStatusBar(); void createShortcuts(); void closeEvent(QCloseEvent *event) override; + void DBCFileChanged(); void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); From 41681e1de102e74d73fe7e13257d51681dcc8b4c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 14 Dec 2022 01:56:57 -0800 Subject: [PATCH 0531/1179] HKG CAN-FD: remove duplicate FW versions (#26793) * remove duplicate FW version * Update values.py --- selfdrive/car/hyundai/values.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index cdcaf629af..db2bee991e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1447,7 +1447,6 @@ FW_VERSIONS = { CAR.KIA_EV6: { (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 ', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.05 99210-CV000 211027', @@ -1459,7 +1458,6 @@ FW_VERSIONS = { CAR.IONIQ_5: { (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 ', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206', From 6fe592c678427b17c48f79487d12e9aed75ac551 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 14 Dec 2022 04:57:17 -0500 Subject: [PATCH 0532/1179] Hyundai: Add FW Versions for Southeast Asia 2022 Ioniq 5 HDA1 (#26755) * Hyundai: Add FW Versions for 2022 Ioniq 5 HDA1 * Check IONIQ_5 fwdCamera FW to segregate radar and camera SCC cars * Test things out * Is it that simple? * Revert "Is it that simple?" This reverts commit 6d48945925597fa686a7c6c534960487bb811e26. * Revert "Test things out" This reverts commit 772cd5f47ab4d92c6ba69e77f44ba3799849d399. * Revert "Check IONIQ_5 fwdCamera FW to segregate radar and camera SCC cars" This reverts commit 3ca1a2d6faa02e86b8fa628985cd5d76e1763688. * No ADAS ECU detected, but has all messages for HDA2 * Check DISTANCE_UNIT on CRUISE_BUTTONS * Revert "Check DISTANCE_UNIT on CRUISE_BUTTONS" This reverts commit 9cbfe520f3406f8b1d66a56608a80417fea54871. * Check DISTANCE_UNIT on CRUISE_BUTTONS for all CAN-FD HKG * Update selfdrive/car/hyundai/interface.py Co-authored-by: Shane Smiskol * Test fingerprint * Southeast Asia specific * Revert "Test fingerprint" This reverts commit 33bb30b750c09f6d11e1b04d72e47f9354bdc9d5. * updatedocs * rename Co-authored-by: Shane Smiskol --- docs/CARS.md | 3 ++- selfdrive/car/hyundai/values.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index 5c7fe57a89..6ae647efcf 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 220 Supported Cars +# 221 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -62,6 +62,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| |Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index db2bee991e..240c9b6000 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -172,6 +172,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, harness=Harness.hyundai_e), CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-22", "All", harness=Harness.hyundai_a), CAR.IONIQ_5: [ + HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", harness=Harness.hyundai_q), HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", harness=Harness.hyundai_k), HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", harness=Harness.hyundai_q), ], @@ -1463,6 +1464,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', + b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', ], }, CAR.TUCSON_4TH_GEN: { From 0c1fbe22b4d83ee5873c992d02b9bc46fd16ae7b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 14 Dec 2022 02:19:09 -0800 Subject: [PATCH 0533/1179] soundd: increase upper bound for volume level (#26792) Update sound.cc --- selfdrive/ui/soundd/sound.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index 42fc9c4b1a..21afd92b1c 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -48,7 +48,7 @@ void Sound::update() { // scale volume using ambient noise level if (sm.updated("microphone")) { - float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 54.f, 0.f, 1.f); + float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 56.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); Hardware::set_volume(volume); } From a143ebf6486480dfa6e2c67a7f68dcb1b9e329a3 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 14 Dec 2022 17:05:13 -0500 Subject: [PATCH 0534/1179] HKG: Add FW Versions for Southeast Asia Kia EV6 2022 HDA1 (#26795) HKG: Add FW Versions for Southeast Asia Kia EV6 2022 --- docs/CARS.md | 3 ++- selfdrive/car/hyundai/values.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index 6ae647efcf..4f1a7cb652 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 221 Supported Cars +# 222 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -93,6 +93,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| |Kia|EV6 (with HDA II) 2022[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| |Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 240c9b6000..a90797ae18 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -215,6 +215,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness=Harness.hyundai_k), CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e), CAR.KIA_EV6: [ + HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", harness=Harness.hyundai_p), HyundaiCarInfo("Kia EV6 (without HDA II) 2022", "Highway Driving Assist", harness=Harness.hyundai_l), HyundaiCarInfo("Kia EV6 (with HDA II) 2022", "Highway Driving Assist II", harness=Harness.hyundai_p) ], @@ -1454,6 +1455,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', + b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', ], }, CAR.IONIQ_5: { From 9743b37cf2b7c3b07a21c52b8be687659fb9b4bb Mon Sep 17 00:00:00 2001 From: royjr Date: Wed, 14 Dec 2022 18:51:24 -0500 Subject: [PATCH 0535/1179] Honda: set MINI_CAR when engaged (#26797) * Update hondacan.py * update refs Co-authored-by: Shane Smiskol --- selfdrive/car/honda/hondacan.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py index 6861198158..17681444af 100644 --- a/selfdrive/car/honda/hondacan.py +++ b/selfdrive/car/honda/hondacan.py @@ -111,7 +111,7 @@ def create_ui_commands(packer, CP, enabled, pcm_speed, hud, is_metric, acc_hud, if CP.openpilotLongitudinalControl: acc_hud_values = { 'CRUISE_SPEED': hud.v_cruise, - 'ENABLE_MINI_CAR': 1, + 'ENABLE_MINI_CAR': 1 if enabled else 0, 'HUD_DISTANCE': 0, # max distance setting on display 'IMPERIAL_UNIT': int(not is_metric), 'HUD_LEAD': 2 if enabled and hud.lead_visible else 1 if enabled else 0, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4f06673e97..f72e160ddb 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -67a4bd615017128ce04d0836608d2c7f32432e3e \ No newline at end of file +358d330ffde4ecd679129b0e0a20806aaf21b786 \ No newline at end of file From 8d95faf97a0717be33ec12f9039efd22fad36857 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 14 Dec 2022 17:17:25 -0800 Subject: [PATCH 0536/1179] nav: add README (#26802) * start docs * Update README.md --- selfdrive/navd/README.md | 24 +++++++++++++++++++ .../{ui/qt/maps => navd}/set_destination.py | 0 2 files changed, 24 insertions(+) create mode 100644 selfdrive/navd/README.md rename selfdrive/{ui/qt/maps => navd}/set_destination.py (100%) diff --git a/selfdrive/navd/README.md b/selfdrive/navd/README.md new file mode 100644 index 0000000000..6c7f7eabe3 --- /dev/null +++ b/selfdrive/navd/README.md @@ -0,0 +1,24 @@ +# navigation + +This directory contains two daemons, `navd` and `map_renderer`, which support navigation in the openpilot stack. + +### navd + +`navd` takes in a route through the `NavDestination` param and sends out two packets: `navRoute` and `navInstruction`. These packets contain the coordinates of the planned route and turn-by-turn instructions. + +### map renderer + +The map renderer listens for the `navRoute` and publishes a rendered map view over VisionIPC for the navigation model, which lives in `selfdrive/modeld/`. The rendered maps look like this: + +![](https://i.imgur.com/oZLfmwq.png) + +## development + +Currently, [mapbox](https://www.mapbox.com/) is used for navigation. + +* get an API token: https://docs.mapbox.com/help/glossary/access-token/ +* set an API token using the `MAPBOX_TOKEN` environment variable +* routes/destinations are set through the `NavDestination` param + * use `set_destination.py` for debugging +* edit the map: https://www.mapbox.com/contribute +* mapbox API playground: https://docs.mapbox.com/playground/ diff --git a/selfdrive/ui/qt/maps/set_destination.py b/selfdrive/navd/set_destination.py similarity index 100% rename from selfdrive/ui/qt/maps/set_destination.py rename to selfdrive/navd/set_destination.py From be9a3fad377fbc6c0cd6d9a3c12f77fb0a3f299a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 14 Dec 2022 18:48:39 -0800 Subject: [PATCH 0537/1179] nav: add setting for extra coordinates to specify route (#26803) --- common/params.cc | 1 + selfdrive/navd/navd.py | 22 +++++++++++++++++++--- selfdrive/navd/set_destination.py | 29 ++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/common/params.cc b/common/params.cc index 9e3e32d584..8f6532bc79 100644 --- a/common/params.cc +++ b/common/params.cc @@ -149,6 +149,7 @@ std::unordered_map keys = { {"LiveTorqueCarParams", PERSISTENT}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, + {"NavDestinationWaypoints", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"NavSettingTime24h", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT}, {"NavdRender", PERSISTENT}, diff --git a/selfdrive/navd/navd.py b/selfdrive/navd/navd.py index 4855b63594..277b84b927 100755 --- a/selfdrive/navd/navd.py +++ b/selfdrive/navd/navd.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import json import math import os import threading @@ -135,12 +136,27 @@ class RouteEngine: 'language': lang, } - if self.last_bearing is not None: - params['bearings'] = f"{(self.last_bearing + 360) % 360:.0f},90;" + # TODO: move waypoints into NavDestination param? + waypoints = self.params.get('NavDestinationWaypoints', encoding='utf8') + waypoint_coords = [] + if waypoints is not None and len(waypoints) > 0: + waypoint_coords = json.loads(waypoints) - url = self.mapbox_host + f'/directions/v5/mapbox/driving-traffic/{self.last_position.longitude},{self.last_position.latitude};{destination.longitude},{destination.latitude}' + coords = [ + (self.last_position.longitude, self.last_position.latitude), + *waypoint_coords, + (destination.longitude, destination.latitude) + ] + params['waypoints'] = f'0;{len(coords)-1}' + if self.last_bearing is not None: + params['bearings'] = f"{(self.last_bearing + 360) % 360:.0f},90" + (';'*(len(coords)-1)) + + coords_str = ';'.join([f'{lon},{lat}' for lon, lat in coords]) + url = self.mapbox_host + '/directions/v5/mapbox/driving-traffic/' + coords_str try: resp = requests.get(url, params=params, timeout=10) + if resp.status_code != 200: + cloudlog.event("API request failed", status_code=resp.status_code, text=resp.text, error=True) resp.raise_for_status() r = resp.json() diff --git a/selfdrive/navd/set_destination.py b/selfdrive/navd/set_destination.py index b9721171cc..e6158dbdee 100755 --- a/selfdrive/navd/set_destination.py +++ b/selfdrive/navd/set_destination.py @@ -5,6 +5,29 @@ import sys from common.params import Params if __name__ == "__main__": - coords = sys.argv[1].split("/@")[-1].split("/")[0].split(",") - dest = {"latitude": float(coords[0]), "longitude": float(coords[1])} - Params().put("NavDestination", json.dumps(dest)) + params = Params() + + # set from google maps url + if len(sys.argv) > 1: + coords = sys.argv[1].split("/@")[-1].split("/")[0].split(",") + dest = { + "latitude": float(coords[0]), + "longitude": float(coords[1]) + } + params.put("NavDestination", json.dumps(dest)) + params.remove("NavDestinationWaypoints") + else: + print("Setting to Taco Bell") + dest = { + "latitude": 32.71160109904473, + "longitude": -117.12556569985693, + } + params.put("NavDestination", json.dumps(dest)) + + waypoints = [ + (-117.16020713111648, 32.71997612490662), + ] + params.put("NavDestinationWaypoints", json.dumps(waypoints)) + + print(dest) + print(waypoints) From 2ac87a0a456ee4a2ffc66986c86e5c7e5d44f930 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 15 Dec 2022 01:14:28 -0500 Subject: [PATCH 0538/1179] add German translation to release notes (#26806) --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index 7d55887ec4..eea69d295f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,6 +2,7 @@ Version 0.9.1 (2022-12-XX) ======================== * Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted +* New German translation thanks to Vrabetz and CzokNorris! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support From 951ceecadd555abac3eea67fe655ddc33dc48b1f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 15 Dec 2022 10:38:44 -0800 Subject: [PATCH 0539/1179] navd: avoid re-routing back to past waypoints --- selfdrive/navd/navd.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/navd/navd.py b/selfdrive/navd/navd.py index 277b84b927..f2de9261ab 100755 --- a/selfdrive/navd/navd.py +++ b/selfdrive/navd/navd.py @@ -191,6 +191,10 @@ class RouteEngine: cloudlog.warning("Got empty route response") self.clear_route() + # clear waypoints to avoid a re-route including past waypoints + # TODO: only clear once we're past a waypoint + self.params.remove('NavDestinationWaypoints') + except requests.exceptions.RequestException: cloudlog.exception("failed to get route") self.clear_route() From 08b4cff484940b394fa64d89dad65330bcb51a4a Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 15 Dec 2022 10:51:21 -0800 Subject: [PATCH 0540/1179] navd: recompute if far for > 3 steps (#26798) * navd: recompute if far for > 3 steps * typo * reset and unindent --- selfdrive/navd/navd.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/selfdrive/navd/navd.py b/selfdrive/navd/navd.py index f2de9261ab..81e3bdb3df 100755 --- a/selfdrive/navd/navd.py +++ b/selfdrive/navd/navd.py @@ -22,6 +22,7 @@ from system.swaglog import cloudlog REROUTE_DISTANCE = 25 MANEUVER_TRANSITION_THRESHOLD = 10 VALID_POS_STD = 50.0 +REROUTE_COUNTER_MIN = 3 class RouteEngine: @@ -48,6 +49,8 @@ class RouteEngine: self.ui_pid = None + self.reroute_counter = 0 + if "MAPBOX_TOKEN" in os.environ: self.mapbox_token = os.environ["MAPBOX_TOKEN"] self.mapbox_host = "https://api.mapbox.com" @@ -114,6 +117,7 @@ class RouteEngine: self.recompute_countdown = 2**self.recompute_backoff self.recompute_backoff = min(6, self.recompute_backoff + 1) self.calculate_route(new_destination) + self.reroute_counter = 0 else: self.recompute_countdown = max(0, self.recompute_countdown - 1) @@ -305,8 +309,11 @@ class RouteEngine: min_d = min(min_d, minimum_distance(a, b, self.last_position)) - return min_d > REROUTE_DISTANCE - + if min_d > REROUTE_DISTANCE: + self.reroute_counter += 1 + else: + self.reroute_counter = 0 + return self.reroute_counter > REROUTE_COUNTER_MIN # TODO: Check for going wrong way in segment From 0fd8e6f491264500a22d80c106ad1f6d78e99dc9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Dec 2022 15:34:44 -0800 Subject: [PATCH 0541/1179] soundd: increase upper bound for volume level (#26811) Raise soundd upper limit --- selfdrive/ui/soundd/sound.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index 21afd92b1c..49c28373c5 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -48,7 +48,7 @@ void Sound::update() { // scale volume using ambient noise level if (sm.updated("microphone")) { - float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 56.f, 0.f, 1.f); + float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 60.f, 0.f, 1.f); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); Hardware::set_volume(volume); } From aab33b1c5f56eb7ef66f1128c98d45d5340ebc60 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Dec 2022 21:52:07 -0800 Subject: [PATCH 0542/1179] Lateral jerk unit test (#25759) * stash * more test * less test * clean test * no angle * add tolerance * fix gm fix gm * test both * lower some rates on hkg * stash * simpler * bump panda * Revert "bump panda" This reverts commit f2137c221145cca723fe6ee3378ba947b7061965. * only torque * make kona pass * duplicate __init__ * move * half clean up * half clean up * more clean up * more clean up * fix static analysis * calculate over 0.5 seconds * limit to max steer * type annotation * calc once --- selfdrive/car/body/values.py | 3 + selfdrive/car/chrysler/carcontroller.py | 2 +- selfdrive/car/chrysler/values.py | 1 + selfdrive/car/ford/carcontroller.py | 2 +- selfdrive/car/ford/values.py | 5 +- selfdrive/car/gm/carcontroller.py | 2 +- selfdrive/car/gm/values.py | 2 +- selfdrive/car/hyundai/carcontroller.py | 3 +- selfdrive/car/hyundai/values.py | 1 + selfdrive/car/mazda/values.py | 4 + selfdrive/car/nissan/values.py | 3 + selfdrive/car/tesla/values.py | 3 + selfdrive/car/tests/test_lateral_limits.py | 97 ++++++++++++++++++++++ selfdrive/car/toyota/values.py | 1 + selfdrive/car/volkswagen/carcontroller.py | 6 +- selfdrive/car/volkswagen/values.py | 2 +- 16 files changed, 126 insertions(+), 11 deletions(-) create mode 100755 selfdrive/car/tests/test_lateral_limits.py diff --git a/selfdrive/car/body/values.py b/selfdrive/car/body/values.py index 548039bc70..4fef966374 100644 --- a/selfdrive/car/body/values.py +++ b/selfdrive/car/body/values.py @@ -17,6 +17,9 @@ class CarControllerParams: LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower STEER_THRESHOLD = 1.0 + def __init__(self, CP): + pass + class CAR: BODY = "COMMA BODY" diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 31cd01b654..ba6aaf8250 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -45,7 +45,7 @@ class CarController: self.hud_count += 1 # steering - if self.frame % 2 == 0: + if self.frame % self.params.STEER_STEP == 0: # TODO: can we make this more sane? why is it different for all the cars? lkas_control_bit = self.lkas_control_bit_prev diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 02261a0b63..7629a2f086 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -35,6 +35,7 @@ class CAR: class CarControllerParams: def __init__(self, CP): + self.STEER_STEP = 2 # 50 Hz self.STEER_ERROR_MAX = 80 if CP.carFingerprint in RAM_HD: self.STEER_DELTA_UP = 14 diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index f18014601c..8c391bb276 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -66,7 +66,7 @@ class CarController: apply_angle = 0. # send steering commands at 20Hz - if (self.frame % CarControllerParams.LKAS_STEER_STEP) == 0: + if (self.frame % CarControllerParams.STEER_STEP) == 0: # use LatCtlPath_An_Actl to actuate steering path_angle = math.radians(apply_angle) / CarControllerParams.LKAS_STEER_RATIO diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 5114f8d065..0e6ef464b3 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -17,7 +17,7 @@ AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_p class CarControllerParams: # Messages: Lane_Assist_Data1, LateralMotionControl - LKAS_STEER_STEP = 5 + STEER_STEP = 5 # Message: IPMA_Data LKAS_UI_STEP = 100 # Message: ACCDATA_3 @@ -32,6 +32,9 @@ class CarControllerParams: RATE_LIMIT_UP = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., .8, .15]) RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) + def __init__(self, CP): + pass + class CANBUS: main = 0 diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index d380abf8e3..b4a79d10a6 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -53,7 +53,7 @@ class CarController: init_lka_counter = not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera steer_step = self.params.INACTIVE_STEER_STEP if CC.latActive or init_lka_counter: - steer_step = self.params.ACTIVE_STEER_STEP + steer_step = self.params.STEER_STEP # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the # next Panda loopback confirmation in the current CS frame. diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 84fa36a994..ece128c253 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -11,7 +11,7 @@ Ecu = car.CarParams.Ecu class CarControllerParams: STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output - ACTIVE_STEER_STEP = 2 # Active control frames per command (50hz) + STEER_STEP = 2 # Active control frames per command (50hz) INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) STEER_DELTA_UP = 7 # Delta rates require review due to observed EPS weakness STEER_DELTA_DOWN = 17 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 5582499f25..b81c5e3f7d 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -59,8 +59,7 @@ class CarController: hud_control = CC.hudControl # steering torque - steer = actuators.steer - new_steer = int(round(steer * self.params.STEER_MAX)) + new_steer = int(round(actuators.steer * self.params.STEER_MAX)) apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) if not CC.latActive: diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index a90797ae18..4d3f44d65f 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -23,6 +23,7 @@ class CarControllerParams: self.STEER_DRIVER_MULTIPLIER = 2 self.STEER_DRIVER_FACTOR = 1 self.STEER_THRESHOLD = 150 + self.STEER_STEP = 1 # 100 Hz if CP.carFingerprint in CANFD_CAR: self.STEER_MAX = 270 diff --git a/selfdrive/car/mazda/values.py b/selfdrive/car/mazda/values.py index e6e9b3aee8..598b598a16 100644 --- a/selfdrive/car/mazda/values.py +++ b/selfdrive/car/mazda/values.py @@ -20,6 +20,10 @@ class CarControllerParams: STEER_DRIVER_MULTIPLIER = 1 # weight driver torque STEER_DRIVER_FACTOR = 1 # from dbc STEER_ERROR_MAX = 350 # max delta between torque cmd and torque motor + STEER_STEP = 1 # 100 Hz + + def __init__(self, CP): + pass class CAR: diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index a6ee27a4a3..6371b56be8 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -17,6 +17,9 @@ class CarControllerParams: LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower STEER_THRESHOLD = 1.0 + def __init__(self, CP): + pass + class CAR: XTRAIL = "NISSAN X-TRAIL 2017" diff --git a/selfdrive/car/tesla/values.py b/selfdrive/car/tesla/values.py index 52f2aedf98..bac025a9c5 100644 --- a/selfdrive/car/tesla/values.py +++ b/selfdrive/car/tesla/values.py @@ -108,3 +108,6 @@ class CarControllerParams: JERK_LIMIT_MAX = 8 JERK_LIMIT_MIN = -8 ACCEL_TO_SPEED_MULTIPLIER = 3 + + def __init__(self, CP): + pass diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py new file mode 100755 index 0000000000..a82c20ce01 --- /dev/null +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +from collections import defaultdict +import importlib +from parameterized import parameterized_class +import sys +from typing import DefaultDict, Dict +import unittest + +from common.realtime import DT_CTRL +from selfdrive.car.car_helpers import interfaces +from selfdrive.car.fingerprints import all_known_cars +from selfdrive.car.interfaces import get_torque_params +from selfdrive.car.hyundai.values import CAR as HYUNDAI + +CAR_MODELS = all_known_cars() + +# ISO 11270 +MAX_LAT_JERK = 2.5 # m/s^3 +MAX_LAT_JERK_TOLERANCE = 0.75 # m/s^3 +MAX_LAT_ACCEL = 3.0 # m/s^2 + +# jerk is measured over half a second +JERK_MEAS_FRAMES = 0.5 / DT_CTRL + +# TODO: update the max measured lateral accel for these cars +ABOVE_LIMITS_CARS = [ + HYUNDAI.KONA_EV, + HYUNDAI.KONA_HEV, + HYUNDAI.KONA, + HYUNDAI.KONA_EV_2022, +] + +car_model_jerks: DefaultDict[str, Dict[str, float]] = defaultdict(dict) + + +@parameterized_class('car_model', [(c,) for c in CAR_MODELS]) +class TestLateralLimits(unittest.TestCase): + car_model: str + + @classmethod + def setUpClass(cls): + CarInterface, _, _ = interfaces[cls.car_model] + CP = CarInterface.get_params(cls.car_model) + + if CP.dashcamOnly: + raise unittest.SkipTest("Platform is behind dashcamOnly") + + # TODO: test all platforms + if CP.lateralTuning.which() != 'torque': + raise unittest.SkipTest + + if CP.notCar: + raise unittest.SkipTest + + if CP.carFingerprint in ABOVE_LIMITS_CARS: + raise unittest.SkipTest + + CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams + cls.control_params = CarControllerParams(CP) + cls.torque_params = get_torque_params(cls.car_model) + + @staticmethod + def calculate_0_5s_jerk(control_params, torque_params): + steer_step = control_params.STEER_STEP + steer_up_per_frame = (control_params.STEER_DELTA_UP / control_params.STEER_MAX) / steer_step + steer_down_per_frame = (control_params.STEER_DELTA_DOWN / control_params.STEER_MAX) / steer_step + + steer_up_0_5_sec = min(steer_up_per_frame * JERK_MEAS_FRAMES, 1.0) + steer_down_0_5_sec = min(steer_down_per_frame * JERK_MEAS_FRAMES, 1.0) + + max_lat_accel = torque_params['MAX_LAT_ACCEL_MEASURED'] + return steer_up_0_5_sec * max_lat_accel, steer_down_0_5_sec * max_lat_accel + + def test_jerk_limits(self): + up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params) + car_model_jerks[self.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk} + self.assertLessEqual(up_jerk, MAX_LAT_JERK + MAX_LAT_JERK_TOLERANCE) + self.assertLessEqual(down_jerk, MAX_LAT_JERK + MAX_LAT_JERK_TOLERANCE) + + def test_max_lateral_accel(self): + self.assertLessEqual(self.torque_params["MAX_LAT_ACCEL_MEASURED"], MAX_LAT_ACCEL) + + +if __name__ == "__main__": + result = unittest.main(exit=False) + + print(f"\n\n---- Lateral limit report ({len(CAR_MODELS)} cars) ----\n") + + max_car_model_len = max([len(car_model) for car_model in car_model_jerks]) + for car_model, _jerks in sorted(car_model_jerks.items(), key=lambda i: i[1]['up_jerk'], reverse=True): + violation = any([_jerk >= MAX_LAT_JERK + MAX_LAT_JERK_TOLERANCE for _jerk in _jerks.values()]) + violation_str = " - VIOLATION" if violation else "" + + print(f"{car_model:{max_car_model_len}} - up jerk: {round(_jerks['up_jerk'], 2):5} m/s^3, down jerk: {round(_jerks['down_jerk'], 2):5} m/s^3{violation_str}") + + # exit with test result + sys.exit(not result.result.wasSuccessful()) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 6a92540f00..8ff06a591a 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -18,6 +18,7 @@ class CarControllerParams: ACCEL_MAX = 1.5 # m/s2, lower than allowed 2.0 m/s2 for tuning reasons ACCEL_MIN = -3.5 # m/s2 + STEER_STEP = 1 STEER_MAX = 1500 STEER_ERROR_MAX = 350 # max delta between torque cmd and torque motor diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 628962de75..4b19f4d13c 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -31,7 +31,7 @@ class CarController: # **** Steering Controls ************************************************ # - if self.frame % self.CCP.HCA_STEP == 0: + if self.frame % self.CCP.STEER_STEP == 0: # Logic to avoid HCA state 4 "refused": # * Don't steer unless HCA is in state 3 "ready" or 5 "active" # * Don't steer at standstill @@ -50,14 +50,14 @@ class CarController: self.hcaEnabledFrameCount = 0 else: self.hcaEnabledFrameCount += 1 - if self.hcaEnabledFrameCount >= 118 * (100 / self.CCP.HCA_STEP): # 118s + if self.hcaEnabledFrameCount >= 118 * (100 / self.CCP.STEER_STEP): # 118s hcaEnabled = False self.hcaEnabledFrameCount = 0 else: hcaEnabled = True if self.apply_steer_last == apply_steer: self.hcaSameTorqueCount += 1 - if self.hcaSameTorqueCount > 1.9 * (100 / self.CCP.HCA_STEP): # 1.9s + if self.hcaSameTorqueCount > 1.9 * (100 / self.CCP.STEER_STEP): # 1.9s apply_steer -= (1, -1)[apply_steer < 0] self.hcaSameTorqueCount = 0 else: diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 208d146e2f..d1f6bfb02c 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -18,7 +18,7 @@ Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) class CarControllerParams: - HCA_STEP = 2 # HCA_01/HCA_1 message frequency 50Hz + STEER_STEP = 2 # HCA_01/HCA_1 message frequency 50Hz ACC_CONTROL_STEP = 2 # ACC_06/ACC_07/ACC_System frequency 50Hz ACCEL_MAX = 2.0 # 2.0 m/s max acceleration From 6dc1fa255970a5976a6acc1f1b9424258ee3fcf3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 15 Dec 2022 22:31:34 -0800 Subject: [PATCH 0543/1179] Remove stretch from MultiOptionDialog --- selfdrive/ui/qt/widgets/input.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index 75453e1b90..6f132adfc2 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -301,7 +301,6 @@ MultiOptionDialog::MultiOptionDialog(const QString &prompt_text, const QStringLi scroll_view->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); main_layout->addWidget(scroll_view); - main_layout->addStretch(1); main_layout->addSpacing(35); // cancel + confirm buttons From 8744384a4f24326c9a39fdae8038b425f5f26df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 16 Dec 2022 17:21:42 -0800 Subject: [PATCH 0544/1179] Sonata less starting state accel (#26363) * Sonata less start accel * Update ref_commit --- selfdrive/car/hyundai/interface.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 811d629f70..6881be5a33 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -232,7 +232,7 @@ class CarInterface(CarInterfaceBase): ret.stoppingControl = True ret.startingState = True ret.vEgoStarting = 0.1 - ret.startAccel = 2.0 + ret.startAccel = 1.0 ret.longitudinalActuatorDelayLowerBound = 0.5 ret.longitudinalActuatorDelayUpperBound = 0.5 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index f72e160ddb..1d586b0334 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -358d330ffde4ecd679129b0e0a20806aaf21b786 \ No newline at end of file +05ba201bcf97b6c1067dbcde2a60f71f43469c56 From d3a3d74830efb33eff6a9f9057a8d552e355bfd7 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 16 Dec 2022 21:46:07 -0800 Subject: [PATCH 0545/1179] nav: add polyline helpers (#26816) * nav: add polyline helpers * Update selfdrive/navd/map_renderer.py --- poetry.lock | 18 +++++++++++++++++- pyproject.toml | 1 + selfdrive/navd/map_renderer.py | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 6360f6f3ab..f7bc4669a3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2755,6 +2755,17 @@ python-versions = ">=3.7,<4.0" poetry = ">=1.2.0,<2.0.0" poetry-core = ">=1.1.0,<2.0.0" +[[package]] +name = "polyline" +version = "1.4.0" +description = "A Python implementation of Google's Encoded Polyline Algorithm Format." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.8.0" + [[package]] name = "portalocker" version = "2.6.0" @@ -4414,7 +4425,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "82e450801a9a1de9fd98615d7deb3d8f0aa5bd3ccf0cf8b258cd8f6e6e4c5309" +content-hash = "d894380c87f5558e032708cc1230aed172ad3e1db9aa112e2e105bebefff4e20" [metadata.files] adal = [ @@ -5420,6 +5431,7 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6666,6 +6678,10 @@ poetry-plugin-export = [ {file = "poetry-plugin-export-1.1.2.tar.gz", hash = "sha256:5e92525dd63f38ce74a51ed68ea91d753523f21ce5f9ef8d3b793e2a4b2222ef"}, {file = "poetry_plugin_export-1.1.2-py3-none-any.whl", hash = "sha256:946e3313b3d00c18fb9a50522e9d5e6a7e111beaba8d6ae33297662fc2070ac1"}, ] +polyline = [ + {file = "polyline-1.4.0-py2.py3-none-any.whl", hash = "sha256:6559a0d5d37f4d14255744b3c6a648d5ff480d3d5c5f30186effc72a4142fd6c"}, + {file = "polyline-1.4.0.tar.gz", hash = "sha256:7c7f89d09a09c7b6161bdbfb4fd304b186fc7a2060fa4f31cb3f61c646a5c074"}, +] portalocker = [ {file = "portalocker-2.6.0-py2.py3-none-any.whl", hash = "sha256:102ed1f2badd8dec9af3d732ef70e94b215b85ba45a8d7ff3c0003f19b442f4e"}, {file = "portalocker-2.6.0.tar.gz", hash = "sha256:964f6830fb42a74b5d32bce99ed37d8308c1d7d44ddf18f3dd89f4680de97b39"}, diff --git a/pyproject.toml b/pyproject.toml index a20868d877..e99b278341 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ tqdm = "^4.64.0" urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" +polyline = "^1.4.0" [tool.poetry.group.dev.dependencies] diff --git a/selfdrive/navd/map_renderer.py b/selfdrive/navd/map_renderer.py index 868307bb63..3239470b23 100755 --- a/selfdrive/navd/map_renderer.py +++ b/selfdrive/navd/map_renderer.py @@ -4,6 +4,7 @@ import os import time import numpy as np +import polyline from cffi import FFI from common.ffi_wrapper import suffix @@ -50,6 +51,22 @@ def get_image(lib, renderer): return r.reshape((WIDTH, HEIGHT)) +def navRoute_to_polyline(nr): + coords = [(m.latitude, m.longitude) for m in nr.navRoute.coordinates] + return coords_to_polyline(coords) + + +def coords_to_polyline(coords): + # TODO: where does this factor of 10 come from? + return polyline.encode([(lat * 10., lon * 10.) for lat, lon in coords]) + + +def polyline_to_coords(p): + coords = polyline.decode(p) + return [(lat / 10., lon / 10.) for lat, lon in coords] + + + if __name__ == "__main__": import matplotlib.pyplot as plt From 66bdd8b1228eb725006cc4c2d389fe2cef7e674a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 17 Dec 2022 00:50:37 -0800 Subject: [PATCH 0546/1179] Fix spacing in MultiOptionDialog (#26817) Update input.cc --- selfdrive/ui/qt/widgets/input.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index 6f132adfc2..2026a70478 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -296,6 +296,8 @@ MultiOptionDialog::MultiOptionDialog(const QString &prompt_text, const QStringLi group->addButton(selectionLabel); listLayout->addWidget(selectionLabel); } + // add stretch to keep buttons spaced correctly + listLayout->addStretch(1); ScrollView *scroll_view = new ScrollView(listWidget, this); scroll_view->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); From 6d8f1667228d74e8c9afca52bafb50c0730a0d83 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Sun, 18 Dec 2022 22:09:40 -0600 Subject: [PATCH 0547/1179] Add several missing HIGHLANDER_TSS2 firmwares (#26801) * Add several missing HIGHLANDER_TSS2 firmwares `@randywf#0891` 2023 Toyota Highlander (ICE) DongleID/route d9049fcd50225c9d|2022-12-14--12-16-16 * docs.py gen'd CARS.md w/ 2023 Highlander update --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 4f1a7cb652..ce067609aa 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -180,7 +180,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 8ff06a591a..80c0ccbb83 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -129,7 +129,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { ToyotaCarInfo("Lexus UX Hybrid 2019-22"), ], CAR.HIGHLANDER: ToyotaCarInfo("Toyota Highlander 2017-19", video_link="https://www.youtube.com/watch?v=0wS0wXSLzoo"), - CAR.HIGHLANDER_TSS2: ToyotaCarInfo("Toyota Highlander 2020-22"), + CAR.HIGHLANDER_TSS2: ToyotaCarInfo("Toyota Highlander 2020-23"), CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19"), CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"), CAR.PRIUS: [ @@ -980,12 +980,14 @@ FW_VERSIONS = { b'8965B48241\x00\x00\x00\x00\x00\x00', b'8965B48310\x00\x00\x00\x00\x00\x00', b'8965B48320\x00\x00\x00\x00\x00\x00', + b'8965B48400\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'\x01F15260E051\x00\x00\x00\x00\x00\x00', b'\x01F15260E061\x00\x00\x00\x00\x00\x00', b'\x01F15260E110\x00\x00\x00\x00\x00\x00', b'\x01F15260E170\x00\x00\x00\x00\x00\x00', + b'\x01F15260E05300\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x01896630E62100\x00\x00\x00\x00', @@ -1003,6 +1005,7 @@ FW_VERSIONS = { b'\x01896630ED9100\x00\x00\x00\x00', b'\x01896630EE1000\x00\x00\x00\x00', b'\x01896630EE1100\x00\x00\x00\x00', + b'\x01896630EG5000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301400\x00\x00\x00\x00', @@ -1013,6 +1016,7 @@ FW_VERSIONS = { b'\x028646F0E02100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F4803000\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F4803000\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', + b'\x028646F4803200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.HIGHLANDERH_TSS2: { From 777dc9dcd2ef3c1011d487f7584f3da9c396e513 Mon Sep 17 00:00:00 2001 From: Samer Khatib <56684133+skhatib07@users.noreply.github.com> Date: Tue, 20 Dec 2022 16:44:33 -0500 Subject: [PATCH 0548/1179] Added unofficial support for Ubuntu 22.10 in ubuntu_setup.sh (#26828) * Added unofficial support for Ubuntu 22.10 in ubuntu_setup.sh Added a conditional to check if $UBUNTU_CODENAME is equal to "kinetic" in ubuntu_setup.sh. Installs the same packages as Ubuntu 22.04 LTS Jammy Jellyfish. * Attempt #2 at adding unofficial support for Ubuntu 22.10 in ubuntu_setup.sh Still checks to see if $UBUNTU_CODENAME is equal to "kinetic" I just fixed some errors that were appearing beforehand * Update tools/ubuntu_setup.sh * Update tools/ubuntu_setup.sh * Update tools/ubuntu_setup.sh * Update tools/ubuntu_setup.sh Co-authored-by: Adeeb Shihadeh --- tools/ubuntu_setup.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 89d33a6127..09296ef94d 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -82,7 +82,7 @@ function install_ubuntu_common_requirements() { } # Install Ubuntu 22.04 LTS packages -function install_ubuntu_jammy_requirements() { +function install_ubuntu_lts_latest_requirements() { install_ubuntu_common_requirements $SUDO apt-get install -y --no-install-recommends \ @@ -108,7 +108,10 @@ if [ -f "/etc/os-release" ]; then source /etc/os-release case "$VERSION_CODENAME" in "jammy") - install_ubuntu_jammy_requirements + install_ubuntu_lts_latest_requirements + ;; + "kinetic") + install_ubuntu_lts_latest_requirements ;; "focal") install_ubuntu_focal_requirements @@ -120,8 +123,8 @@ if [ -f "/etc/os-release" ]; then if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi - if [ "$UBUNTU_CODENAME" = "jammy" ]; then - install_ubuntu_jammy_requirements + if [ "$UBUNTU_CODENAME" = "jammy" ] || [ "$UBUNTU_CODENAME" = "kinetic" ]; then + install_ubuntu_lts_latest_requirements else install_ubuntu_focal_requirements fi From 49ae806534a32858a327745698ca2f36e5210803 Mon Sep 17 00:00:00 2001 From: Hamid Ebadi Date: Tue, 20 Dec 2022 22:45:06 +0100 Subject: [PATCH 0549/1179] carla sim: fix accelerometer sensor data (#26794) --- tools/sim/bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index f72927ba9a..f0694078e2 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -128,7 +128,7 @@ def imu_callback(imu, vehicle_state): vehicle_state.bearing_deg = math.degrees(imu.compass) dat = messaging.new_message('accelerometer') dat.accelerometer.sensor = 4 - dat.accelerometer.type = 0x1 + dat.accelerometer.type = 0x10 dat.accelerometer.timestamp = dat.logMonoTime # TODO: use the IMU timestamp dat.accelerometer.init('acceleration') dat.accelerometer.acceleration.v = [imu.accelerometer.x, imu.accelerometer.y, imu.accelerometer.z] From 5ab2fc16ab5b883f3fa151d0e7362bc73545ca32 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Tue, 20 Dec 2022 14:19:21 -0800 Subject: [PATCH 0550/1179] model_replay: use last N frames of segment so navRoute is valid (#26790) * model_replay: use last N frames of segment so navRoute is valid * Use llk logMonoTime for MapRenderState.locationMonoTime * Record mapRenderState * update refs Co-authored-by: Comma Device --- selfdrive/navd/map_renderer.cc | 4 ++-- selfdrive/test/process_replay/model_replay.py | 16 +++++++++++----- .../test/process_replay/model_replay_ref_commit | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/selfdrive/navd/map_renderer.cc b/selfdrive/navd/map_renderer.cc index 91f31d06dc..51676bb3a3 100644 --- a/selfdrive/navd/map_renderer.cc +++ b/selfdrive/navd/map_renderer.cc @@ -169,7 +169,7 @@ void MapRenderer::publish(const double render_time) { VisionBuf* buf = vipc_server->get_buffer(VisionStreamType::VISION_STREAM_MAP); VisionIpcBufExtra extra = { .frame_id = frame_id, - .timestamp_sof = sm->rcv_time("liveLocationKalman"), + .timestamp_sof = (*sm)["liveLocationKalman"].getLogMonoTime(), .timestamp_eof = ts, }; @@ -206,7 +206,7 @@ void MapRenderer::publish(const double render_time) { // Send state msg MessageBuilder msg; auto state = msg.initEvent().initMapRenderState(); - state.setLocationMonoTime(sm->rcv_time("liveLocationKalman")); + state.setLocationMonoTime((*sm)["liveLocationKalman"].getLogMonoTime()); state.setRenderTime(render_time); state.setFrameId(frame_id); pm->send("mapRenderState", msg); diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index ce861b37e6..324801fead 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -43,12 +43,12 @@ def replace_calib(msg, calib): def nav_model_replay(lr): - sm = messaging.SubMaster(['navModel', 'navThumbnail']) + sm = messaging.SubMaster(['navModel', 'navThumbnail', 'mapRenderState']) pm = messaging.PubMaster(['liveLocationKalman', 'navRoute']) nav = [m for m in lr if m.which() == 'navRoute'] llk = [m for m in lr if m.which() == 'liveLocationKalman'] - assert len(nav) > 0 and len(llk) >= NAV_FRAMES + assert len(nav) > 0 and len(llk) >= NAV_FRAMES and nav[0].logMonoTime < llk[-NAV_FRAMES].logMonoTime log_msgs = [] try: @@ -59,8 +59,8 @@ def nav_model_replay(lr): # setup position and route for _ in range(10): - for s in (llk, nav): - pm.send(s[0].which(), s[0].as_builder().to_bytes()) + for s in (llk[-NAV_FRAMES], nav[0]): + pm.send(s.which(), s.as_builder().to_bytes()) sm.update(1000) if sm.updated['navModel']: break @@ -74,12 +74,16 @@ def nav_model_replay(lr): sm.update(0) # run replay - for n in range(NAV_FRAMES): + for n in range(len(llk) - NAV_FRAMES, len(llk)): pm.send(llk[n].which(), llk[n].as_builder().to_bytes()) m = messaging.recv_one(sm.sock['navThumbnail']) assert m is not None, f"no navThumbnail, frame={n}" log_msgs.append(m) + m = messaging.recv_one(sm.sock['mapRenderState']) + assert m is not None, f"no mapRenderState, frame={n}" + log_msgs.append(m) + m = messaging.recv_one(sm.sock['navModel']) assert m is not None, f"no navModel response, frame={n}" log_msgs.append(m) @@ -231,6 +235,8 @@ if __name__ == "__main__": 'navModel.dspExecutionTime', 'navModel.modelExecutionTime', 'navThumbnail.timestampEof', + 'mapRenderState.locationMonoTime', + 'mapRenderState.renderTime', ] if PC: ignore += [ diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index aa204e0f8a..22e021dcaf 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -4ff972367fdb9546be68ee0ba0d45cf4f839dae7 +db587bfef2317c5a3471632ac47381457e1be853 \ No newline at end of file From f75b640cf57d8f1a54d2d421194178d3ea9d38f1 Mon Sep 17 00:00:00 2001 From: lucentheart <97204067+lucentheart@users.noreply.github.com> Date: Tue, 20 Dec 2022 20:57:07 -0500 Subject: [PATCH 0551/1179] Add missing FW versions for 2019 Honda Passport (#26815) Update values.py --- selfdrive/car/honda/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 905c9f4b4f..2906b23bda 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1167,6 +1167,7 @@ FW_VERSIONS = { (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-RLV-B220\x00\x00', b'37805-RLV-B210\x00\x00', + b'37805-RLV-L160\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TGS-A230\x00\x00', @@ -1177,6 +1178,7 @@ FW_VERSIONS = { ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TG7-A040\x00\x00', + b'38897-TG7-A030\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TGS-A010\x00\x00', @@ -1186,10 +1188,12 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5EZ-A600\x00\x00', + b'28101-5EZ-A430\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TGS-AT20\x00\x00', b'78109-TGS-AX20\x00\x00', + b'78109-TGS-AJ20\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TGS-A530\x00\x00', From c4d2e8bcf4ce7187c92a4321e0ab2d99fa0791a6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 20 Dec 2022 20:03:24 -0800 Subject: [PATCH 0552/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 9e5c28e568..345147fe2b 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 9e5c28e568a1efe4bac340b48b3c16aafc82e84c +Subproject commit 345147fe2bc3a06c44709426f9fcd298588b9fe4 From af561393fe0d535315a52e35556697667886089d Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Wed, 28 Dec 2022 15:38:10 +0100 Subject: [PATCH 0553/1179] Tesla non-zero stopAccel (#26840) remove stopAccel override --- selfdrive/car/tesla/interface.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 49e06d8923..6a73472108 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -23,7 +23,6 @@ class CarInterface(CarInterfaceBase): ret.longitudinalTuning.kpV = [0] ret.longitudinalTuning.kiBP = [0] ret.longitudinalTuning.kiV = [0] - ret.stopAccel = 0.0 ret.longitudinalActuatorDelayUpperBound = 0.5 # s ret.radarTimeStep = (1.0 / 8) # 8Hz From f15a5c9ad697e41eb273875577855ec5edede7f4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 29 Dec 2022 08:47:49 +0800 Subject: [PATCH 0554/1179] cabana: align y axis correctly (#26837) --- tools/cabana/chartswidget.cc | 39 ++++++++++++++++++++++++------------ tools/cabana/chartswidget.h | 5 ++++- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index bc28666a34..da39fb1a66 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -156,6 +156,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); + QObject::connect(chart, &ChartView::axisYUpdated, this, &ChartsWidget::alignCharts); charts_layout->insertWidget(0, chart); charts.push_back(chart); } @@ -171,6 +172,7 @@ void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); updateToolBar(); + alignCharts(); emit seriesChanged(); } @@ -183,6 +185,16 @@ void ChartsWidget::removeAll() { emit seriesChanged(); } +void ChartsWidget::alignCharts() { + int plot_left = 0; + for (auto c : charts) { + plot_left = qMax((qreal)plot_left, c->getYAsixLabelWidth()); + } + for (auto c : charts) { + c->setPlotAreaLeftPosition(plot_left); + } +} + bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { if (obj != this && event->type() == QEvent::Close) { emit dock_btn->triggered(); @@ -202,7 +214,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->addAxis(axis_y, Qt::AlignLeft); chart->legend()->setShowToolTips(true); chart->layout()->setContentsMargins(0, 0, 0, 0); - chart->setMargins(QMargins(20, 11, 11, 11)); QToolButton *remove_btn = new QToolButton(); remove_btn->setText("X"); @@ -234,6 +245,19 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(manage_btn, &QToolButton::clicked, this, &ChartView::manageSeries); } +qreal ChartView::getYAsixLabelWidth() const { + QFontMetrics fm(axis_y->labelsFont()); + int n = qMax(int(-qFloor(std::log10((axis_y->max() - axis_y->min()) / (axis_y->tickCount() - 1)))), 0) + 1; + return qMax(fm.width(QString::number(axis_y->min(), 'f', n)), fm.width(QString::number(axis_y->max(), 'f', n))) + 20; +} + +void ChartView::setPlotAreaLeftPosition(int pos) { + if (std::ceil(chart()->plotArea().left()) != pos) { + const float left_margin = chart()->margins().left() + pos - chart()->plotArea().left(); + chart()->setMargins(QMargins(left_margin, 11, 11, 11)); + } +} + void ChartView::addSeries(const QString &msg_id, const Signal *sig) { QLineSeries *series = new QLineSeries(this); series->setUseOpenGL(true); @@ -361,16 +385,6 @@ void ChartView::setDisplayRange(double min, double max) { } } -void ChartView::adjustChartMargins() { - // TODO: Remove hardcoded aligned_pos - const int aligned_pos = 60; - if ((int)chart()->plotArea().left() != aligned_pos) { - const float left_margin = chart()->margins().left() + aligned_pos - chart()->plotArea().left(); - chart()->setMargins(QMargins(left_margin, 11, 11, 11)); - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); - } -} - void ChartView::updateSeries(const Signal *sig) { auto events = can->events(); if (!events || sigs.isEmpty()) return; @@ -436,8 +450,7 @@ void ChartView::updateAxisY() { double range = max_y - min_y; applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05); } - - adjustChartMargins(); + QTimer::singleShot(0, this, &ChartView::axisYUpdated); } void ChartView::applyNiceNumbers(qreal min, qreal max) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 1799a25488..7a8325382d 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -26,6 +26,8 @@ public: void updateSeries(const Signal *sig = nullptr); void setEventsRange(const std::pair &range); void setDisplayRange(double min, double max); + void setPlotAreaLeftPosition(int pos); + qreal getYAsixLabelWidth() const; struct SigItem { QString msg_id; @@ -44,6 +46,7 @@ signals: void zoomIn(double min, double max); void zoomReset(); void remove(); + void axisYUpdated(); private slots: void msgRemoved(uint32_t address); @@ -58,7 +61,6 @@ private: void mouseMoveEvent(QMouseEvent *ev) override; void leaveEvent(QEvent *event) override; void resizeEvent(QResizeEvent *event) override; - void adjustChartMargins(); void updateAxisY(); void updateTitle(); void updateFromSettings(); @@ -89,6 +91,7 @@ signals: void seriesChanged(); private: + void alignCharts(); void removeChart(ChartView *chart); void eventsMerged(); void updateState(); From 65509669b676bad41d57443454dbea8ffbc1c8f7 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 29 Dec 2022 08:51:02 +0800 Subject: [PATCH 0555/1179] Cabana: add tool to find similar bits (#26834) * find similar bits * set window title --- tools/cabana/SConscript | 2 +- tools/cabana/mainwin.cc | 8 ++ tools/cabana/mainwin.h | 2 + tools/cabana/tools/findsimilarbits.cc | 115 ++++++++++++++++++++++++++ tools/cabana/tools/findsimilarbits.h | 23 ++++++ 5 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 tools/cabana/tools/findsimilarbits.cc create mode 100644 tools/cabana/tools/findsimilarbits.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 52fe9e346d..718e2e50af 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -18,7 +18,7 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', - 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index f14d522c20..4ae53223a8 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -133,6 +133,9 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(undo_view); commands_menu->addAction(commands_act); + QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); + tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); + QMenu *help_menu = menuBar()->addMenu(tr("&Help")); help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } @@ -283,3 +286,8 @@ void MainWindow::setOption() { SettingsDlg dlg(this); dlg.exec(); } + +void MainWindow::findSimilarBits() { + FindSimilarBitsDlg dlg(this); + dlg.exec(); +} diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 17c513d809..5d3ba470a1 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -11,6 +11,7 @@ #include "tools/cabana/detailwidget.h" #include "tools/cabana/messageswidget.h" #include "tools/cabana/videowidget.h" +#include "tools/cabana/tools/findsimilarbits.h" class MainWindow : public QMainWindow { Q_OBJECT @@ -41,6 +42,7 @@ protected: void DBCFileChanged(); void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); + void findSimilarBits(); VideoWidget *video_widget; MessagesWidget *messages_widget; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc new file mode 100644 index 0000000000..5fa5bcf7b8 --- /dev/null +++ b/tools/cabana/tools/findsimilarbits.cc @@ -0,0 +1,115 @@ +#include "tools/cabana/tools/findsimilarbits.h" + +#include +#include +#include +#include +#include +#include + +#include "tools/cabana/canmessages.h" +#include "tools/cabana/dbcmanager.h" + +FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent) { + setWindowTitle(tr("Find similar bits")); + QVBoxLayout *main_layout = new QVBoxLayout(this); + + QHBoxLayout *form_layout = new QHBoxLayout(); + bus_combo = new QComboBox(this); + QSet bus_set; + for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + bus_set << DBCManager::parseId(it.key()).first; + } + for (uint8_t bus : bus_set) { + bus_combo->addItem(QString::number(bus)); + } + bus_combo->model()->sort(0); + bus_combo->setCurrentIndex(0); + form_layout->addWidget(new QLabel("Bus")); + form_layout->addWidget(bus_combo); + + bit_combo = new QComboBox(this); + bit_combo->addItems({"0", "1"}); + bit_combo->setCurrentIndex(1); + form_layout->addWidget(new QLabel("Bit")); + form_layout->addWidget(bit_combo); + + min_msgs = new QLineEdit(this); + min_msgs->setValidator(new QIntValidator(this)); + min_msgs->setText("100"); + form_layout->addWidget(new QLabel("Min msg count")); + form_layout->addWidget(min_msgs); + search_btn = new QPushButton(tr("&Find"), this); + form_layout->addWidget(search_btn); + form_layout->addStretch(1); + main_layout->addLayout(form_layout); + + table = new QTableWidget(this); + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->horizontalHeader()->setStretchLastSection(true); + main_layout->addWidget(table); + + setMinimumSize({700, 500}); + QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); +} + +void FindSimilarBitsDlg::find() { + search_btn->setEnabled(false); + table->clear(); + auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), bit_combo->currentIndex(), min_msgs->text().toInt()); + table->setRowCount(msg_mismatched.size()); + table->setColumnCount(6); + table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total", "perc%"}); + for (int i = 0; i < msg_mismatched.size(); ++i) { + auto &m = msg_mismatched[i]; + table->setItem(i, 0, new QTableWidgetItem(QString("%1").arg(m.address, 1, 16))); + table->setItem(i, 1, new QTableWidgetItem(QString::number(m.byte_idx))); + table->setItem(i, 2, new QTableWidgetItem(QString::number(m.bit_idx))); + table->setItem(i, 3, new QTableWidgetItem(QString::number(m.mismatches))); + table->setItem(i, 4, new QTableWidgetItem(QString::number(m.total))); + table->setItem(i, 5, new QTableWidgetItem(QString::number(m.perc))); + } + search_btn->setEnabled(true); +} + +QList FindSimilarBitsDlg::calcBits(uint8_t bus, int bit_to_find, int min_msgs_cnt) { + QHash> mismatches; + QHash msg_count; + auto events = can->events(); + for (auto e : *events) { + if (e->which == cereal::Event::Which::CAN) { + for (const auto &c : e->event.getCan()) { + if (c.getSrc() == bus) { + uint32_t address = c.getAddress(); + ++msg_count[address]; + auto &mismatched = mismatches[address]; + const auto dat = c.getDat(); + if (mismatched.size() < dat.size() * 8) { + mismatched.resize(dat.size() * 8); + } + for (int i = 0; i < dat.size(); ++i) { + for (int j = 0; j < 8; ++j) { + int bit = ((dat[i] >> (7 - j)) & 1) != 0; + mismatched[i * 8 + j] += (bit != bit_to_find); + } + } + } + } + } + } + + QList result; + result.reserve(mismatches.size()); + for (auto it = mismatches.begin(); it != mismatches.end(); ++it) { + if (auto cnt = msg_count[it.key()]; cnt > min_msgs_cnt) { + auto &mismatched = it.value(); + for (int i = 0; i < mismatched.size(); ++i) { + if (uint32_t perc = (mismatched[i] / (double)cnt) * 100; perc < 50) { + result.push_back({it.key(), (uint32_t)i / 8, (uint32_t)i % 8, mismatched[i], cnt, perc}); + } + } + } + } + std::sort(result.begin(), result.end(), [](auto &l, auto &r) { return l.perc > r.perc; }); + return result; +} diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h new file mode 100644 index 0000000000..79db4a1c69 --- /dev/null +++ b/tools/cabana/tools/findsimilarbits.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include + +class FindSimilarBitsDlg : public QDialog { +public: + FindSimilarBitsDlg(QWidget *parent); + +private: + struct mismatched_struct { + uint32_t address, byte_idx, bit_idx, mismatches, total, perc; + }; + QList calcBits(uint8_t bus, int bit_to_find, int min_msgs_cnt); + void find(); + + QTableWidget *table; + QComboBox *bus_combo, *bit_combo; + QPushButton *search_btn; + QLineEdit *min_msgs; +}; From 7ae87923864af4cd1378eeccc23c002fc66447e5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 29 Dec 2022 10:21:06 +0800 Subject: [PATCH 0556/1179] Cabana: make all panels dockable into each other (#26838) --- tools/cabana/cabana.cc | 4 +- tools/cabana/chartswidget.cc | 4 +- tools/cabana/mainwin.cc | 100 ++++++++++++++++------------------- tools/cabana/mainwin.h | 6 +-- tools/cabana/settings.cc | 6 ++- tools/cabana/settings.h | 2 +- tools/cabana/videowidget.cc | 13 +++-- tools/cabana/videowidget.h | 2 +- 8 files changed, 70 insertions(+), 67 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 51418e293f..4f037ba595 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -6,6 +6,8 @@ #include "tools/cabana/mainwin.h" int main(int argc, char *argv[]) { + QCoreApplication::setApplicationName("Cabana"); + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); initApp(argc, argv); QApplication app(argc, argv); @@ -36,7 +38,7 @@ int main(int argc, char *argv[]) { int ret = 0; if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { MainWindow w; - w.showMaximized(); + w.show(); ret = app.exec(); } return ret; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index da39fb1a66..71886a113f 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,5 +1,6 @@ #include "tools/cabana/chartswidget.h" +#include #include #include #include @@ -42,7 +43,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(charts_scroll); max_chart_range = settings.max_chart_x_range; - use_dark_theme = palette().color(QPalette::WindowText).value() > palette().color(QPalette::Background).value(); + use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > + QApplication::style()->standardPalette().color(QPalette::Background).value(); updateToolBar(); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 4ae53223a8..43aa330029 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -1,19 +1,16 @@ #include "tools/cabana/mainwin.h" #include -#include #include #include +#include #include #include #include -#include #include #include #include #include -#include -#include #include #include #include @@ -25,58 +22,20 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const } MainWindow::MainWindow() : QMainWindow() { - setWindowTitle("Cabana"); - QWidget *central_widget = new QWidget(this); - QHBoxLayout *main_layout = new QHBoxLayout(central_widget); - main_layout->setContentsMargins(11, 11, 11, 0); - main_layout->setSpacing(0); - - splitter = new QSplitter(Qt::Horizontal, this); - splitter->setHandleWidth(11); - - QWidget *messages_container = new QWidget(this); - QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); - messages_layout->setContentsMargins(0, 0, 0, 0); - - // left panel - dbc_combo = createDBCSelector(); - messages_layout->addWidget(dbc_combo); - messages_widget = new MessagesWidget(this); - messages_layout->addWidget(messages_widget); - splitter->addWidget(messages_container); - - charts_widget = new ChartsWidget(this); + createDockWindows(); 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 - QWidget *right_container = new QWidget(this); - right_container->setFixedWidth(640); - r_layout = new QVBoxLayout(right_container); - r_layout->setContentsMargins(11, 0, 0, 0); - QHBoxLayout *right_hlayout = new QHBoxLayout(); - fingerprint_label = new QLabel(this); - right_hlayout->addWidget(fingerprint_label, 0, Qt::AlignLeft); - - // TODO: click to select another route. - right_hlayout->addWidget(new QLabel(can->routeName()), 0, Qt::AlignRight); - r_layout->addLayout(right_hlayout); - - video_widget = new VideoWidget(this); - r_layout->addWidget(video_widget, 0, Qt::AlignTop); - r_layout->addWidget(charts_widget, 1); - r_layout->addStretch(0); - main_layout->addWidget(right_container); - - setCentralWidget(central_widget); + detail_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + setCentralWidget(detail_widget); createActions(); createStatusBar(); createShortcuts(); + restoreGeometry(settings.geometry); + if (isMaximized()) { + setGeometry(QApplication::desktop()->availableGeometry(this)); + } + restoreState(settings.window_state); + qRegisterMetaType("uint64_t"); qRegisterMetaType("ReplyMsgType"); installMessageHandler([this](ReplyMsgType type, const std::string msg) { @@ -140,6 +99,39 @@ void MainWindow::createActions() { help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } +void MainWindow::createDockWindows() { + // left panel + QWidget *messages_container = new QWidget(this); + QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); + dbc_combo = createDBCSelector(); + messages_layout->addWidget(dbc_combo); + messages_widget = new MessagesWidget(this); + messages_layout->addWidget(messages_widget); + + QDockWidget *dock = new QDockWidget(tr("MESSAGES"), this); + dock->setObjectName("MessagesPanel"); + dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + dock->setWidget(messages_container); + addDockWidget(Qt::LeftDockWidgetArea, dock); + + // right panel + QWidget *right_container = new QWidget(this); + r_layout = new QVBoxLayout(right_container); + charts_widget = new ChartsWidget(this); + video_widget = new VideoWidget(this); + r_layout->addWidget(video_widget, 0, Qt::AlignTop); + r_layout->addWidget(charts_widget, 1); + r_layout->addStretch(0); + + video_dock = new QDockWidget(can->routeName(), this); + video_dock->setObjectName(tr("VideoPanel")); + video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + video_dock->setWidget(right_container); + addDockWidget(Qt::RightDockWidgetArea, video_dock); +} + QComboBox *MainWindow::createDBCSelector() { QComboBox *c = new QComboBox(this); c->setEditable(true); @@ -205,7 +197,7 @@ void MainWindow::loadDBCFromClipboard() { void MainWindow::loadDBCFromFingerprint() { auto fingerprint = can->carFingerprint(); - fingerprint_label->setText(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint); + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { @@ -257,7 +249,6 @@ void MainWindow::dockCharts(bool dock) { floating_window->setLayout(new QVBoxLayout()); floating_window->layout()->addWidget(charts_widget); floating_window->installEventFilter(charts_widget); - floating_window->setMinimumSize(QGuiApplication::primaryScreen()->size() / 2); floating_window->showMaximized(); } } @@ -277,7 +268,8 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (floating_window) floating_window->deleteLater(); - settings.splitter_state = splitter->saveState(); + settings.geometry = saveGeometry(); + settings.window_state = saveState(); settings.save(); QWidget::closeEvent(event); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 5d3ba470a1..f8b5f92349 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,10 +1,10 @@ #pragma once #include +#include #include #include #include -#include #include #include "tools/cabana/chartswidget.h" @@ -35,6 +35,7 @@ signals: protected: void createActions(); + void createDockWindows(); QComboBox *createDBCSelector(); void createStatusBar(); void createShortcuts(); @@ -45,14 +46,13 @@ protected: void findSimilarBits(); VideoWidget *video_widget; + QDockWidget *video_dock; MessagesWidget *messages_widget; DetailWidget *detail_widget; ChartsWidget *charts_widget; - QSplitter *splitter; QWidget *floating_window = nullptr; QVBoxLayout *r_layout; QProgressBar *progress_bar; - QLabel *fingerprint_label; QJsonDocument fingerprint_to_dbc; QComboBox *dbc_combo; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 63e26f3808..5e7f833317 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -19,7 +19,8 @@ void Settings::save() { s.setValue("chart_height", chart_height); s.setValue("max_chart_x_range", max_chart_x_range); s.setValue("last_dir", last_dir); - s.setValue("splitter_state", splitter_state); + s.setValue("window_state", window_state); + s.setValue("geometry", geometry); } void Settings::load() { @@ -29,7 +30,8 @@ void Settings::load() { chart_height = s.value("chart_height", 200).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(); + window_state = s.value("window_state").toByteArray(); + geometry = s.value("geometry").toByteArray(); } // SettingsDlg diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 1db92fe231..d231a3a53a 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -18,7 +18,7 @@ public: int chart_height = 200; int max_chart_x_range = 3 * 60; // 3 minutes QString last_dir; - QByteArray splitter_state; + QByteArray window_state, geometry; signals: void changed(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 6cd173b514..7e40ba2adb 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -17,10 +17,17 @@ inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } -VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); +VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { + setFrameShape(QFrame::StyledPanel); + setFrameShadow(QFrame::Sunken); + QHBoxLayout *containter_layout = new QHBoxLayout(this); + QVBoxLayout *main_layout = new QVBoxLayout(); main_layout->setContentsMargins(0, 0, 0, 0); + containter_layout->addStretch(1); + containter_layout->addLayout(main_layout); + containter_layout->addStretch(1); + cam_widget = new CameraWidget("camerad", can->visionStreamType(), false, this); cam_widget->setFixedSize(parent->width(), parent->width() / 1.596); main_layout->addWidget(cam_widget); @@ -56,8 +63,6 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { } main_layout->addLayout(control_layout); - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - 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)); }); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index ea62081a91..86cdc6f114 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -35,7 +35,7 @@ private: QSize thumbnail_size = {}; }; -class VideoWidget : public QWidget { +class VideoWidget : public QFrame { Q_OBJECT public: From ab797588f800c02c6ea181a86b3b1c7d760e8c72 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 29 Dec 2022 10:22:04 +0800 Subject: [PATCH 0557/1179] Cabana: double click on logs cell to open the chart (#26833) --- tools/cabana/chartswidget.cc | 7 ++++--- tools/cabana/detailwidget.cc | 3 +++ tools/cabana/historylog.cc | 12 ++++++++++++ tools/cabana/historylog.h | 4 ++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 71886a113f..cf01533aaa 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -145,8 +145,9 @@ ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bool merge) { setUpdatesEnabled(false); - if (show) { - ChartView *chart = merge && charts.size() > 0 ? charts.back() : nullptr; + ChartView *chart = findChart(id, sig); + if (show && !chart) { + chart = merge && charts.size() > 0 ? charts.back() : nullptr; if (!chart) { chart = new ChartView(this); chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); @@ -163,7 +164,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo charts.push_back(chart); } chart->addSeries(id, sig); - } else if (ChartView *chart = findChart(id, sig)) { + } else if (!show && chart) { chart->removeSeries(id, sig); } updateToolBar(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 108aa8776e..06377616da 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -108,6 +108,9 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart }); QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); QObject::connect(charts, &ChartsWidget::seriesChanged, this, &DetailWidget::updateChartState); + QObject::connect(history_log, &LogsWidget::openChart, [this](const QString &id, const Signal *sig) { + this->charts->showChart(id, sig, true, false); + }); QObject::connect(undo_stack, &QUndoStack::indexChanged, [this]() { if (undo_stack->count() > 0) dbcMsgChanged(); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 3e456e44e9..0fd939c6f7 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -22,6 +22,8 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { return !sigs.empty() ? QString::number(m.sig_values[index.column() - 1]) : m.data; } else if (role == Qt::FontRole && index.column() == 1 && sigs.empty()) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); + } else if (role == Qt::ToolTipRole && index.column() > 0 && !sigs.empty()) { + return tr("double click to open the chart"); } return {}; } @@ -182,6 +184,7 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { logs->setModel(model); main_layout->addWidget(logs); + QObject::connect(logs, &QTableView::doubleClicked, this, &LogsWidget::doubleClicked); QObject::connect(signals_cb, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilter())); QObject::connect(comp_box, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilter())); QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); @@ -218,3 +221,12 @@ void LogsWidget::setFilter() { } model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); } + +void LogsWidget::doubleClicked(const QModelIndex &index) { + if (index.isValid()) { + if (model->sigs.size() > 0 && index.column() > 0) { + emit openChart(model->msg_id, model->sigs[index.column()-1]); + } + can->seekTo(model->messages[index.row()].mono_time / (double)1e9 - can->routeStartTime()); + } +} diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index d5ae47192e..c636f9b48f 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -60,10 +60,14 @@ public: void setMessage(const QString &message_id); void updateState() { model->updateState(); } +signals: + void openChart(const QString &msg_id, const Signal *sig); + private slots: void setFilter(); private: + void doubleClicked(const QModelIndex &index); void showEvent(QShowEvent *event) override { model->setMessage(model->msg_id); }; HistoryLog *logs; From 981532f0c32f58e0ba4675fe3b066d7c6d0d9a8e Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Thu, 29 Dec 2022 17:56:35 -0700 Subject: [PATCH 0558/1179] Laikad preperation (#26800) * laikad update, renaming * update locationd * address PR comments * draft to fix replay * fix process relay to allow no response for messages * bump cereal * update process replay ref commit * move laikad helpers to laika * fix ublox test * update refs * add proper qcom replay support * fix gnss support if both is available * update refs * move laika back to master * move cereal back to master Co-authored-by: Kurt Nistelberger --- cereal | 2 +- laika_repo | 2 +- release/files_common | 1 - selfdrive/locationd/laikad.py | 158 +++++++++++------- selfdrive/locationd/laikad_helpers.py | 89 ---------- selfdrive/locationd/locationd.cc | 92 +++++++++- selfdrive/locationd/locationd.h | 2 + .../locationd/test/test_ublox_processing.py | 7 +- .../test/process_replay/process_replay.py | 25 ++- selfdrive/test/process_replay/ref_commit | 2 +- 10 files changed, 199 insertions(+), 181 deletions(-) delete mode 100644 selfdrive/locationd/laikad_helpers.py diff --git a/cereal b/cereal index 22b1431132..f200875ca3 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 22b1431132b038253a24ab3fbbe3af36ef93b95b +Subproject commit f200875ca300d3a7b9293c4effcc9456e359e505 diff --git a/laika_repo b/laika_repo index e1049cde0a..5eb0c3c259 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit e1049cde0a68f7d4a70b1ebd76befdc0e163ad55 +Subproject commit 5eb0c3c2596dd12a232b83bdb057a716810e89cf diff --git a/release/files_common b/release/files_common index f438904118..a06543abbf 100644 --- a/release/files_common +++ b/release/files_common @@ -233,7 +233,6 @@ selfdrive/locationd/generated/gps.cpp selfdrive/locationd/generated/gps.h selfdrive/locationd/laikad.py -selfdrive/locationd/laikad_helpers.py selfdrive/locationd/locationd.h selfdrive/locationd/locationd.cc selfdrive/locationd/paramsd.py diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 6936d88acc..1f13c2b69a 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -20,7 +20,7 @@ from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_ephem, parse from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad_helpers import calc_pos_fix_gauss_newton, get_posfix_sympy_fun +from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind from selfdrive.locationd.models.gnss_kf import GNSSKalman from selfdrive.locationd.models.gnss_kf import States as GStates @@ -58,9 +58,9 @@ class Laikad: self.load_cache() self.posfix_functions = {constellation: get_posfix_sympy_fun(constellation) for constellation in (ConstellationId.GPS, ConstellationId.GLONASS)} - self.last_pos_fix = [] - self.last_pos_residual = [] - self.last_pos_fix_t = None + self.velfix_function = get_velfix_sympy_func() + self.last_fix_pos = None + self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom @@ -92,20 +92,23 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = t - def get_est_pos(self, t, processed_measurements): - if self.last_pos_fix_t is None or abs(self.last_pos_fix_t - t) >= 2: - min_measurements = 6 if any(p.constellation_id == ConstellationId.GLONASS for p in processed_measurements) else 5 - pos_fix, pos_fix_residual = calc_pos_fix_gauss_newton(processed_measurements, self.posfix_functions, min_measurements=min_measurements) - if len(pos_fix) > 0: - self.last_pos_fix_t = t - residual_median = np.median(np.abs(pos_fix_residual)) - if np.median(np.abs(pos_fix_residual)) < POS_FIX_RESIDUAL_THRESHOLD: - cloudlog.debug(f"Pos fix is within threshold with median: {residual_median.round()}") - self.last_pos_fix = pos_fix[:3] - self.last_pos_residual = pos_fix_residual - else: - cloudlog.debug(f"Pos fix failed with median: {residual_median.round()}. All residuals: {np.round(pos_fix_residual)}") - return self.last_pos_fix + def get_lsq_fix(self, t, measurements): + if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: + min_measurements = 6 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 5 + position_solution, pr_residuals = calc_pos_fix(measurements, self.posfix_functions, min_measurements=min_measurements) + + if len(position_solution) < 3: + return None + position_estimate = position_solution[:3] + #TODO median abs residual is decent estimate of std, can be improved with measurements stds and/or DOP + position_std = np.median(np.abs(pr_residuals)) * np.ones(3) + velocity_solution, prr_residuals = calc_vel_fix(measurements, position_estimate, self.velfix_function, min_measurements=min_measurements) + if len(velocity_solution) < 3: + return None + + velocity_estimate = velocity_solution[:3] + velocity_std = np.median(np.abs(prr_residuals)) * np.ones(3) + return position_estimate, position_std, velocity_estimate, velocity_std def is_good_report(self, gnss_msg): if gnss_msg.which() == 'drMeasurementReport' and self.use_qcom: @@ -148,11 +151,36 @@ class Laikad: self.astro_dog.add_navs({ephem.prn: [ephem]}) self.cache_ephemeris(t=ephem.epoch) - def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): - if self.is_good_report(gnss_msg): - week, tow, new_meas = self.read_report(gnss_msg) - self.gps_week = week + def process_report(self, new_meas, t): + # Filter measurements with unexpected pseudoranges for GPS and GLONASS satellites + new_meas = [m for m in new_meas if 1e7 < m.observables['C1C'] < 3e7] + processed_measurements = process_measurements(new_meas, self.astro_dog) + instant_fix = self.get_lsq_fix(t, processed_measurements) + if instant_fix is None: + return None + else: + position_estimate, position_std, velocity_estimate, velocity_std = instant_fix + self.last_fix_t = t + self.last_fix_pos = position_estimate + self.lat_fix_pos_std = position_std + + corrected_measurements = correct_measurements(processed_measurements, position_estimate, self.astro_dog) + if (t*1e9) % 10 == 0: + cloudlog.debug(f"Measurements Incoming/Processed/Corrected: {len(new_meas), len(processed_measurements), len(corrected_measurements)}") + return position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, processed_measurements + + def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): + if self.is_ephemeris(gnss_msg): + self.read_ephemeris(gnss_msg) + return None + elif self.is_good_report(gnss_msg): + + week, tow, new_meas = self.read_report(gnss_msg) + if len(new_meas) == 0: + return None + + self.gps_week = week t = gnss_mono_time * 1e-9 if week > 0: self.got_first_gnss_msg = True @@ -160,44 +188,38 @@ class Laikad: if self.auto_fetch_orbits: self.fetch_orbits(latest_msg_t, block) - # Filter measurements with unexpected pseudoranges for GPS and GLONASS satellites - new_meas = [m for m in new_meas if 1e7 < m.observables['C1C'] < 3e7] - - processed_measurements = process_measurements(new_meas, self.astro_dog) - est_pos = self.get_est_pos(t, processed_measurements) - - corrected_measurements = correct_measurements(processed_measurements, est_pos, self.astro_dog) if len(est_pos) > 0 else [] - if gnss_mono_time % 10 == 0: - cloudlog.debug(f"Measurements Incoming/Processed/Corrected: {len(new_meas), len(processed_measurements), len(corrected_measurements)}") - - self.update_localizer(est_pos, t, corrected_measurements) - kf_valid = all(self.kf_valid(t)) - ecef_pos = self.gnss_kf.x[GStates.ECEF_POS] - ecef_vel = self.gnss_kf.x[GStates.ECEF_VELOCITY] - - p = self.gnss_kf.P.diagonal() - pos_std = np.sqrt(p[GStates.ECEF_POS]) - vel_std = np.sqrt(p[GStates.ECEF_VELOCITY]) + output = self.process_report(new_meas, t) + if output is None: + return None + position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output + self.update_localizer(position_estimate, t, corrected_measurements) meas_msgs = [create_measurement_msg(m) for m in corrected_measurements] - dat = messaging.new_message("gnssMeasurements") + msg = messaging.new_message("gnssMeasurements") measurement_msg = log.LiveLocationKalman.Measurement.new_message - dat.gnssMeasurements = { + + P_diag = self.gnss_kf.P.diagonal() + kf_valid = all(self.kf_valid(t)) + msg.gnssMeasurements = { "gpsWeek": week, "gpsTimeOfWeek": tow, - "positionECEF": measurement_msg(value=ecef_pos.tolist(), std=pos_std.tolist(), valid=kf_valid), - "velocityECEF": measurement_msg(value=ecef_vel.tolist(), std=vel_std.tolist(), valid=kf_valid), - # TODO std is incorrectly the dimension of the measurements and not 3D - "positionFixECEF": measurement_msg(value=self.last_pos_fix, std=self.last_pos_residual, valid=self.last_pos_fix_t == t), - "ubloxMonoTime": gnss_mono_time, + "kalmanPositionECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), + std=np.sqrt(P_diag[GStates.ECEF_POS]).tolist(), + valid=kf_valid), + "kalmanVelocityECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_VELOCITY].tolist(), + std=np.sqrt(P_diag[GStates.ECEF_VELOCITY]).tolist(), + valid=kf_valid), + "positionECEF": measurement_msg(value=position_estimate, std=position_std.tolist(), valid=bool(self.last_fix_t == t)), + "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), + + "measTime": gnss_mono_time, "correctedMeasurements": meas_msgs } - return dat - elif self.is_ephemeris(gnss_msg): - self.read_ephemeris(gnss_msg) + return msg #elif gnss_msg.which() == 'ionoData': - # todo add this. Needed to better correct messages offline. First fix ublox_msg.cc to sent them. + # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. + def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid @@ -349,9 +371,23 @@ class EphemerisSourceType(IntEnum): qcom = 3 -def main(sm=None, pm=None): +def process_msg(laikad, gnss_msg, mono_time, block=False): + # TODO: Understand and use remaining unknown constellations + if gnss_msg.which() == "drMeasurementReport": + if getattr(gnss_msg, gnss_msg.which()).source not in ['glonass', 'gps', 'beidou', 'sbas']: + return None + + if getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max: + # gpsWeek 65535 is received rarely from quectel, this cannot be + # passed to GnssMeasurements's gpsWeek (Int16) + return None + + return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) + + +def main(sm=None, pm=None, qc=None): use_qcom = not Params().get_bool("UbloxAvailable", block=True) - if use_qcom: + if use_qcom or (qc is not None and qc): raw_gnss_socket = "qcomGnss" else: raw_gnss_socket = "ubloxGnss" @@ -371,19 +407,13 @@ def main(sm=None, pm=None): if sm.updated[raw_gnss_socket]: gnss_msg = sm[raw_gnss_socket] - # TODO: Understand and use remaining unknown constellations - if gnss_msg.which() == "drMeasurementReport": - if getattr(gnss_msg, gnss_msg.which()).source not in ['glonass', 'gps', 'beidou', 'sbas']: - continue + msg = process_msg(laikad, gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) + if msg is None: + msg = messaging.new_message("gnssMeasurements") + msg.valid = False - if getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max: - # gpsWeek 65535 is received rarely from quectel, this cannot be - # passed to GnssMeasurements's gpsWeek (Int16) - continue + pm.send('gnssMeasurements', msg) - msg = laikad.process_gnss_msg(gnss_msg, sm.logMonoTime[raw_gnss_socket], block=replay) - if msg is not None: - pm.send('gnssMeasurements', msg) if not laikad.got_first_gnss_msg and sm.updated['clocks']: clocks_msg = sm['clocks'] t = GPSTime.from_datetime(datetime.utcfromtimestamp(clocks_msg.wallTimeNanos * 1E-9)) diff --git a/selfdrive/locationd/laikad_helpers.py b/selfdrive/locationd/laikad_helpers.py deleted file mode 100644 index f13e8e73bb..0000000000 --- a/selfdrive/locationd/laikad_helpers.py +++ /dev/null @@ -1,89 +0,0 @@ -import numpy as np -import sympy - -from laika.constants import EARTH_ROTATION_RATE, SPEED_OF_LIGHT -from laika.helpers import ConstellationId - - -def calc_pos_fix_gauss_newton(measurements, posfix_functions, x0=None, signal='C1C', min_measurements=6): - ''' - Calculates gps fix using gauss newton method - To solve the problem a minimal of 4 measurements are required. - If Glonass is included 5 are required to solve for the additional free variable. - returns: - 0 -> list with positions - ''' - if x0 is None: - x0 = [0, 0, 0, 0, 0] - n = len(measurements) - if n < min_measurements: - return [], [] - - Fx_pos = pr_residual(measurements, posfix_functions, signal=signal) - x = gauss_newton(Fx_pos, x0) - residual, _ = Fx_pos(x, weight=1.0) - return x.tolist(), residual.tolist() - - -def pr_residual(measurements, posfix_functions, signal='C1C'): - def Fx_pos(inp, weight=None): - vals, gradients = [], [] - - for meas in measurements: - pr = meas.observables[signal] - pr += meas.sat_clock_err * SPEED_OF_LIGHT - - w = (1 / meas.observables_std[signal]) if weight is None else weight - - val, *gradient = posfix_functions[meas.constellation_id](*inp, pr, *meas.sat_pos, w) - vals.append(val) - gradients.append(gradient) - return np.asarray(vals), np.asarray(gradients) - - return Fx_pos - - -def gauss_newton(fun, b, xtol=1e-8, max_n=25): - for _ in range(max_n): - # Compute function and jacobian on current estimate - r, J = fun(b) - - # Update estimate - delta = np.linalg.pinv(J) @ r - b -= delta - - # Check step size for stopping condition - if np.linalg.norm(delta) < xtol: - break - return b - - -def get_posfix_sympy_fun(constellation): - # Unknowns - x, y, z = sympy.Symbol('x'), sympy.Symbol('y'), sympy.Symbol('z') - bc = sympy.Symbol('bc') - bg = sympy.Symbol('bg') - var = [x, y, z, bc, bg] - - # Knowns - pr = sympy.Symbol('pr') - sat_x, sat_y, sat_z = sympy.Symbol('sat_x'), sympy.Symbol('sat_y'), sympy.Symbol('sat_z') - weight = sympy.Symbol('weight') - - theta = EARTH_ROTATION_RATE * (pr - bc) / SPEED_OF_LIGHT - val = sympy.sqrt( - (sat_x * sympy.cos(theta) + sat_y * sympy.sin(theta) - x) ** 2 + - (sat_y * sympy.cos(theta) - sat_x * sympy.sin(theta) - y) ** 2 + - (sat_z - z) ** 2 - ) - - if constellation == ConstellationId.GLONASS: - res = weight * (val - (pr - bc - bg)) - elif constellation == ConstellationId.GPS: - res = weight * (val - (pr - bc)) - else: - raise NotImplementedError(f"Constellation {constellation} not supported") - - res = [res] + [sympy.diff(res, v) for v in var] - - return sympy.lambdify([x, y, z, bc, bg, pr, sat_x, sat_y, sat_z, weight], res, modules=["numpy"]) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 4325900c0e..442adcd347 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -25,8 +25,15 @@ const double MAX_FILTER_REWIND_TIME = 0.8; // s // TODO: GPS sensor time offsets are empirically calculated // They should be replaced with synced time from a real clock -const double GPS_LOCATION_SENSOR_TIME_OFFSET = 0.630; // s -const double GPS_LOCATION_EXTERNAL_SENSOR_TIME_OFFSET = 0.095; // s +const double GPS_QUECTEL_SENSOR_TIME_OFFSET = 0.630; // s +const double GPS_UBLOX_SENSOR_TIME_OFFSET = 0.095; // s +const float GPS_MUL_FACTOR = 10.0; +const float GPS_POS_STD_THRESHOLD = 50.0; +const float GPS_VEL_STD_THRESHOLD = 5.0; +const float GPS_POS_ERROR_RESET_THRESHOLD = 200.0; +const float GPS_POS_STD_RESET_THRESHOLD = 5.0; +const float GPS_VEL_STD_RESET_THRESHOLD = 0.5; +const float GPS_ORIENTATION_ERROR_RESET_THRESHOLD = 5.0; static VectorXd floatlist2vector(const capnp::List::Reader& floatlist) { VectorXd res(floatlist.size()); @@ -316,8 +323,8 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R VectorXd ecef_pos = this->converter->ned2ecef({ 0.0, 0.0, 0.0 }).to_vector(); VectorXd ecef_vel = this->converter->ned2ecef({ log.getVNED()[0], log.getVNED()[1], log.getVNED()[2] }).to_vector() - ecef_pos; - MatrixXdr ecef_pos_R = Vector3d::Constant(std::pow(10.0 * log.getAccuracy(),2) + std::pow(10.0 * log.getVerticalAccuracy(),2)).asDiagonal(); - MatrixXdr ecef_vel_R = Vector3d::Constant(std::pow(log.getSpeedAccuracy() * 10.0, 2)).asDiagonal(); + MatrixXdr ecef_pos_R = Vector3d::Constant(std::pow(GPS_MUL_FACTOR * log.getAccuracy(),2) + std::pow(GPS_MUL_FACTOR * log.getVerticalAccuracy(),2)).asDiagonal(); + MatrixXdr ecef_vel_R = Vector3d::Constant(std::pow(GPS_MUL_FACTOR * log.getSpeedAccuracy(), 2)).asDiagonal(); this->unix_timestamp_millis = log.getUnixTimestampMillis(); double gps_est_error = (this->kf->get_x().segment(STATE_ECEF_POS_START) - ecef_pos).norm(); @@ -348,6 +355,77 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); } +void Localizer::handle_gnss(double current_time, const cereal::GnssMeasurements::Reader& log) { + + this->gps_valid = log.getPositionECEF().getValid() && log.getVelocityECEF().getValid(); + if (!this->gps_valid) { + this->determine_gps_mode(current_time); + return; + } + this->gps_mode = true; + + double sensor_time = log.getMeasTime() * 1e-9; + if (ublox_available) + sensor_time -= GPS_UBLOX_SENSOR_TIME_OFFSET; + else + sensor_time -= GPS_QUECTEL_SENSOR_TIME_OFFSET; + + auto ecef_pos_v = log.getPositionECEF().getValue(); + VectorXd ecef_pos = Vector3d(ecef_pos_v[0], ecef_pos_v[1], ecef_pos_v[2]); + + // indexed at 0 cause all std values are the same MAE + auto ecef_pos_std = log.getPositionECEF().getStd()[0]; + MatrixXdr ecef_pos_R = Vector3d::Constant(pow(GPS_MUL_FACTOR*ecef_pos_std, 2)).asDiagonal(); + + auto ecef_vel_v = log.getVelocityECEF().getValue(); + VectorXd ecef_vel = Vector3d(ecef_vel_v[0], ecef_vel_v[1], ecef_vel_v[2]); + + // indexed at 0 cause all std values are the same MAE + auto ecef_vel_std = log.getVelocityECEF().getStd()[0]; + MatrixXdr ecef_vel_R = Vector3d::Constant(pow(GPS_MUL_FACTOR*ecef_vel_std, 2)).asDiagonal(); + + double gps_est_error = (this->kf->get_x().segment(STATE_ECEF_POS_START) - ecef_pos).norm(); + + VectorXd orientation_ecef = quat2euler(vector2quat(this->kf->get_x().segment(STATE_ECEF_ORIENTATION_START))); + VectorXd orientation_ned = ned_euler_from_ecef({ ecef_pos[0], ecef_pos[1], ecef_pos[2] }, orientation_ecef); + + LocalCoord convs((ECEF){ .x = ecef_pos[0], .y = ecef_pos[1], .z = ecef_pos[2] }); + ECEF next_ecef = {.x = ecef_pos[0] + ecef_vel[0], .y = ecef_pos[1] + ecef_vel[1], .z = ecef_pos[2] + ecef_vel[2]}; + VectorXd ned_vel = convs.ecef2ned(next_ecef).to_vector(); + double bearing_rad = atan2(ned_vel[1], ned_vel[0]); + + VectorXd orientation_ned_gps = Vector3d(0.0, 0.0, bearing_rad); + VectorXd orientation_error = (orientation_ned - orientation_ned_gps).array() - M_PI; + for (int i = 0; i < orientation_error.size(); i++) { + orientation_error(i) = std::fmod(orientation_error(i), 2.0 * M_PI); + if (orientation_error(i) < 0.0) { + orientation_error(i) += 2.0 * M_PI; + } + orientation_error(i) -= M_PI; + } + VectorXd initial_pose_ecef_quat = quat2vector(euler2quat(ecef_euler_from_ned({ ecef_pos(0), ecef_pos(1), ecef_pos(2) }, orientation_ned_gps))); + + if (ecef_pos_std > GPS_POS_STD_THRESHOLD || ecef_vel_std > GPS_VEL_STD_THRESHOLD) { + this->gps_valid = false; + this->determine_gps_mode(current_time); + return; + } + + if ((gps_est_error > GPS_POS_ERROR_RESET_THRESHOLD && ecef_pos_std < GPS_POS_STD_RESET_THRESHOLD) || this->last_gps_msg == 0) { + // always reset on first gps message and if the location is off but the accuracy is high + LOGE("Locationd vs gnssMeasurement position difference too large, kalman reset"); + this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); + } else if (ecef_vel_std < GPS_VEL_STD_RESET_THRESHOLD && orientation_error.norm() > GPS_ORIENTATION_ERROR_RESET_THRESHOLD) { + LOGE("Locationd vs gnssMeasurement orientation difference too large, kalman reset"); + this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); + this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_ORIENTATION_FROM_GPS, { initial_pose_ecef_quat }); + } + + this->last_gps_msg = current_time; + this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_POS, { ecef_pos }, { ecef_pos_R }); + this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); +} + void Localizer::handle_car_state(double current_time, const cereal::CarState::Reader& log) { this->car_speed = std::abs(log.getVEgo()); if (log.getStandstill()) { @@ -497,9 +575,11 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); } else if (log.isGpsLocation()) { - this->handle_gps(t, log.getGpsLocation(), GPS_LOCATION_SENSOR_TIME_OFFSET); + this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); } else if (log.isGpsLocationExternal()) { - this->handle_gps(t, log.getGpsLocationExternal(), GPS_LOCATION_EXTERNAL_SENSOR_TIME_OFFSET); + this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + //} else if (log.isGnssMeasurements()) { + // this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index f0872d9f56..7a282be9d7 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -52,6 +52,7 @@ public: void handle_msg(const cereal::Event::Reader& log); void handle_sensor(double current_time, const cereal::SensorEventData::Reader& log); void handle_gps(double current_time, const cereal::GpsLocationData::Reader& log, const double sensor_time_offset); + void handle_gnss(double current_time, const cereal::GnssMeasurements::Reader& log); void handle_car_state(double current_time, const cereal::CarState::Reader& log); void handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log); void handle_live_calib(double current_time, const cereal::LiveCalibrationData::Reader& log); @@ -77,6 +78,7 @@ private: bool device_fell = false; bool gps_mode = false; bool gps_valid = false; + double last_gps_msg = 0; bool ublox_available = true; bool observation_timings_invalid = false; std::map observation_values_invalid; diff --git a/selfdrive/locationd/test/test_ublox_processing.py b/selfdrive/locationd/test/test_ublox_processing.py index 427003b24c..7aa588d43e 100755 --- a/selfdrive/locationd/test/test_ublox_processing.py +++ b/selfdrive/locationd/test/test_ublox_processing.py @@ -4,7 +4,8 @@ import numpy as np from laika import AstroDog from laika.helpers import ConstellationId -from laika.raw_gnss import calc_pos_fix, correct_measurements, process_measurements, read_raw_ublox +from laika.raw_gnss import correct_measurements, process_measurements, read_raw_ublox +from laika.opt import calc_pos_fix from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader @@ -54,14 +55,14 @@ class TestUbloxProcessing(unittest.TestCase): processed_meas = process_measurements(measurements, dog) count_processed_measurements += len(processed_meas) pos_fix = calc_pos_fix(processed_meas) - if len(pos_fix) > 0 and all(pos_fix[0] != 0): + if len(pos_fix) > 0 and all(p != 0 for p in pos_fix[0]): position_fix_found += 1 corrected_meas = correct_measurements(processed_meas, pos_fix[0][:3], dog) count_corrected_measurements += len(corrected_meas) pos_fix = calc_pos_fix(corrected_meas) - if len(pos_fix) > 0 and all(pos_fix[0] != 0): + if len(pos_fix) > 0 and all(p != 0 for p in pos_fix[0]): pos_ests.append(pos_fix[0]) position_fix_found_after_correcting += 1 diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index bc55e33cbf..c5465fc025 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -251,8 +251,10 @@ def ublox_rcv_callback(msg): def laika_rcv_callback(msg, CP, cfg, fsm): if msg.which() == 'ubloxGnss' and msg.ubloxGnss.which() == "measurementReport": return ["gnssMeasurements"], True + elif msg.which() == 'qcomGnss' and msg.qcomGnss.which() == "drMeasurementReport": + return ["gnssMeasurements"], True else: - return [], True + return [], False CONFIGS = [ @@ -360,24 +362,11 @@ CONFIGS = [ tolerance=None, fake_pubsubmaster=False, ), - ProcessConfig( - proc_name="laikad", - subtest_name="Offline", - pub_sub={ - "ubloxGnss": ["gnssMeasurements"], - "clocks": [] - }, - ignore=["logMonoTime"], - init_callback=get_car_params, - should_recv_callback=laika_rcv_callback, - tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, - environ={"LAIKAD_NO_INTERNET": "1"}, - ), ProcessConfig( proc_name="laikad", pub_sub={ "ubloxGnss": ["gnssMeasurements"], + "qcomGnss": ["gnssMeasurements"], "clocks": [] }, ignore=["logMonoTime"], @@ -474,6 +463,12 @@ def python_replay_process(cfg, lr, fingerprint=None): all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) pub_msgs = [msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())] + # laikad needs decision between submaster ubloxGnss and qcomGnss, prio given to ubloxGnss + if cfg.proc_name == "laikad": + args = (*args, not any(m.which() == "ubloxGnss" for m in pub_msgs)) + service = "qcomGnss" if args[2] else "ubloxGnss" + pub_msgs = [m for m in pub_msgs if m.which() == service or m.which() == 'clocks'] + controlsState = None initialized = False for msg in lr: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1d586b0334..603d2b2d96 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -05ba201bcf97b6c1067dbcde2a60f71f43469c56 +557ffbf5a1c9cafba1ff8d6f3e2642df98b2d6e6 \ No newline at end of file From e01809857174533e61a25d4bcb85b708031aa8cb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 31 Dec 2022 05:57:29 +0800 Subject: [PATCH 0559/1179] Cabana: add dynamic/static mode to logs view (#26832) --- tools/cabana/historylog.cc | 141 +++++++++++++++++++++++-------------- tools/cabana/historylog.h | 23 ++++-- 2 files changed, 105 insertions(+), 59 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 0fd939c6f7..485a21cc1b 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -7,12 +7,6 @@ // HistoryLogModel -HistoryLogModel::HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) { - QObject::connect(can, &CANMessages::seekedTo, [this]() { - if (!msg_id.isEmpty()) setMessage(msg_id); - }); -} - QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { const auto &m = messages[index.row()]; @@ -29,17 +23,19 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { } void HistoryLogModel::setMessage(const QString &message_id) { - beginResetModel(); + msg_id = message_id; sigs.clear(); - messages.clear(); - has_more_data = true; - if (auto dbc_msg = dbc()->msg(message_id)) { + if (auto dbc_msg = dbc()->msg(msg_id)) { sigs = dbc_msg->getSignals(); } - if (msg_id != message_id || sigs.empty()) { - filter_cmp = nullptr; - } - msg_id = message_id; + filter_cmp = nullptr; + refresh(); +} + +void HistoryLogModel::refresh() { + beginResetModel(); + last_fetch_time = 0; + messages.clear(); updateState(); endResetModel(); } @@ -60,33 +56,40 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i return {}; } -void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function cmp) { - if (sig_idx < sigs.size()) { - filter_sig_idx = sig_idx; - filter_value = value.toDouble(); - filter_cmp = value.isEmpty() ? nullptr : cmp; - beginResetModel(); - messages.clear(); - updateState(); - endResetModel(); +void HistoryLogModel::setDynamicMode(int state) { + dynamic_mode = state != 0; + refresh(); +} + +void HistoryLogModel::segmentsMerged() { + if (!dynamic_mode) { + has_more_data = true; } } +void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function cmp) { + filter_sig_idx = sig_idx; + filter_value = value.toDouble(); + filter_cmp = value.isEmpty() ? nullptr : cmp; + refresh(); +} + void HistoryLogModel::updateState() { if (!msg_id.isEmpty()) { - uint64_t last_mono_time = messages.empty() ? 0 : messages.front().mono_time; - auto new_msgs = fetchData(last_mono_time, (can->currentSec() + can->routeStartTime()) * 1e9); + uint64_t current_time = (can->currentSec() + can->routeStartTime()) * 1e9; + auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, 0, new_msgs.size() - 1); messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); endInsertRows(); } + last_fetch_time = current_time; } } void HistoryLogModel::fetchMore(const QModelIndex &parent) { if (!messages.empty()) { - auto new_msgs = fetchData(0, messages.back().mono_time); + auto new_msgs = fetchData(messages.back().mono_time); if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, messages.size(), messages.size() + new_msgs.size() - 1); messages.insert(messages.end(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); @@ -95,19 +98,12 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) { } } -std::deque HistoryLogModel::fetchData(uint64_t min_mono_time, uint64_t max_mono_time) { - auto events = can->events(); - auto it = std::lower_bound(events->begin(), events->end(), max_mono_time, [=](auto &e, uint64_t ts) { - return e->mono_time < ts; - }); - if (it == events->end() || it == events->begin()) - return {}; - +template +std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; const auto [src, address] = DBCManager::parseId(msg_id); - uint32_t cnt = 0; QVector values(sigs.size()); - for (--it; it != events->begin() && (*it)->mono_time > min_mono_time; --it) { + for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { if (src == c.getSrc() && address == c.getAddress()) { @@ -120,7 +116,7 @@ std::deque HistoryLogModel::fetchData(uint64_t min_mon m.mono_time = (*it)->mono_time; m.data = toHex(QByteArray((char *)dat.begin(), dat.size())); m.sig_values = values; - if (++cnt >= batch_size && min_mono_time == 0) + if (msgs.size() >= batch_size && min_time == 0) return msgs; } } @@ -129,6 +125,25 @@ std::deque HistoryLogModel::fetchData(uint64_t min_mon } return msgs; } +template std::deque HistoryLogModel::fetchData<>(std::vector::iterator first, std::vector::iterator last, uint64_t min_time); +template std::deque HistoryLogModel::fetchData<>(std::vector::reverse_iterator first, std::vector::reverse_iterator last, uint64_t min_time); + +std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { + auto events = can->events(); + if (dynamic_mode) { + auto it = std::lower_bound(events->rbegin(), events->rend(), from_time, [=](auto &e, uint64_t ts) { + return e->mono_time > ts; + }); + if (it != events->rend()) ++it; + return fetchData(it, events->rend(), min_time); + } else { + assert(min_time == 0); + auto it = std::upper_bound(events->begin(), events->end(), from_time, [=](uint64_t ts, auto &e) { + return ts < e->mono_time; + }); + return fetchData(it, events->end(), 0); + } +} // HeaderView @@ -166,9 +181,9 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - filter_container = new QWidget(this); - QHBoxLayout *h = new QHBoxLayout(filter_container); + QHBoxLayout *h = new QHBoxLayout(); signals_cb = new QComboBox(this); + signals_cb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); h->addWidget(signals_cb); comp_box = new QComboBox(); comp_box->addItems({">", "=", "!=", "<"}); @@ -177,7 +192,9 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { value_edit->setClearButtonEnabled(true); value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); h->addWidget(value_edit); - main_layout->addWidget(filter_container); + dynamic_mode = new QCheckBox(tr("Dynamic")); + h->addWidget(dynamic_mode, 0, Qt::AlignRight); + main_layout->addLayout(h); model = new HistoryLogModel(this); logs = new HistoryLog(this); @@ -185,33 +202,38 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(logs); QObject::connect(logs, &QTableView::doubleClicked, this, &LogsWidget::doubleClicked); - QObject::connect(signals_cb, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilter())); - QObject::connect(comp_box, SIGNAL(currentIndexChanged(int)), this, SLOT(setFilter())); + QObject::connect(signals_cb, SIGNAL(activated(int)), this, SLOT(setFilter())); + QObject::connect(comp_box, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); + QObject::connect(dynamic_mode, &QCheckBox::stateChanged, model, &HistoryLogModel::setDynamicMode); + QObject::connect(can, &CANMessages::seekedTo, model, &HistoryLogModel::refresh); + QObject::connect(can, &CANMessages::eventsMerged, model, &HistoryLogModel::segmentsMerged); } void LogsWidget::setMessage(const QString &message_id) { - blockSignals(true); + model->setMessage(message_id); + cur_filter_text = ""; value_edit->setText(""); signals_cb->clear(); comp_box->setCurrentIndex(0); - sigs.clear(); - if (auto dbc_msg = dbc()->msg(message_id)) { - sigs = dbc_msg->getSignals(); - for (auto s : sigs) { + bool has_signals = model->sigs.size() > 0; + if (has_signals) { + for (auto s : model->sigs) { signals_cb->addItem(s->name.c_str()); } } - filter_container->setVisible(!sigs.empty()); - model->setMessage(message_id); - blockSignals(false); + comp_box->setVisible(has_signals); + value_edit->setVisible(has_signals); + signals_cb->setVisible(has_signals); } -static bool not_equal(double l, double r) { - return l != r; -} +static bool not_equal(double l, double r) { return l != r; } void LogsWidget::setFilter() { + if (cur_filter_text.isEmpty() && value_edit->text().isEmpty()) { + return; + } + std::function cmp; switch (comp_box->currentIndex()) { case 0: cmp = std::greater{}; break; @@ -220,6 +242,19 @@ void LogsWidget::setFilter() { case 3: cmp = std::less{}; break; } model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); + cur_filter_text = value_edit->text(); +} + +void LogsWidget::showEvent(QShowEvent *event) { + if (dynamic_mode->isChecked()) { + model->refresh(); + } +} + +void LogsWidget::updateState() { + if (dynamic_mode->isChecked()) { + model->updateState(); + } } void LogsWidget::doubleClicked(const QModelIndex &index) { diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index c636f9b48f..f20f51637a 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -17,8 +18,10 @@ public: }; class HistoryLogModel : public QAbstractTableModel { + Q_OBJECT + public: - HistoryLogModel(QObject *parent); + HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} void setMessage(const QString &message_id); void updateState(); void setFilter(int sig_idx, const QString &value, std::function cmp); @@ -28,6 +31,9 @@ public: inline bool canFetchMore(const QModelIndex &parent) const override { return has_more_data; } int rowCount(const QModelIndex &parent = QModelIndex()) const override { return messages.size(); } int columnCount(const QModelIndex &parent = QModelIndex()) const override { return std::max(1ul, sigs.size()) + 1; } + void setDynamicMode(int state); + void segmentsMerged(); + void refresh(); struct Message { uint64_t mono_time = 0; @@ -35,15 +41,20 @@ public: QString data; }; - std::deque fetchData(uint64_t min_mono_time, uint64_t max_mono_time); + template + std::deque fetchData(InputIt first, InputIt last, uint64_t min_time); + std::deque fetchData(uint64_t from_time, uint64_t min_time = 0); + QString msg_id; bool has_more_data = true; const int batch_size = 50; int filter_sig_idx = -1; double filter_value = 0; + uint64_t last_fetch_time = 0; std::function filter_cmp = nullptr; std::deque messages; std::vector sigs; + bool dynamic_mode = false; }; class HistoryLog : public QTableView { @@ -58,7 +69,7 @@ class LogsWidget : public QWidget { public: LogsWidget(QWidget *parent); void setMessage(const QString &message_id); - void updateState() { model->updateState(); } + void updateState(); signals: void openChart(const QString &msg_id, const Signal *sig); @@ -68,12 +79,12 @@ private slots: private: void doubleClicked(const QModelIndex &index); - void showEvent(QShowEvent *event) override { model->setMessage(model->msg_id); }; + void showEvent(QShowEvent *event) override; HistoryLog *logs; HistoryLogModel *model; - QWidget *filter_container; + QCheckBox *dynamic_mode; QComboBox *signals_cb, *comp_box; QLineEdit *value_edit; - std::vector sigs; + QString cur_filter_text; }; From 28d0459c69a6f9bcf511fe982ba573cb7842e385 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 30 Dec 2022 14:44:59 -0800 Subject: [PATCH 0560/1179] update_requirements: skip pre-commit install on mac --- update_requirements.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/update_requirements.sh b/update_requirements.sh index e5dedea7a6..b430df59e5 100755 --- a/update_requirements.sh +++ b/update_requirements.sh @@ -69,11 +69,13 @@ else RUN="poetry run" fi -echo "pre-commit hooks install..." -shopt -s nullglob -for f in .pre-commit-config.yaml */.pre-commit-config.yaml; do - cd $DIR/$(dirname $f) - if [ -e ".git" ]; then - $RUN pre-commit install - fi -done +if [ "$(uname)" != "Darwin" ]; then + echo "pre-commit hooks install..." + shopt -s nullglob + for f in .pre-commit-config.yaml */.pre-commit-config.yaml; do + cd $DIR/$(dirname $f) + if [ -e ".git" ]; then + $RUN pre-commit install + fi + done +fi From a7155a43b726266084554e7cfa11d8a7bba88238 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Fri, 30 Dec 2022 18:16:24 -0600 Subject: [PATCH 0561/1179] Add several missing HIGHLANDERH_TSS2 firmwares (#26844) * Add several missing HIGHLANDERH_TSS2 firmwares `@joeswisher#3240` 2023 Highlander Hybrid DongleID/route 1cdd18b56163c309|2022-12-29--23-18-05 * docs.py gen'd CARS.md w/ 2023 Highlander Hybrid update --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index ce067609aa..f3667c4cea 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -182,7 +182,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| |Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| |Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 80c0ccbb83..64a0bed0b2 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -131,7 +131,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.HIGHLANDER: ToyotaCarInfo("Toyota Highlander 2017-19", video_link="https://www.youtube.com/watch?v=0wS0wXSLzoo"), CAR.HIGHLANDER_TSS2: ToyotaCarInfo("Toyota Highlander 2020-23"), CAR.HIGHLANDERH: ToyotaCarInfo("Toyota Highlander Hybrid 2017-19"), - CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-22"), + CAR.HIGHLANDERH_TSS2: ToyotaCarInfo("Toyota Highlander Hybrid 2020-23"), CAR.PRIUS: [ ToyotaCarInfo("Toyota Prius 2016", "Toyota Safety Sense P", "https://www.youtube.com/watch?v=8zopPJI8XQ0"), ToyotaCarInfo("Toyota Prius 2017-20", video_link="https://www.youtube.com/watch?v=8zopPJI8XQ0"), @@ -1023,11 +1023,13 @@ FW_VERSIONS = { (Ecu.eps, 0x7a1, None): [ b'8965B48241\x00\x00\x00\x00\x00\x00', b'8965B48310\x00\x00\x00\x00\x00\x00', + b'8965B48400\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'\x01F15264872300\x00\x00\x00\x00', b'\x01F15264872400\x00\x00\x00\x00', b'\x01F15264872500\x00\x00\x00\x00', + b'\x01F15264872600\x00\x00\x00\x00', b'\x01F15264873500\x00\x00\x00\x00', b'\x01F152648C6300\x00\x00\x00\x00', b'\x01F152648J4000\x00\x00\x00\x00', @@ -1041,6 +1043,7 @@ FW_VERSIONS = { b'\x01896630EE4100\x00\x00\x00\x00', b'\x01896630EE5000\x00\x00\x00\x00', b'\x01896630EE6000\x00\x00\x00\x00', + b'\x01896630EF8000\x00\x00\x00\x00', b'\x02896630E66000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x02896630E66100\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', b'\x01896630EA1000\x00\x00\x00\x00897CF4801001\x00\x00\x00\x00', @@ -1056,6 +1059,7 @@ FW_VERSIONS = { b'\x028646F0E02100\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F4803000\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F4803000\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', + b'\x028646F4803200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.LEXUS_IS: { From 52b72dd71b77e1937691174a790fc8cc348298a3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 30 Dec 2022 17:16:22 -0800 Subject: [PATCH 0562/1179] LGTM.com is deprecated (#26846) --- README.md | 3 --- lgtm.yml | 19 ------------------- 2 files changed, 22 deletions(-) delete mode 100644 lgtm.yml diff --git a/README.md b/README.md index cfeb625bfe..88b7aeb2bb 100755 --- a/README.md +++ b/README.md @@ -143,7 +143,4 @@ NO WARRANTY EXPRESSED OR IMPLIED.** [![openpilot tests](https://github.com/commaai/openpilot/workflows/openpilot%20tests/badge.svg?event=push)](https://github.com/commaai/openpilot/actions) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/alerts/) -[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:python) -[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:cpp) [![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot) diff --git a/lgtm.yml b/lgtm.yml deleted file mode 100644 index 6ce9353562..0000000000 --- a/lgtm.yml +++ /dev/null @@ -1,19 +0,0 @@ -path_classifiers: - library: - - external - - third_party - - pyextra - - tools/lib/mkvparse -extraction: - cpp: - after_prepare: - - "pip3 install --upgrade --user pkgconfig cython setuptools wheel" - - "pip3 install --upgrade --user jinja2 pyyaml cython pycapnp numpy sympy tqdm\ - \ cffi logentries zmq scons" - - "export PATH=/opt/work/.local/bin:$PATH" - index: - build_command: "scons" - javascript: - index: - filters: - - exclude: "*" From e3a41b3c255a5c72064f66c4d2504e1655bf2ac9 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 30 Dec 2022 20:25:33 -0800 Subject: [PATCH 0563/1179] add spidev2 package (#26847) --- poetry.lock | 43 ++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index f7bc4669a3..9ab86329d7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1352,6 +1352,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "ioctl-opt" +version = "1.2.2" +description = "Functions to compute fnctl.ioctl's opt argument" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "ipykernel" version = "6.16.1" @@ -3881,6 +3889,17 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "spidev2" +version = "0.9.0" +description = "Pure-python interface to Linux spidev." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +ioctl-opt = "*" + [[package]] name = "sqlalchemy" version = "1.4.42" @@ -4425,7 +4444,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "d894380c87f5558e032708cc1230aed172ad3e1db9aa112e2e105bebefff4e20" +content-hash = "2ab9d6aee6cc2c7bb5ba9763a54779ef9535cb752ec0038736a442992a04d459" [metadata.files] adal = [ @@ -5624,6 +5643,9 @@ inputs = [ {file = "inputs-0.5-py2.py3-none-any.whl", hash = "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec"}, {file = "inputs-0.5.tar.gz", hash = "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4"}, ] +ioctl-opt = [ + {file = "ioctl-opt-1.2.2.tar.gz", hash = "sha256:9628bbd6728f90d019759f54d20b741ddbf9f8db8d41976da4332492f669d643"}, +] ipykernel = [ {file = "ipykernel-6.16.1-py3-none-any.whl", hash = "sha256:32eb7bdc5af57185e9a42b0dcef66413ef91a0490b378eae46cbdf0d4e0b5912"}, {file = "ipykernel-6.16.1.tar.gz", hash = "sha256:3a27a550c1d682e7825f0f7732b0142b79ef1b21cd2e713cacac0c9847535f13"}, @@ -6429,6 +6451,7 @@ onnx = [ ] onnx2torch = [ {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, + {file = "onnx2torch-1.5.4.tar.gz", hash = "sha256:df837b557a63540223d85fde4a1d679fde0ca8d8bb89d5379c030b01eddc9c24"}, ] onnxoptimizer = [ {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, @@ -6810,6 +6833,7 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -6817,12 +6841,14 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, + {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, @@ -7417,6 +7443,18 @@ setproctitle = [ {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, + {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, + {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, @@ -7611,6 +7649,9 @@ spidev = [ {file = "spidev-3.6-cp39-cp39-linux_armv7l.whl", hash = "sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5"}, {file = "spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b"}, ] +spidev2 = [ + {file = "spidev2-0.9.0.tar.gz", hash = "sha256:152da2911a8660283ceac3a75dd869953379bcbcf079e5436af5aae736876086"}, +] sqlalchemy = [ {file = "SQLAlchemy-1.4.42-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124"}, {file = "SQLAlchemy-1.4.42-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88"}, diff --git a/pyproject.toml b/pyproject.toml index e99b278341..af9fcc6e6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ six = "^1.16.0" smbus2 = "^0.4.2" sounddevice = "^0.4.5" spidev = { version = "^3.6", platform = "linux" } +spidev2 = { version = "^0.9.0", platform = "linux" } sympy = "^1.10.1" timezonefinder = "^6.0.1" tqdm = "^4.64.0" From 65414bcd8d2fa23d0c6dce8070fb468c08a85dde Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 31 Dec 2022 11:30:28 -0800 Subject: [PATCH 0564/1179] controlsd: remove laikad from ignored process list --- selfdrive/controls/controlsd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 36f0b559c2..fea19adbdb 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -38,7 +38,7 @@ REPLAY = "REPLAY" in os.environ SIMULATION = "SIMULATION" in os.environ NOSENSOR = "NOSENSOR" in os.environ IGNORE_PROCESSES = {"uploader", "deleter", "loggerd", "logmessaged", "tombstoned", "statsd", - "logcatd", "proclogd", "clocksd", "updated", "timezoned", "manage_athenad", "laikad"} | \ + "logcatd", "proclogd", "clocksd", "updated", "timezoned", "manage_athenad"} | \ {k for k, v in managed_processes.items() if not v.enabled} ThermalStatus = log.DeviceState.ThermalStatus From 304796bafe0c0608e40b20fc44923f9edf462240 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 31 Dec 2022 19:51:03 -0800 Subject: [PATCH 0565/1179] ui: draw radarState leads (#26852) use radarState --- selfdrive/ui/qt/onroad.cc | 20 +++++++++++--------- selfdrive/ui/qt/onroad.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 95ad813dff..1b4b880fbf 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -498,13 +498,13 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { painter.restore(); } -void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd) { +void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd) { painter.save(); const float speedBuff = 10.; const float leadBuff = 40.; - const float d_rel = lead_data.getX()[0]; - const float v_rel = lead_data.getV()[0]; + const float d_rel = lead_data.getDRel(); + const float v_rel = lead_data.getVRel(); float fillAlpha = 0; if (d_rel < leadBuff) { @@ -539,6 +539,7 @@ void AnnotatedCameraWidget::paintGL() { SubMaster &sm = *(s->sm); const double start_draw_t = millis_since_boot(); const cereal::ModelDataV2::Reader &model = sm["modelV2"].getModelV2(); + const cereal::RadarState::Reader &radar_state = sm["radarState"].getRadarState(); // draw camera frame { @@ -589,19 +590,20 @@ void AnnotatedCameraWidget::paintGL() { if (sm.rcv_frame("modelV2") > s->scene.started_frame) { update_model(s, sm["modelV2"].getModelV2()); if (sm.rcv_frame("radarState") > s->scene.started_frame) { - update_leads(s, sm["radarState"].getRadarState(), sm["modelV2"].getModelV2().getPosition()); + update_leads(s, radar_state, sm["modelV2"].getModelV2().getPosition()); } } drawLaneLines(painter, s); if (s->scene.longitudinal_control) { - const auto leads = model.getLeadsV3(); - if (leads[0].getProb() > .5) { - drawLead(painter, leads[0], s->scene.lead_vertices[0]); + auto lead_one = radar_state.getLeadOne(); + auto lead_two = radar_state.getLeadTwo(); + if (lead_one.getStatus()) { + drawLead(painter, lead_one, s->scene.lead_vertices[0]); } - if (leads[1].getProb() > .5 && (std::abs(leads[1].getX()[0] - leads[0].getX()[0]) > 3.0)) { - drawLead(painter, leads[1], s->scene.lead_vertices[1]); + if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { + drawLead(painter, lead_two, s->scene.lead_vertices[1]); } } } diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 9e18355970..3dbb05b674 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -80,7 +80,7 @@ protected: void showEvent(QShowEvent *event) override; void updateFrameMat() override; void drawLaneLines(QPainter &painter, const UIState *s); - void drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd); + void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd); void drawHud(QPainter &p); inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } From cd8e03d53ed210aec46a2ff728cb4a830314a21a Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 31 Dec 2022 21:00:50 -0800 Subject: [PATCH 0566/1179] move all third party stuff into third_party/ (#26853) * mv fastcluster * move msm_kgsl.h * camerad include * update path * mv pyextra * fix tici build * add acados_template to release build Co-authored-by: Comma Device --- .pre-commit-config.yaml | 12 ++++++------ Dockerfile.openpilot | 1 - README.md | 1 - SConstruct | 5 ++--- docs/Makefile | 2 +- docs/docker/Dockerfile | 1 - launch_chffrplus.sh | 2 +- mypy.ini | 2 +- release/files_common | 11 ++++------- selfdrive/controls/lib/lateral_mpc_lib/SConscript | 6 +++--- selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py | 2 +- .../controls/lib/longitudinal_mpc_lib/SConscript | 6 +++--- .../controls/lib/longitudinal_mpc_lib/long_mpc.py | 2 +- selfdrive/controls/radard.py | 2 +- selfdrive/controls/tests/test_clustering.py | 4 ++-- selfdrive/manager/manager.py | 2 -- selfdrive/modeld/thneed/thneed.h | 2 +- system/camerad/SConscript | 14 +++++--------- {pyextra => third_party}/.gitignore | 0 third_party/SConscript | 2 ++ .../acados}/acados_template/.gitignore | 0 .../acados}/acados_template/__init__.py | 0 .../acados}/acados_template/acados_layout.json | 0 .../acados}/acados_template/acados_model.py | 0 .../acados}/acados_template/acados_ocp.py | 0 .../acados}/acados_template/acados_ocp_solver.py | 0 .../acados_template/acados_ocp_solver_pyx.pyx | 0 .../acados}/acados_template/acados_sim.py | 0 .../acados}/acados_template/acados_sim_layout.json | 0 .../acados}/acados_template/acados_sim_solver.py | 0 .../acados_template/acados_solver_common.pxd | 0 .../acados}/acados_template/builders.py | 0 .../c_templates_tera/CMakeLists.in.txt | 0 .../acados_template/c_templates_tera/CPPLINT.cfg | 0 .../acados_template/c_templates_tera/Makefile.in | 0 .../c_templates_tera/acados_mex_create.in.c | 0 .../c_templates_tera/acados_mex_free.in.c | 0 .../c_templates_tera/acados_mex_set.in.c | 0 .../c_templates_tera/acados_mex_solve.in.c | 0 .../c_templates_tera/acados_sim_solver.in.c | 0 .../c_templates_tera/acados_sim_solver.in.h | 0 .../c_templates_tera/acados_sim_solver_sfun.in.c | 0 .../c_templates_tera/acados_solver.in.c | 0 .../c_templates_tera/acados_solver.in.h | 0 .../c_templates_tera/acados_solver.in.pxd | 0 .../c_templates_tera/acados_solver_sfun.in.c | 0 .../c_templates_tera/cost_y_0_fun.in.h | 0 .../c_templates_tera/cost_y_e_fun.in.h | 0 .../c_templates_tera/cost_y_fun.in.h | 0 .../c_templates_tera/external_cost.in.h | 0 .../c_templates_tera/external_cost_0.in.h | 0 .../c_templates_tera/external_cost_e.in.h | 0 .../c_templates_tera/h_constraint.in.h | 0 .../c_templates_tera/h_e_constraint.in.h | 0 .../acados_template/c_templates_tera/main.in.c | 0 .../acados_template/c_templates_tera/main_mex.in.c | 0 .../acados_template/c_templates_tera/main_sim.in.c | 0 .../c_templates_tera/make_main_mex.in.m | 0 .../acados_template/c_templates_tera/make_mex.in.m | 0 .../c_templates_tera/make_sfun.in.m | 0 .../c_templates_tera/make_sfun_sim.in.m | 0 .../c_templates_tera/mex_solver.in.m | 0 .../acados_template/c_templates_tera/model.in.h | 0 .../c_templates_tera/phi_constraint.in.h | 0 .../c_templates_tera/phi_e_constraint.in.h | 0 .../acados_template/generate_c_code_constraint.py | 0 .../generate_c_code_discrete_dynamics.py | 0 .../generate_c_code_explicit_ode.py | 0 .../generate_c_code_external_cost.py | 0 .../acados_template/generate_c_code_gnsf.py | 0 .../generate_c_code_implicit_ode.py | 0 .../acados_template/generate_c_code_nls_cost.py | 0 .../acados_template/simulink_default_opts.json | 0 .../acados}/acados_template/utils.py | 0 third_party/acados/build.sh | 5 ++--- .../lib => third_party}/cluster/.gitignore | 0 .../controls/lib => third_party}/cluster/LICENSE | 0 .../controls/lib => third_party}/cluster/README | 0 .../lib => third_party}/cluster/SConscript | 0 .../lib => third_party}/cluster/__init__.py | 0 .../lib => third_party}/cluster/fastcluster.cpp | 0 .../lib => third_party}/cluster/fastcluster.h | 0 .../cluster/fastcluster_R_dm.cpp | 0 .../lib => third_party}/cluster/fastcluster_dm.cpp | 0 .../lib => third_party}/cluster/fastcluster_py.py | 0 .../controls/lib => third_party}/cluster/test.cpp | 0 .../linux}/include/media/cam_cpas.h | 0 .../linux}/include/media/cam_defs.h | 0 .../linux}/include/media/cam_fd.h | 0 .../linux}/include/media/cam_icp.h | 0 .../linux}/include/media/cam_isp.h | 0 .../linux}/include/media/cam_isp_ife.h | 0 .../linux}/include/media/cam_isp_vfe.h | 0 .../linux}/include/media/cam_jpeg.h | 0 .../linux}/include/media/cam_lrme.h | 0 .../linux}/include/media/cam_req_mgr.h | 0 .../linux}/include/media/cam_sensor.h | 0 .../linux}/include/media/cam_sensor_cmn_header.h | 0 .../linux}/include/media/cam_sync.h | 0 .../linux}/include/msm_cam_sensor.h | 0 .../linux}/include/msm_camsensor_sdk.h | 0 .../linux}/include/msm_kgsl.h | 0 .../linux}/include/msmb_camera.h | 0 .../linux}/include/msmb_isp.h | 0 .../linux}/include/msmb_ispif.h | 0 tools/gpstest/fuzzy_testing.py | 2 +- tools/sim/Dockerfile.sim | 1 - 107 files changed, 37 insertions(+), 50 deletions(-) rename {pyextra => third_party}/.gitignore (100%) rename {pyextra => third_party/acados}/acados_template/.gitignore (100%) rename {pyextra => third_party/acados}/acados_template/__init__.py (100%) rename {pyextra => third_party/acados}/acados_template/acados_layout.json (100%) rename {pyextra => third_party/acados}/acados_template/acados_model.py (100%) rename {pyextra => third_party/acados}/acados_template/acados_ocp.py (100%) rename {pyextra => third_party/acados}/acados_template/acados_ocp_solver.py (100%) rename {pyextra => third_party/acados}/acados_template/acados_ocp_solver_pyx.pyx (100%) rename {pyextra => third_party/acados}/acados_template/acados_sim.py (100%) rename {pyextra => third_party/acados}/acados_template/acados_sim_layout.json (100%) rename {pyextra => third_party/acados}/acados_template/acados_sim_solver.py (100%) rename {pyextra => third_party/acados}/acados_template/acados_solver_common.pxd (100%) rename {pyextra => third_party/acados}/acados_template/builders.py (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/CMakeLists.in.txt (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/CPPLINT.cfg (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/Makefile.in (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_mex_create.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_mex_free.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_mex_set.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_mex_solve.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_sim_solver.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_sim_solver.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_solver.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_solver.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_solver.in.pxd (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/acados_solver_sfun.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/cost_y_0_fun.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/cost_y_e_fun.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/cost_y_fun.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/external_cost.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/external_cost_0.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/external_cost_e.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/h_constraint.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/h_e_constraint.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/main.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/main_mex.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/main_sim.in.c (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/make_main_mex.in.m (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/make_mex.in.m (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/make_sfun.in.m (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/make_sfun_sim.in.m (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/mex_solver.in.m (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/model.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/phi_constraint.in.h (100%) rename {pyextra => third_party/acados}/acados_template/c_templates_tera/phi_e_constraint.in.h (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_constraint.py (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_discrete_dynamics.py (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_explicit_ode.py (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_external_cost.py (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_gnsf.py (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_implicit_ode.py (100%) rename {pyextra => third_party/acados}/acados_template/generate_c_code_nls_cost.py (100%) rename {pyextra => third_party/acados}/acados_template/simulink_default_opts.json (100%) rename {pyextra => third_party/acados}/acados_template/utils.py (100%) rename {selfdrive/controls/lib => third_party}/cluster/.gitignore (100%) rename {selfdrive/controls/lib => third_party}/cluster/LICENSE (100%) rename {selfdrive/controls/lib => third_party}/cluster/README (100%) rename {selfdrive/controls/lib => third_party}/cluster/SConscript (100%) rename {selfdrive/controls/lib => third_party}/cluster/__init__.py (100%) rename {selfdrive/controls/lib => third_party}/cluster/fastcluster.cpp (100%) rename {selfdrive/controls/lib => third_party}/cluster/fastcluster.h (100%) rename {selfdrive/controls/lib => third_party}/cluster/fastcluster_R_dm.cpp (100%) rename {selfdrive/controls/lib => third_party}/cluster/fastcluster_dm.cpp (100%) rename {selfdrive/controls/lib => third_party}/cluster/fastcluster_py.py (100%) rename {selfdrive/controls/lib => third_party}/cluster/test.cpp (100%) rename {system/camerad => third_party/linux}/include/media/cam_cpas.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_defs.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_fd.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_icp.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_isp.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_isp_ife.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_isp_vfe.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_jpeg.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_lrme.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_req_mgr.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_sensor.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_sensor_cmn_header.h (100%) rename {system/camerad => third_party/linux}/include/media/cam_sync.h (100%) rename {system/camerad => third_party/linux}/include/msm_cam_sensor.h (100%) rename {system/camerad => third_party/linux}/include/msm_camsensor_sdk.h (100%) rename {selfdrive/modeld/thneed => third_party/linux}/include/msm_kgsl.h (100%) rename {system/camerad => third_party/linux}/include/msmb_camera.h (100%) rename {system/camerad => third_party/linux}/include/msmb_isp.h (100%) rename {system/camerad => third_party/linux}/include/msmb_ispif.h (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91b9c61628..edbca52fed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: rev: v4.1.0 hooks: - id: check-ast - exclude: '^(pyextra)/' + exclude: '^(third_party)/' - id: check-json - id: check-xml - id: check-yaml @@ -19,7 +19,7 @@ repos: rev: v2.2.1 hooks: - id: codespell - exclude: '^(pyextra/)|(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(include/)|(selfdrive/ui/translations/.*.ts)|(selfdrive/controls/lib/cluster)' + exclude: '^(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/ui/translations/.*.ts)' args: # if you've got a short variable name that's getting flagged, add it here - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup @@ -31,12 +31,12 @@ repos: entry: mypy language: system types: [python] - exclude: '^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' + exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)' - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 - exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(selfdrive/debug/)/' + exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(selfdrive/debug/)/' additional_dependencies: ['flake8-no-implicit-concat'] args: - --indent-size=2 @@ -51,7 +51,7 @@ repos: entry: pylint language: system types: [python] - exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' + exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)' args: - -j0 - -rn @@ -64,7 +64,7 @@ repos: entry: cppcheck language: system types: [c++] - exclude: '^(third_party/)|(pyextra/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)' + exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)' args: - --error-exitcode=1 - --language=c++ diff --git a/Dockerfile.openpilot b/Dockerfile.openpilot index 102da78d7d..acc0fcc784 100644 --- a/Dockerfile.openpilot +++ b/Dockerfile.openpilot @@ -10,7 +10,6 @@ WORKDIR ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH} -COPY ./pyextra ${OPENPILOT_PATH}/pyextra COPY ./third_party ${OPENPILOT_PATH}/third_party COPY ./site_scons ${OPENPILOT_PATH}/site_scons COPY ./laika ${OPENPILOT_PATH}/laika diff --git a/README.md b/README.md index 88b7aeb2bb..4896d9ff72 100755 --- a/README.md +++ b/README.md @@ -103,7 +103,6 @@ Directory Structure ├── opendbc # Files showing how to interpret data from cars ├── panda # Code used to communicate on CAN ├── third_party # External libraries - ├── pyextra # Extra python packages └── system # Generic services ├── camerad # Driver to capture images from the camera sensors ├── clocksd # Broadcasts current time diff --git a/SConstruct b/SConstruct index 54b008004e..b148a9116a 100644 --- a/SConstruct +++ b/SConstruct @@ -71,10 +71,10 @@ if arch == "aarch64" and AGNOS: lenv = { "PATH": os.environ['PATH'], "LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath], - "PYTHONPATH": Dir("#").abspath + ":" + Dir("#pyextra/").abspath, + "PYTHONPATH": Dir("#").abspath, "ACADOS_SOURCE_DIR": Dir("#third_party/acados/include/acados").abspath, - "ACADOS_PYTHON_INTERFACE_PATH": Dir("#pyextra/acados_template").abspath, + "ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath, "TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer" } @@ -422,7 +422,6 @@ SConscript(['common/transformations/SConscript']) SConscript(['selfdrive/modeld/SConscript']) -SConscript(['selfdrive/controls/lib/cluster/SConscript']) SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript']) SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript']) diff --git a/docs/Makefile b/docs/Makefile index d0aa841c4d..dee660f770 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -41,7 +41,7 @@ clean: @echo "Building rst files..." sphinx-apidoc -o "$(DOCSBUILDDIR)" ../ \ - ../xx ../laika_repo ../rednose_repo ../pyextra ../notebooks ../panda_jungle \ + ../xx ../laika_repo ../rednose_repo ../notebooks ../panda_jungle \ ../third_party \ ../panda/examples \ ../scripts \ diff --git a/docs/docker/Dockerfile b/docs/docker/Dockerfile index 0d5883f566..a1cdbbeaf0 100644 --- a/docs/docker/Dockerfile +++ b/docs/docker/Dockerfile @@ -11,7 +11,6 @@ WORKDIR ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH} -COPY ./pyextra ${OPENPILOT_PATH}/pyextra COPY ./third_party ${OPENPILOT_PATH}/third_party COPY ./site_scons ${OPENPILOT_PATH}/site_scons COPY ./laika ${OPENPILOT_PATH}/laika diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 911774a4eb..9fe9b1bd15 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -74,7 +74,7 @@ function launch { # handle pythonpath ln -sfn $(pwd) /data/pythonpath - export PYTHONPATH="$PWD:$PWD/pyextra" + export PYTHONPATH="$PWD" # hardware specific init agnos_init diff --git a/mypy.ini b/mypy.ini index 39b1b007a7..9b6d00d2c4 100644 --- a/mypy.ini +++ b/mypy.ini @@ -2,7 +2,7 @@ python_version = 3.8 plugins = numpy.typing.mypy_plugin files = body, common, docs, scripts, selfdrive, site_scons, system, tools -exclude = ^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/) +exclude = ^(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/) ; third-party packages ignore_missing_imports = True diff --git a/release/files_common b/release/files_common index a06543abbf..d0afa30dea 100644 --- a/release/files_common +++ b/release/files_common @@ -192,8 +192,6 @@ selfdrive/controls/lib/pid.py selfdrive/controls/lib/radar_helpers.py selfdrive/controls/lib/vehicle_model.py -selfdrive/controls/lib/cluster/* - selfdrive/controls/lib/lateral_mpc_lib/.gitignore selfdrive/controls/lib/longitudinal_mpc_lib/.gitignore selfdrive/controls/lib/lateral_mpc_lib/* @@ -328,7 +326,6 @@ system/camerad/SConscript system/camerad/main.cc system/camerad/snapshot/* -system/camerad/include/* system/camerad/cameras/camera_common.h system/camerad/cameras/camera_common.cc system/camerad/cameras/sensor2_i2c.h @@ -384,7 +381,6 @@ selfdrive/modeld/thneed/thneed.h selfdrive/modeld/thneed/thneed_common.cc selfdrive/modeld/thneed/thneed_qcom2.cc selfdrive/modeld/thneed/serialize.cc -selfdrive/modeld/thneed/include/* selfdrive/modeld/runners/snpemodel.cc selfdrive/modeld/runners/snpemodel.h @@ -412,8 +408,11 @@ selfdrive/assets/offroad/* selfdrive/assets/sounds/* selfdrive/assets/training/* +third_party/.gitignore third_party/SConscript +third_party/cluster/* + third_party/linux/** third_party/opencl/** @@ -436,15 +435,13 @@ third_party/snpe/dsp** third_party/acados/x86_64/** third_party/acados/larch64/** third_party/acados/include/** +third_party/acados/acados_template/** third_party/qt5/larch64/bin/** scripts/update_now.sh scripts/stop_updater.sh -pyextra/.gitignore -pyextra/acados_template/** - rednose/.gitignore rednose/** laika/** diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index df1e2a2a1a..868b5a873c 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -44,7 +44,7 @@ generated_files = [ ] + build_files acados_dir = '#third_party/acados' -acados_templates_dir = '#pyextra/acados_template/c_templates_tera' +acados_templates_dir = '#third_party/acados/acados_template/c_templates_tera' source_list = ['lat_mpc.py', f'{acados_dir}/include/acados_c/ocp_nlp_interface.h', @@ -70,8 +70,8 @@ lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_lat", LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e']) # generate cython stuff -acados_ocp_solver_pyx = File("#pyextra/acados_template/acados_ocp_solver_pyx.pyx") -acados_ocp_solver_common = File("#pyextra/acados_template/acados_solver_common.pxd") +acados_ocp_solver_pyx = File("#third_party/acados/acados_template/acados_ocp_solver_pyx.pyx") +acados_ocp_solver_common = File("#third_party/acados/acados_template/acados_solver_common.pxd") libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd') libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c') diff --git a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py index 9607532ace..536f436fce 100755 --- a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py +++ b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py @@ -8,7 +8,7 @@ from common.realtime import sec_since_boot from selfdrive.modeld.constants import T_IDXS if __name__ == '__main__': # generating code - from pyextra.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver + from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver else: from selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython # pylint: disable=no-name-in-module, import-error diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index 5a9e69c297..e5b2360607 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -51,7 +51,7 @@ generated_files = [ ] + build_files acados_dir = '#third_party/acados' -acados_templates_dir = '#pyextra/acados_template/c_templates_tera' +acados_templates_dir = '#third_party/acados/acados_template/c_templates_tera' source_list = ['long_mpc.py', f'{acados_dir}/include/acados_c/ocp_nlp_interface.h', @@ -77,8 +77,8 @@ lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_long", LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e']) # generate cython stuff -acados_ocp_solver_pyx = File("#pyextra/acados_template/acados_ocp_solver_pyx.pyx") -acados_ocp_solver_common = File("#pyextra/acados_template/acados_solver_common.pxd") +acados_ocp_solver_pyx = File("#third_party/acados/acados_template/acados_ocp_solver_pyx.pyx") +acados_ocp_solver_common = File("#third_party/acados/acados_template/acados_solver_common.pxd") libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd') libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c') diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index 79a9ec4f0c..dc27fd27a9 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -9,7 +9,7 @@ from selfdrive.modeld.constants import index_function from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU if __name__ == '__main__': # generating code - from pyextra.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver + from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver else: from selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython # pylint: disable=no-name-in-module, import-error diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 3d958139d6..db87604e98 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -8,9 +8,9 @@ from cereal import car from common.numpy_fast import interp from common.params import Params from common.realtime import Ratekeeper, Priority, config_realtime_process -from selfdrive.controls.lib.cluster.fastcluster_py import cluster_points_centroid from selfdrive.controls.lib.radar_helpers import Cluster, Track, RADAR_TO_CAMERA from system.swaglog import cloudlog +from third_party.cluster.fastcluster_py import cluster_points_centroid class KalmanParams(): diff --git a/selfdrive/controls/tests/test_clustering.py b/selfdrive/controls/tests/test_clustering.py index 290b267029..99c24d5938 100644 --- a/selfdrive/controls/tests/test_clustering.py +++ b/selfdrive/controls/tests/test_clustering.py @@ -7,8 +7,8 @@ from fastcluster import linkage_vector from scipy.cluster import _hierarchy from scipy.spatial.distance import pdist -from selfdrive.controls.lib.cluster.fastcluster_py import hclust, ffi -from selfdrive.controls.lib.cluster.fastcluster_py import cluster_points_centroid +from third_party.cluster.fastcluster_py import hclust, ffi +from third_party.cluster.fastcluster_py import cluster_points_centroid def fcluster(Z, t, criterion='inconsistent', depth=2, R=None, monocrit=None): diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 928507f65b..369c529626 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -23,8 +23,6 @@ from system.version import is_dirty, get_commit, get_version, get_origin, get_sh terms_version, training_version, is_tested_branch -sys.path.append(os.path.join(BASEDIR, "pyextra")) - def manager_init() -> None: # update system time from panda diff --git a/selfdrive/modeld/thneed/thneed.h b/selfdrive/modeld/thneed/thneed.h index 65475ccf7f..6475577734 100644 --- a/selfdrive/modeld/thneed/thneed.h +++ b/selfdrive/modeld/thneed/thneed.h @@ -12,7 +12,7 @@ #include -#include "selfdrive/modeld/thneed/include/msm_kgsl.h" +#include "msm_kgsl.h" using namespace std; diff --git a/system/camerad/SConscript b/system/camerad/SConscript index ddc763b53d..3ecc3f6d72 100644 --- a/system/camerad/SConscript +++ b/system/camerad/SConscript @@ -2,17 +2,13 @@ Import('env', 'arch', 'cereal', 'messaging', 'common', 'gpucommon', 'visionipc') libs = ['m', 'pthread', common, 'jpeg', 'OpenCL', 'yuv', cereal, messaging, 'zmq', 'capnp', 'kj', visionipc, gpucommon, 'atomic'] -cenv = env.Clone() -cenv['CPPPATH'].append('include/') - -camera_obj = cenv.Object(['cameras/camera_qcom2.cc', 'cameras/camera_common.cc', 'cameras/camera_util.cc']) -cenv.Program('camerad', [ +camera_obj = env.Object(['cameras/camera_qcom2.cc', 'cameras/camera_common.cc', 'cameras/camera_util.cc']) +env.Program('camerad', [ 'main.cc', camera_obj, ], LIBS=libs) if GetOption("test") and arch == "x86_64": - cenv.Program('test/ae_gray_test', [ - 'test/ae_gray_test.cc', - camera_obj, - ], LIBS=libs) + env.Program('test/ae_gray_test', + ['test/ae_gray_test.cc', camera_obj], + LIBS=libs) diff --git a/pyextra/.gitignore b/third_party/.gitignore similarity index 100% rename from pyextra/.gitignore rename to third_party/.gitignore diff --git a/third_party/SConscript b/third_party/SConscript index e5bbfaa07a..e8d1789ee0 100644 --- a/third_party/SConscript +++ b/third_party/SConscript @@ -4,3 +4,5 @@ env.Library('json11', ['json11/json11.cpp'], CCFLAGS=env['CCFLAGS'] + ['-Wno-unq env.Append(CPPPATH=[Dir('json11')]) env.Library('kaitai', ['kaitai/kaitaistream.cpp'], CPPDEFINES=['KS_STR_ENCODING_NONE']) + +SConscript(['cluster/SConscript']) diff --git a/pyextra/acados_template/.gitignore b/third_party/acados/acados_template/.gitignore similarity index 100% rename from pyextra/acados_template/.gitignore rename to third_party/acados/acados_template/.gitignore diff --git a/pyextra/acados_template/__init__.py b/third_party/acados/acados_template/__init__.py similarity index 100% rename from pyextra/acados_template/__init__.py rename to third_party/acados/acados_template/__init__.py diff --git a/pyextra/acados_template/acados_layout.json b/third_party/acados/acados_template/acados_layout.json similarity index 100% rename from pyextra/acados_template/acados_layout.json rename to third_party/acados/acados_template/acados_layout.json diff --git a/pyextra/acados_template/acados_model.py b/third_party/acados/acados_template/acados_model.py similarity index 100% rename from pyextra/acados_template/acados_model.py rename to third_party/acados/acados_template/acados_model.py diff --git a/pyextra/acados_template/acados_ocp.py b/third_party/acados/acados_template/acados_ocp.py similarity index 100% rename from pyextra/acados_template/acados_ocp.py rename to third_party/acados/acados_template/acados_ocp.py diff --git a/pyextra/acados_template/acados_ocp_solver.py b/third_party/acados/acados_template/acados_ocp_solver.py similarity index 100% rename from pyextra/acados_template/acados_ocp_solver.py rename to third_party/acados/acados_template/acados_ocp_solver.py diff --git a/pyextra/acados_template/acados_ocp_solver_pyx.pyx b/third_party/acados/acados_template/acados_ocp_solver_pyx.pyx similarity index 100% rename from pyextra/acados_template/acados_ocp_solver_pyx.pyx rename to third_party/acados/acados_template/acados_ocp_solver_pyx.pyx diff --git a/pyextra/acados_template/acados_sim.py b/third_party/acados/acados_template/acados_sim.py similarity index 100% rename from pyextra/acados_template/acados_sim.py rename to third_party/acados/acados_template/acados_sim.py diff --git a/pyextra/acados_template/acados_sim_layout.json b/third_party/acados/acados_template/acados_sim_layout.json similarity index 100% rename from pyextra/acados_template/acados_sim_layout.json rename to third_party/acados/acados_template/acados_sim_layout.json diff --git a/pyextra/acados_template/acados_sim_solver.py b/third_party/acados/acados_template/acados_sim_solver.py similarity index 100% rename from pyextra/acados_template/acados_sim_solver.py rename to third_party/acados/acados_template/acados_sim_solver.py diff --git a/pyextra/acados_template/acados_solver_common.pxd b/third_party/acados/acados_template/acados_solver_common.pxd similarity index 100% rename from pyextra/acados_template/acados_solver_common.pxd rename to third_party/acados/acados_template/acados_solver_common.pxd diff --git a/pyextra/acados_template/builders.py b/third_party/acados/acados_template/builders.py similarity index 100% rename from pyextra/acados_template/builders.py rename to third_party/acados/acados_template/builders.py diff --git a/pyextra/acados_template/c_templates_tera/CMakeLists.in.txt b/third_party/acados/acados_template/c_templates_tera/CMakeLists.in.txt similarity index 100% rename from pyextra/acados_template/c_templates_tera/CMakeLists.in.txt rename to third_party/acados/acados_template/c_templates_tera/CMakeLists.in.txt diff --git a/pyextra/acados_template/c_templates_tera/CPPLINT.cfg b/third_party/acados/acados_template/c_templates_tera/CPPLINT.cfg similarity index 100% rename from pyextra/acados_template/c_templates_tera/CPPLINT.cfg rename to third_party/acados/acados_template/c_templates_tera/CPPLINT.cfg diff --git a/pyextra/acados_template/c_templates_tera/Makefile.in b/third_party/acados/acados_template/c_templates_tera/Makefile.in similarity index 100% rename from pyextra/acados_template/c_templates_tera/Makefile.in rename to third_party/acados/acados_template/c_templates_tera/Makefile.in diff --git a/pyextra/acados_template/c_templates_tera/acados_mex_create.in.c b/third_party/acados/acados_template/c_templates_tera/acados_mex_create.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_mex_create.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_mex_create.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_mex_free.in.c b/third_party/acados/acados_template/c_templates_tera/acados_mex_free.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_mex_free.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_mex_free.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_mex_set.in.c b/third_party/acados/acados_template/c_templates_tera/acados_mex_set.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_mex_set.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_mex_set.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_mex_solve.in.c b/third_party/acados/acados_template/c_templates_tera/acados_mex_solve.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_mex_solve.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_mex_solve.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_sim_solver.in.c b/third_party/acados/acados_template/c_templates_tera/acados_sim_solver.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_sim_solver.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_sim_solver.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_sim_solver.in.h b/third_party/acados/acados_template/c_templates_tera/acados_sim_solver.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_sim_solver.in.h rename to third_party/acados/acados_template/c_templates_tera/acados_sim_solver.in.h diff --git a/pyextra/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c b/third_party/acados/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_solver.in.c b/third_party/acados/acados_template/c_templates_tera/acados_solver.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_solver.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_solver.in.c diff --git a/pyextra/acados_template/c_templates_tera/acados_solver.in.h b/third_party/acados/acados_template/c_templates_tera/acados_solver.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_solver.in.h rename to third_party/acados/acados_template/c_templates_tera/acados_solver.in.h diff --git a/pyextra/acados_template/c_templates_tera/acados_solver.in.pxd b/third_party/acados/acados_template/c_templates_tera/acados_solver.in.pxd similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_solver.in.pxd rename to third_party/acados/acados_template/c_templates_tera/acados_solver.in.pxd diff --git a/pyextra/acados_template/c_templates_tera/acados_solver_sfun.in.c b/third_party/acados/acados_template/c_templates_tera/acados_solver_sfun.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/acados_solver_sfun.in.c rename to third_party/acados/acados_template/c_templates_tera/acados_solver_sfun.in.c diff --git a/pyextra/acados_template/c_templates_tera/cost_y_0_fun.in.h b/third_party/acados/acados_template/c_templates_tera/cost_y_0_fun.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/cost_y_0_fun.in.h rename to third_party/acados/acados_template/c_templates_tera/cost_y_0_fun.in.h diff --git a/pyextra/acados_template/c_templates_tera/cost_y_e_fun.in.h b/third_party/acados/acados_template/c_templates_tera/cost_y_e_fun.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/cost_y_e_fun.in.h rename to third_party/acados/acados_template/c_templates_tera/cost_y_e_fun.in.h diff --git a/pyextra/acados_template/c_templates_tera/cost_y_fun.in.h b/third_party/acados/acados_template/c_templates_tera/cost_y_fun.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/cost_y_fun.in.h rename to third_party/acados/acados_template/c_templates_tera/cost_y_fun.in.h diff --git a/pyextra/acados_template/c_templates_tera/external_cost.in.h b/third_party/acados/acados_template/c_templates_tera/external_cost.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/external_cost.in.h rename to third_party/acados/acados_template/c_templates_tera/external_cost.in.h diff --git a/pyextra/acados_template/c_templates_tera/external_cost_0.in.h b/third_party/acados/acados_template/c_templates_tera/external_cost_0.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/external_cost_0.in.h rename to third_party/acados/acados_template/c_templates_tera/external_cost_0.in.h diff --git a/pyextra/acados_template/c_templates_tera/external_cost_e.in.h b/third_party/acados/acados_template/c_templates_tera/external_cost_e.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/external_cost_e.in.h rename to third_party/acados/acados_template/c_templates_tera/external_cost_e.in.h diff --git a/pyextra/acados_template/c_templates_tera/h_constraint.in.h b/third_party/acados/acados_template/c_templates_tera/h_constraint.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/h_constraint.in.h rename to third_party/acados/acados_template/c_templates_tera/h_constraint.in.h diff --git a/pyextra/acados_template/c_templates_tera/h_e_constraint.in.h b/third_party/acados/acados_template/c_templates_tera/h_e_constraint.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/h_e_constraint.in.h rename to third_party/acados/acados_template/c_templates_tera/h_e_constraint.in.h diff --git a/pyextra/acados_template/c_templates_tera/main.in.c b/third_party/acados/acados_template/c_templates_tera/main.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/main.in.c rename to third_party/acados/acados_template/c_templates_tera/main.in.c diff --git a/pyextra/acados_template/c_templates_tera/main_mex.in.c b/third_party/acados/acados_template/c_templates_tera/main_mex.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/main_mex.in.c rename to third_party/acados/acados_template/c_templates_tera/main_mex.in.c diff --git a/pyextra/acados_template/c_templates_tera/main_sim.in.c b/third_party/acados/acados_template/c_templates_tera/main_sim.in.c similarity index 100% rename from pyextra/acados_template/c_templates_tera/main_sim.in.c rename to third_party/acados/acados_template/c_templates_tera/main_sim.in.c diff --git a/pyextra/acados_template/c_templates_tera/make_main_mex.in.m b/third_party/acados/acados_template/c_templates_tera/make_main_mex.in.m similarity index 100% rename from pyextra/acados_template/c_templates_tera/make_main_mex.in.m rename to third_party/acados/acados_template/c_templates_tera/make_main_mex.in.m diff --git a/pyextra/acados_template/c_templates_tera/make_mex.in.m b/third_party/acados/acados_template/c_templates_tera/make_mex.in.m similarity index 100% rename from pyextra/acados_template/c_templates_tera/make_mex.in.m rename to third_party/acados/acados_template/c_templates_tera/make_mex.in.m diff --git a/pyextra/acados_template/c_templates_tera/make_sfun.in.m b/third_party/acados/acados_template/c_templates_tera/make_sfun.in.m similarity index 100% rename from pyextra/acados_template/c_templates_tera/make_sfun.in.m rename to third_party/acados/acados_template/c_templates_tera/make_sfun.in.m diff --git a/pyextra/acados_template/c_templates_tera/make_sfun_sim.in.m b/third_party/acados/acados_template/c_templates_tera/make_sfun_sim.in.m similarity index 100% rename from pyextra/acados_template/c_templates_tera/make_sfun_sim.in.m rename to third_party/acados/acados_template/c_templates_tera/make_sfun_sim.in.m diff --git a/pyextra/acados_template/c_templates_tera/mex_solver.in.m b/third_party/acados/acados_template/c_templates_tera/mex_solver.in.m similarity index 100% rename from pyextra/acados_template/c_templates_tera/mex_solver.in.m rename to third_party/acados/acados_template/c_templates_tera/mex_solver.in.m diff --git a/pyextra/acados_template/c_templates_tera/model.in.h b/third_party/acados/acados_template/c_templates_tera/model.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/model.in.h rename to third_party/acados/acados_template/c_templates_tera/model.in.h diff --git a/pyextra/acados_template/c_templates_tera/phi_constraint.in.h b/third_party/acados/acados_template/c_templates_tera/phi_constraint.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/phi_constraint.in.h rename to third_party/acados/acados_template/c_templates_tera/phi_constraint.in.h diff --git a/pyextra/acados_template/c_templates_tera/phi_e_constraint.in.h b/third_party/acados/acados_template/c_templates_tera/phi_e_constraint.in.h similarity index 100% rename from pyextra/acados_template/c_templates_tera/phi_e_constraint.in.h rename to third_party/acados/acados_template/c_templates_tera/phi_e_constraint.in.h diff --git a/pyextra/acados_template/generate_c_code_constraint.py b/third_party/acados/acados_template/generate_c_code_constraint.py similarity index 100% rename from pyextra/acados_template/generate_c_code_constraint.py rename to third_party/acados/acados_template/generate_c_code_constraint.py diff --git a/pyextra/acados_template/generate_c_code_discrete_dynamics.py b/third_party/acados/acados_template/generate_c_code_discrete_dynamics.py similarity index 100% rename from pyextra/acados_template/generate_c_code_discrete_dynamics.py rename to third_party/acados/acados_template/generate_c_code_discrete_dynamics.py diff --git a/pyextra/acados_template/generate_c_code_explicit_ode.py b/third_party/acados/acados_template/generate_c_code_explicit_ode.py similarity index 100% rename from pyextra/acados_template/generate_c_code_explicit_ode.py rename to third_party/acados/acados_template/generate_c_code_explicit_ode.py diff --git a/pyextra/acados_template/generate_c_code_external_cost.py b/third_party/acados/acados_template/generate_c_code_external_cost.py similarity index 100% rename from pyextra/acados_template/generate_c_code_external_cost.py rename to third_party/acados/acados_template/generate_c_code_external_cost.py diff --git a/pyextra/acados_template/generate_c_code_gnsf.py b/third_party/acados/acados_template/generate_c_code_gnsf.py similarity index 100% rename from pyextra/acados_template/generate_c_code_gnsf.py rename to third_party/acados/acados_template/generate_c_code_gnsf.py diff --git a/pyextra/acados_template/generate_c_code_implicit_ode.py b/third_party/acados/acados_template/generate_c_code_implicit_ode.py similarity index 100% rename from pyextra/acados_template/generate_c_code_implicit_ode.py rename to third_party/acados/acados_template/generate_c_code_implicit_ode.py diff --git a/pyextra/acados_template/generate_c_code_nls_cost.py b/third_party/acados/acados_template/generate_c_code_nls_cost.py similarity index 100% rename from pyextra/acados_template/generate_c_code_nls_cost.py rename to third_party/acados/acados_template/generate_c_code_nls_cost.py diff --git a/pyextra/acados_template/simulink_default_opts.json b/third_party/acados/acados_template/simulink_default_opts.json similarity index 100% rename from pyextra/acados_template/simulink_default_opts.json rename to third_party/acados/acados_template/simulink_default_opts.json diff --git a/pyextra/acados_template/utils.py b/third_party/acados/acados_template/utils.py similarity index 100% rename from pyextra/acados_template/utils.py rename to third_party/acados/acados_template/utils.py diff --git a/third_party/acados/build.sh b/third_party/acados/build.sh index 0481e8159b..9b18b2b67d 100755 --- a/third_party/acados/build.sh +++ b/third_party/acados/build.sh @@ -43,11 +43,10 @@ mkdir -p $INSTALL_DIR rm $DIR/acados_repo/lib/*.json -rm -rf $DIR/include +rm -rf $DIR/include $DIR/acados_template cp -r $DIR/acados_repo/include $DIR cp -r $DIR/acados_repo/lib $INSTALL_DIR -rm -rf $DIR/../../pyextra/acados_template -cp -r $DIR/acados_repo/interfaces/acados_template/acados_template $DIR/../../pyextra +cp -r $DIR/acados_repo/interfaces/acados_template/acados_template $DIR/ #pip3 install -e $DIR/acados/interfaces/acados_template # build tera diff --git a/selfdrive/controls/lib/cluster/.gitignore b/third_party/cluster/.gitignore similarity index 100% rename from selfdrive/controls/lib/cluster/.gitignore rename to third_party/cluster/.gitignore diff --git a/selfdrive/controls/lib/cluster/LICENSE b/third_party/cluster/LICENSE similarity index 100% rename from selfdrive/controls/lib/cluster/LICENSE rename to third_party/cluster/LICENSE diff --git a/selfdrive/controls/lib/cluster/README b/third_party/cluster/README similarity index 100% rename from selfdrive/controls/lib/cluster/README rename to third_party/cluster/README diff --git a/selfdrive/controls/lib/cluster/SConscript b/third_party/cluster/SConscript similarity index 100% rename from selfdrive/controls/lib/cluster/SConscript rename to third_party/cluster/SConscript diff --git a/selfdrive/controls/lib/cluster/__init__.py b/third_party/cluster/__init__.py similarity index 100% rename from selfdrive/controls/lib/cluster/__init__.py rename to third_party/cluster/__init__.py diff --git a/selfdrive/controls/lib/cluster/fastcluster.cpp b/third_party/cluster/fastcluster.cpp similarity index 100% rename from selfdrive/controls/lib/cluster/fastcluster.cpp rename to third_party/cluster/fastcluster.cpp diff --git a/selfdrive/controls/lib/cluster/fastcluster.h b/third_party/cluster/fastcluster.h similarity index 100% rename from selfdrive/controls/lib/cluster/fastcluster.h rename to third_party/cluster/fastcluster.h diff --git a/selfdrive/controls/lib/cluster/fastcluster_R_dm.cpp b/third_party/cluster/fastcluster_R_dm.cpp similarity index 100% rename from selfdrive/controls/lib/cluster/fastcluster_R_dm.cpp rename to third_party/cluster/fastcluster_R_dm.cpp diff --git a/selfdrive/controls/lib/cluster/fastcluster_dm.cpp b/third_party/cluster/fastcluster_dm.cpp similarity index 100% rename from selfdrive/controls/lib/cluster/fastcluster_dm.cpp rename to third_party/cluster/fastcluster_dm.cpp diff --git a/selfdrive/controls/lib/cluster/fastcluster_py.py b/third_party/cluster/fastcluster_py.py similarity index 100% rename from selfdrive/controls/lib/cluster/fastcluster_py.py rename to third_party/cluster/fastcluster_py.py diff --git a/selfdrive/controls/lib/cluster/test.cpp b/third_party/cluster/test.cpp similarity index 100% rename from selfdrive/controls/lib/cluster/test.cpp rename to third_party/cluster/test.cpp diff --git a/system/camerad/include/media/cam_cpas.h b/third_party/linux/include/media/cam_cpas.h similarity index 100% rename from system/camerad/include/media/cam_cpas.h rename to third_party/linux/include/media/cam_cpas.h diff --git a/system/camerad/include/media/cam_defs.h b/third_party/linux/include/media/cam_defs.h similarity index 100% rename from system/camerad/include/media/cam_defs.h rename to third_party/linux/include/media/cam_defs.h diff --git a/system/camerad/include/media/cam_fd.h b/third_party/linux/include/media/cam_fd.h similarity index 100% rename from system/camerad/include/media/cam_fd.h rename to third_party/linux/include/media/cam_fd.h diff --git a/system/camerad/include/media/cam_icp.h b/third_party/linux/include/media/cam_icp.h similarity index 100% rename from system/camerad/include/media/cam_icp.h rename to third_party/linux/include/media/cam_icp.h diff --git a/system/camerad/include/media/cam_isp.h b/third_party/linux/include/media/cam_isp.h similarity index 100% rename from system/camerad/include/media/cam_isp.h rename to third_party/linux/include/media/cam_isp.h diff --git a/system/camerad/include/media/cam_isp_ife.h b/third_party/linux/include/media/cam_isp_ife.h similarity index 100% rename from system/camerad/include/media/cam_isp_ife.h rename to third_party/linux/include/media/cam_isp_ife.h diff --git a/system/camerad/include/media/cam_isp_vfe.h b/third_party/linux/include/media/cam_isp_vfe.h similarity index 100% rename from system/camerad/include/media/cam_isp_vfe.h rename to third_party/linux/include/media/cam_isp_vfe.h diff --git a/system/camerad/include/media/cam_jpeg.h b/third_party/linux/include/media/cam_jpeg.h similarity index 100% rename from system/camerad/include/media/cam_jpeg.h rename to third_party/linux/include/media/cam_jpeg.h diff --git a/system/camerad/include/media/cam_lrme.h b/third_party/linux/include/media/cam_lrme.h similarity index 100% rename from system/camerad/include/media/cam_lrme.h rename to third_party/linux/include/media/cam_lrme.h diff --git a/system/camerad/include/media/cam_req_mgr.h b/third_party/linux/include/media/cam_req_mgr.h similarity index 100% rename from system/camerad/include/media/cam_req_mgr.h rename to third_party/linux/include/media/cam_req_mgr.h diff --git a/system/camerad/include/media/cam_sensor.h b/third_party/linux/include/media/cam_sensor.h similarity index 100% rename from system/camerad/include/media/cam_sensor.h rename to third_party/linux/include/media/cam_sensor.h diff --git a/system/camerad/include/media/cam_sensor_cmn_header.h b/third_party/linux/include/media/cam_sensor_cmn_header.h similarity index 100% rename from system/camerad/include/media/cam_sensor_cmn_header.h rename to third_party/linux/include/media/cam_sensor_cmn_header.h diff --git a/system/camerad/include/media/cam_sync.h b/third_party/linux/include/media/cam_sync.h similarity index 100% rename from system/camerad/include/media/cam_sync.h rename to third_party/linux/include/media/cam_sync.h diff --git a/system/camerad/include/msm_cam_sensor.h b/third_party/linux/include/msm_cam_sensor.h similarity index 100% rename from system/camerad/include/msm_cam_sensor.h rename to third_party/linux/include/msm_cam_sensor.h diff --git a/system/camerad/include/msm_camsensor_sdk.h b/third_party/linux/include/msm_camsensor_sdk.h similarity index 100% rename from system/camerad/include/msm_camsensor_sdk.h rename to third_party/linux/include/msm_camsensor_sdk.h diff --git a/selfdrive/modeld/thneed/include/msm_kgsl.h b/third_party/linux/include/msm_kgsl.h similarity index 100% rename from selfdrive/modeld/thneed/include/msm_kgsl.h rename to third_party/linux/include/msm_kgsl.h diff --git a/system/camerad/include/msmb_camera.h b/third_party/linux/include/msmb_camera.h similarity index 100% rename from system/camerad/include/msmb_camera.h rename to third_party/linux/include/msmb_camera.h diff --git a/system/camerad/include/msmb_isp.h b/third_party/linux/include/msmb_isp.h similarity index 100% rename from system/camerad/include/msmb_isp.h rename to third_party/linux/include/msmb_isp.h diff --git a/system/camerad/include/msmb_ispif.h b/third_party/linux/include/msmb_ispif.h similarity index 100% rename from system/camerad/include/msmb_ispif.h rename to third_party/linux/include/msmb_ispif.h diff --git a/tools/gpstest/fuzzy_testing.py b/tools/gpstest/fuzzy_testing.py index df6691c558..bd204e7ae7 100755 --- a/tools/gpstest/fuzzy_testing.py +++ b/tools/gpstest/fuzzy_testing.py @@ -69,7 +69,7 @@ rc_p: Any = None def exec_remote_checker(lat, lon, duration, ip_addr): global rc_p # TODO: good enough for testing - remote_cmd = "export PYTHONPATH=/data/pythonpath:/data/pythonpath/pyextra && " + remote_cmd = "export PYTHONPATH=/data/pythonpath && " remote_cmd += "cd /data/openpilot && " remote_cmd += f"timeout {duration} /usr/local/pyenv/shims/python tools/gpstest/remote_checker.py " remote_cmd += f"{lat} {lon}" diff --git a/tools/sim/Dockerfile.sim b/tools/sim/Dockerfile.sim index 3692d48e0f..be16f8c863 100644 --- a/tools/sim/Dockerfile.sim +++ b/tools/sim/Dockerfile.sim @@ -15,7 +15,6 @@ RUN mkdir -p $HOME/openpilot COPY SConstruct $HOME/openpilot/ COPY ./third_party $HOME/openpilot/third_party -COPY ./pyextra $HOME/openpilot/pyextra COPY ./site_scons $HOME/openpilot/site_scons COPY ./rednose $HOME/openpilot/rednose COPY ./laika $HOME/openpilot/laika From 3d44b6b3ac6d1f207e01d4cbf225bd929255ca1e Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 1 Jan 2023 19:15:44 -0800 Subject: [PATCH 0567/1179] alt amp config (#26858) * alt amp config * fix * not executable * comment * consistency Co-authored-by: Comma Device --- system/hardware/tici/amplifier.py | 52 ++++++++++++++++++++++++------- system/hardware/tici/hardware.py | 14 +++++++-- 2 files changed, 53 insertions(+), 13 deletions(-) mode change 100755 => 100644 system/hardware/tici/amplifier.py diff --git a/system/hardware/tici/amplifier.py b/system/hardware/tici/amplifier.py old mode 100755 new mode 100644 index a8b2798630..8233834d11 --- a/system/hardware/tici/amplifier.py +++ b/system/hardware/tici/amplifier.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python from smbus2 import SMBus from collections import namedtuple @@ -63,11 +62,43 @@ BASE_CONFIG = [ AmpConfig("Zero-crossing detection disabled", 0b0, 0x49, 5, 0b00100000), ] -BASE_CONFIG += configs_from_eq_params(0x84, EQParams(0x274F, 0xC0FF, 0x3BF9, 0x0B3C, 0x1656)) -BASE_CONFIG += configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF)) -BASE_CONFIG += configs_from_eq_params(0x98, EQParams(0x0F75, 0xCBE5, 0x0ED2, 0x2528, 0x3E42)) -BASE_CONFIG += configs_from_eq_params(0xA2, EQParams(0x091F, 0x3D4C, 0xCE11, 0x1266, 0x2807)) -BASE_CONFIG += configs_from_eq_params(0xAC, EQParams(0x0A9E, 0x3F20, 0xE573, 0x0A8B, 0x3A3B)) +CONFIGS = { + "tici": [ + *configs_from_eq_params(0x84, EQParams(0x274F, 0xC0FF, 0x3BF9, 0x0B3C, 0x1656)), + *configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF)), + *configs_from_eq_params(0x98, EQParams(0x0F75, 0xCBE5, 0x0ED2, 0x2528, 0x3E42)), + *configs_from_eq_params(0xA2, EQParams(0x091F, 0x3D4C, 0xCE11, 0x1266, 0x2807)), + *configs_from_eq_params(0xAC, EQParams(0x0A9E, 0x3F20, 0xE573, 0x0A8B, 0x3A3B)), + ], + "tizi": [ + AmpConfig("Left speaker output from left DAC", 0b1, 0x2B, 0, 0b11111111), + AmpConfig("Left Speaker Mixer Gain", 0b00, 0x2D, 0, 0b00000011), + AmpConfig("Left speaker output volume", 0x1F, 0x3D, 0, 0b00011111), + AmpConfig("Right speaker output volume", 0x1F, 0x3E, 0, 0b00011111), + AmpConfig("DAI1 attenuation (DV1)", 0x4, 0x2F, 0, 0b00001111), + AmpConfig("DAI2 attenuation (DV2)", 0x4, 0x31, 0, 0b00001111), + AmpConfig("DAI2: DC blocking", 0b0, 0x20, 0, 0b00000001), + AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000), + AmpConfig("DAI2 EQ attenuation", 0x2, 0x32, 0, 0b00001111), + AmpConfig("Excursion limiter upper corner freq", 0b001, 0x41, 4, 0b01110000), + AmpConfig("Excursion limiter threshold", 0b100, 0x42, 0, 0b00001111), + AmpConfig("Distortion limit (THDCLP)", 0x0, 0x46, 4, 0b11110000), + AmpConfig("Distortion limiter release time constant", 0b1, 0x46, 0, 0b00000001), + AmpConfig("Left DAC input mixer: DAI1 left", 0b0, 0x22, 7, 0b10000000), + AmpConfig("Left DAC input mixer: DAI1 right", 0b0, 0x22, 6, 0b01000000), + AmpConfig("Left DAC input mixer: DAI2 left", 0b1, 0x22, 5, 0b00100000), + AmpConfig("Left DAC input mixer: DAI2 right", 0b0, 0x22, 4, 0b00010000), + AmpConfig("Right DAC input mixer: DAI2 left", 0b0, 0x22, 1, 0b00000010), + AmpConfig("Right DAC input mixer: DAI2 right", 0b1, 0x22, 0, 0b00000001), + AmpConfig("Volume adjustment smoothing disabled", 0b1, 0x49, 6, 0b01000000), + + *configs_from_eq_params(0x84, EQParams(0x3084, 0xC023, 0x3D60, 0x042B, 0x1222)), + *configs_from_eq_params(0x8E, EQParams(0x2FB2, 0xC05C, 0x3BD3, 0x06C5, 0x16BB)), + *configs_from_eq_params(0x98, EQParams(0x21F5, 0xDF73, 0x2DFE, 0x371A, 0x2C80)), + *configs_from_eq_params(0xA2, EQParams(0x2A5A, 0x0AD0, 0x14FA, 0x3F14, 0x3C76)), + *configs_from_eq_params(0xAC, EQParams(0x1577, 0x3FAE, 0xEE60, 0x0664, 0x3D86)), + ], +} class Amplifier: AMP_I2C_BUS = 0 @@ -91,14 +122,13 @@ class Amplifier: def set_global_shutdown(self, amp_disabled): self.set_config(AmpConfig("Global shutdown", 0b0 if amp_disabled else 0b1, 0x51, 7, 0b10000000)) - def initialize_configuration(self): + def initialize_configuration(self, model): self.set_global_shutdown(amp_disabled=True) for config in BASE_CONFIG: self.set_config(config) + for config in CONFIGS[model]: + self.set_config(config) + self.set_global_shutdown(amp_disabled=False) - - -if __name__ == "__main__": - Amplifier(debug=True).initialize_configuration() diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index b5f5e00410..c0fbc66fae 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -85,6 +85,16 @@ class Tici(HardwareBase): def amplifier(self): return Amplifier() + @cached_property + def model(self): + with open("/sys/firmware/devicetree/base/model") as f: + model = f.read().strip('\x00') + model = model.split('comma ')[-1] + # TODO: remove this with AGNOS 7+ + if model.startswith('Qualcomm'): + model = 'tici' + return model + def get_os_version(self): with open("/VERSION") as f: return f.read().strip() @@ -401,7 +411,7 @@ class Tici(HardwareBase): # amplifier, 100mW at idle self.amplifier.set_global_shutdown(amp_disabled=powersave_enabled) if not powersave_enabled: - self.amplifier.initialize_configuration() + self.amplifier.initialize_configuration(self.model) # *** CPU config *** @@ -430,7 +440,7 @@ class Tici(HardwareBase): return 0 def initialize_hardware(self): - self.amplifier.initialize_configuration() + self.amplifier.initialize_configuration(self.model) # Allow thermald to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") From 922bedaf47effb448c056a1844c13ecd7a26a244 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 1 Jan 2023 19:47:02 -0800 Subject: [PATCH 0568/1179] tici: remove hardcoded max brightness (#26859) * tici: remove hardcoded max brightness * fix that one * cleanup Co-authored-by: Comma Device --- system/hardware/tici/hardware.h | 4 +++- system/hardware/tici/hardware.py | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index d388f9c48a..521a257627 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -25,9 +25,11 @@ public: static void reboot() { std::system("sudo reboot"); }; static void poweroff() { std::system("sudo poweroff"); }; static void set_brightness(int percent) { + std::string max = util::read_file("/sys/class/backlight/panel0-backlight/max_brightness"); + std::ofstream brightness_control("/sys/class/backlight/panel0-backlight/brightness"); if (brightness_control.is_open()) { - brightness_control << (percent * (int)(1023/100.)) << "\n"; + brightness_control << (int)(percent * (std::stof(max)/100.)) << "\n"; brightness_control.close(); } }; diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index c0fbc66fae..9c1cc930c1 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -395,15 +395,22 @@ class Tici(HardwareBase): def set_screen_brightness(self, percentage): try: + with open("/sys/class/backlight/panel0-backlight/max_brightness") as f: + max_brightness = float(f.read().strip()) + + val = int(percentage * (max_brightness / 100.)) with open("/sys/class/backlight/panel0-backlight/brightness", "w") as f: - f.write(str(int(percentage * 10.23))) + f.write(str(val)) except Exception: pass def get_screen_brightness(self): try: + with open("/sys/class/backlight/panel0-backlight/max_brightness") as f: + max_brightness = float(f.read().strip()) + with open("/sys/class/backlight/panel0-backlight/brightness") as f: - return int(float(f.read()) / 10.23) + return int(float(f.read()) / (max_brightness / 100.)) except Exception: return 0 From b5a2dfa93ed053b5e1e04f6a3b76735126c1e00f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 3 Jan 2023 03:57:51 +0800 Subject: [PATCH 0569/1179] replay: only keep one init_data in merged events (#26863) don't merge init_data --- tools/replay/replay.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index a01371abe1..998c93b938 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -269,8 +269,12 @@ void Replay::mergeSegments(const SegmentMap::iterator &begin, const SegmentMap:: new_events_->reserve(new_events_size); for (int n : segments_need_merge) { const auto &e = segments_[n]->log->events; - auto middle = new_events_->insert(new_events_->end(), e.begin(), e.end()); - std::inplace_merge(new_events_->begin(), middle, new_events_->end(), Event::lessThan()); + if (e.size() > 0) { + auto insert_from = e.begin(); + if (new_events_->size() > 0 && (*insert_from)->which == cereal::Event::Which::INIT_DATA) ++insert_from; + auto middle = new_events_->insert(new_events_->end(), insert_from, e.end()); + std::inplace_merge(new_events_->begin(), middle, new_events_->end(), Event::lessThan()); + } } updateEvents([&]() { From 88fd2ea84ff7c465a2c2f7de13635f112d604637 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 3 Jan 2023 05:31:08 +0800 Subject: [PATCH 0570/1179] replay: add option --prefix to set OPENPILOT_PREFIX (#26862) --- tools/replay/main.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/replay/main.cc b/tools/replay/main.cc index 8621a9b978..6b624aa1fa 100644 --- a/tools/replay/main.cc +++ b/tools/replay/main.cc @@ -1,6 +1,7 @@ #include #include +#include "common/prefix.h" #include "tools/replay/consoleui.h" #include "tools/replay/replay.h" @@ -27,6 +28,7 @@ int main(int argc, char *argv[]) { parser.addOption({{"s", "start"}, "start from ", "seconds"}); parser.addOption({"demo", "use a demo route instead of providing your own"}); parser.addOption({"data_dir", "local directory with routes", "data_dir"}); + parser.addOption({"prefix", "set OPENPILOT_PREFIX", "prefix"}); for (auto &[name, _, desc] : flags) { parser.addOption({name, desc}); } @@ -47,6 +49,13 @@ int main(int argc, char *argv[]) { replay_flags |= flag; } } + + std::unique_ptr op_prefix; + auto prefix = parser.value("prefix"); + if (!prefix.isEmpty()) { + op_prefix.reset(new OpenpilotPrefix(prefix.toStdString())); + } + Replay *replay = new Replay(route, allow, block, nullptr, replay_flags, parser.value("data_dir"), &app); if (!parser.value("c").isEmpty()) { replay->setSegmentCacheLimit(parser.value("c").toInt()); From 8b4c5631a4c8f259fe7e7db1789556c2b26e0f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 2 Jan 2023 22:25:39 -0800 Subject: [PATCH 0571/1179] Ev6 upper jerk limit (#26868) --- opendbc | 2 +- selfdrive/car/hyundai/hyundaicanfd.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index 4a7ad636ff..d585a9bf29 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 4a7ad636ff806146a93f7ae541e463a7dfa5696d +Subproject commit d585a9bf2908b2c83bf02b567b9e1f5bfc587a01 diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index c492e6a5ff..43c9642342 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -83,6 +83,7 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove "aReqRaw": a_raw, "VSetDis": set_speed, "JerkLowerLimit": jerk if enabled else 1, + "JerkUpperLimit": 3.0, "ACC_ObjDist": 1, "ObjValid": 0, @@ -90,7 +91,6 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove "SET_ME_2": 0x4, "SET_ME_3": 0x3, "SET_ME_TMP_64": 0x64, - "NEW_SIGNAL_10": 4, "DISTANCE_SETTING": 4, } From 2c293bf728f59a36830898e0f0d4111cd6708619 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 4 Jan 2023 12:06:01 -0800 Subject: [PATCH 0572/1179] Hyundai CAN-FD: set request accel when stopping (#26877) Update hyundaicanfd.py --- selfdrive/car/hyundai/hyundaicanfd.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/selfdrive/car/hyundai/hyundaicanfd.py b/selfdrive/car/hyundai/hyundaicanfd.py index 43c9642342..af7239571c 100644 --- a/selfdrive/car/hyundai/hyundaicanfd.py +++ b/selfdrive/car/hyundai/hyundaicanfd.py @@ -72,8 +72,6 @@ def create_acc_control(packer, CP, enabled, accel_last, accel, stopping, gas_ove else: a_raw = accel a_val = clip(accel, accel_last - jn, accel_last + jn) - if stopping: - a_raw = 0 values = { "ACCMode": 0 if not enabled else (2 if gas_override else 1), From b48b2f09b203db3e6bb26c671dd7e9b328207bc4 Mon Sep 17 00:00:00 2001 From: Luckst4r <67570890+Luckst4r@users.noreply.github.com> Date: Wed, 4 Jan 2023 17:17:01 -0600 Subject: [PATCH 0573/1179] Genesis GV70 2023: add missing FW versions (#26876) * Update values.py Fingerprint GV70 * Update selfdrive/car/hyundai/values.py Co-authored-by: Shane Smiskol --- 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 4d3f44d65f..782c3989a7 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1517,9 +1517,11 @@ FW_VERSIONS = { CAR.GENESIS_GV70_1ST_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204', + b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR200 220125', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00JK1_ SCC FHCUP 1.00 1.02 99110-AR000 ', + b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR200 ', ], }, CAR.GENESIS_GV60_EV_1ST_GEN: { From 083bcb6f0271518537ccfc69bdcc20ae50efd600 Mon Sep 17 00:00:00 2001 From: mitchellgoffpc Date: Fri, 6 Jan 2023 12:08:22 -0800 Subject: [PATCH 0574/1179] Added omegaconf to xx dependencies --- poetry.lock | 29 ++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 9ab86329d7..8edfbb868c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -80,6 +80,14 @@ develop = ["imgaug (>=0.4.0)", "pytest"] imgaug = ["imgaug (>=0.4.0)"] tests = ["pytest"] +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +description = "ANTLR 4.9.3 runtime for Python 3.7" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "anyio" version = "3.6.2" @@ -2431,6 +2439,18 @@ rsa = ["cryptography (>=3.0.0)"] signals = ["blinker (>=1.4.0)"] signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] +[[package]] +name = "omegaconf" +version = "2.3.0" +description = "A flexible configuration library" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +antlr4-python3-runtime = ">=4.9.0,<4.10.0" +PyYAML = ">=5.1.0" + [[package]] name = "onnx" version = "1.12.0" @@ -4444,7 +4464,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "2ab9d6aee6cc2c7bb5ba9763a54779ef9535cb752ec0038736a442992a04d459" +content-hash = "3c2597d2199a29ef79dd4d5fbc5e2350d86c82a3fe6716d13b93ebc268053eb9" [metadata.files] adal = [ @@ -4557,6 +4577,9 @@ albumentations = [ {file = "albumentations-1.3.0-py3-none-any.whl", hash = "sha256:294165d87d03bc8323e484927f0a5c1a3c64b0e7b9c32a979582a6c93c363bdf"}, {file = "albumentations-1.3.0.tar.gz", hash = "sha256:be1af36832c8893314f2a5550e8ac19801e04770734c1b70fa3c996b41f37bed"}, ] +antlr4-python3-runtime = [ + {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, +] anyio = [ {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, @@ -6426,6 +6449,10 @@ oauthlib = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, ] +omegaconf = [ + {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, + {file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"}, +] onnx = [ {file = "onnx-1.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bdbd2578424c70836f4d0f9dda16c21868ddb07cc8192f9e8a176908b43d694b"}, {file = "onnx-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213e73610173f6b2e99f99a4b0636f80b379c417312079d603806e48ada4ca8b"}, diff --git a/pyproject.toml b/pyproject.toml index af9fcc6e6e..ed3a821e29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,6 +171,7 @@ torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0 triton = "^1.1.1" Werkzeug = "^2.1.2" zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } +omegaconf = "^2.3.0" [build-system] From 18b011636ef623023e53bd7326d9871c4ce07f97 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Fri, 6 Jan 2023 19:31:24 -0500 Subject: [PATCH 0575/1179] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202019=20?= =?UTF-8?q?=C5=A0koda=20Octavia=20(#26886)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index d1f6bfb02c..24ea0a03ba 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1023,6 +1023,7 @@ FW_VERSIONS = { }, CAR.SKODA_OCTAVIA_MK3: { (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704C906025L \xf1\x896198', b'\xf1\x8704E906016ER\xf1\x895823', b'\xf1\x8704E906027HD\xf1\x893742', b'\xf1\x8704E906027MH\xf1\x894786', @@ -1034,6 +1035,7 @@ FW_VERSIONS = { b'\xf1\x870CW300041L \xf1\x891601', b'\xf1\x870CW300041N \xf1\x891605', b'\xf1\x870CW300043B \xf1\x891601', + b'\xf1\x870CW300043P \xf1\x891605', b'\xf1\x870D9300041C \xf1\x894936', b'\xf1\x870D9300041J \xf1\x894902', b'\xf1\x870D9300041P \xf1\x894507', @@ -1043,6 +1045,7 @@ FW_VERSIONS = { b'\xf1\x873Q0959655AQ\xf1\x890200\xf1\x82\r11120011100010312212113100', b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r11120011100010022212110200', b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\0163221003221002105755331052100', + b'\xf1\x873Q0959655CM\xf1\x890720\xf1\x82\x0e3221003221002105755331052100', b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e3221003221002105755331052100', b'\xf1\x875QD959655 \xf1\x890388\xf1\x82\x111101000011110006110411111111119111', ], From b994b93b164bb9dc2a8689dff0f271d2d68ced55 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Fri, 6 Jan 2023 17:46:21 -0700 Subject: [PATCH 0576/1179] GM: check radarOffCan in radar_interface (#26885) Remove hardcoded vehicle list, replace with radarOffCan check --- selfdrive/car/gm/radar_interface.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py index 6904e6f899..5cb211812d 100755 --- a/selfdrive/car/gm/radar_interface.py +++ b/selfdrive/car/gm/radar_interface.py @@ -3,7 +3,7 @@ import math from cereal import car from common.conversions import Conversions as CV from opendbc.can.parser import CANParser -from selfdrive.car.gm.values import DBC, CAR, CanBus +from selfdrive.car.gm.values import DBC, CanBus from selfdrive.car.interfaces import RadarInterfaceBase RADAR_HEADER_MSG = 1120 @@ -16,9 +16,6 @@ LAST_RADAR_MSG = RADAR_HEADER_MSG + NUM_SLOTS def create_radar_can_parser(car_fingerprint): - if car_fingerprint not in (CAR.VOLT, CAR.MALIBU, CAR.HOLDEN_ASTRA, CAR.ACADIA, CAR.CADILLAC_ATS, CAR.ESCALADE_ESV): - return None - # C1A-ARS3-A by Continental radar_targets = list(range(SLOT_1_MSG, SLOT_1_MSG + NUM_SLOTS)) signals = list(zip(['FLRRNumValidTargets', @@ -34,11 +31,12 @@ def create_radar_can_parser(car_fingerprint): return CANParser(DBC[car_fingerprint]['radar'], signals, checks, CanBus.OBSTACLE) + class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) - self.rcp = create_radar_can_parser(CP.carFingerprint) + self.rcp = None if CP.radarOffCan else create_radar_can_parser(CP.carFingerprint) self.trigger_msg = LAST_RADAR_MSG self.updated_messages = set() From 4145bc837948f530eb17c3f93728a1347e4eceb3 Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:49:27 -0800 Subject: [PATCH 0577/1179] Hyundai: add FW versions for Sonata 2023 (#26880) * Update Hyundai Sonata year to 2023 * update docs * update docs * update docs * Update values.py * and engine Co-authored-by: Laptop Researcher Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index f3667c4cea..d53ea39893 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -82,7 +82,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Sonata 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| |Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 782c3989a7..dd7f347863 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -160,7 +160,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-22", "All", "https://youtu.be/VnHzSTygTS4", harness=Harness.hyundai_l), CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022", "All", harness=Harness.hyundai_l), CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022", "All", harness=Harness.hyundai_l), - CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-22", "All", "https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a), + CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", "https://www.youtube.com/watch?v=ix63r9kE3Fw", harness=Harness.hyundai_a), CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", harness=Harness.hyundai_e), CAR.TUCSON: [ HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_l), @@ -512,6 +512,7 @@ FW_VERSIONS = { b'HM6M1_0a0_G20', b'HM6M2_0a0_BD0', b'\xf1\x8739110-2S278\xf1\x82DNDVD5GMCCXXXL5B', + b'\xf1\x8739110-2S041\xf1\x81HM6M1_0a0_M00', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', # modified firmware @@ -529,6 +530,7 @@ FW_VERSIONS = { b'\xf1\x8756310L0210\x00\xf1\x00DN8 MDPS C 1.00 1.01 56310L0210\x00 4DNAC101', b'\xf1\x8757700-L0000\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP100', b'\xf1\x00DN8 MDPS R 1.00 1.00 57700-L0000 4DNAP101', + b'\xf1\x00DN8 MDPS C 1.00 1.01 56310-L0210 4DNAC102', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.02 99211-L1000 190422', @@ -538,6 +540,7 @@ FW_VERSIONS = { b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.03 99211-L0000 210603', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.05 99211-L1000 201109', b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.06 99211-L1000 210325', + b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.07 99211-L1000 211223', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', @@ -548,6 +551,7 @@ FW_VERSIONS = { b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x00HT6WA250BLHT6WA910A1SDN8G25NB1\x00\x00\x00\x00\x00\x00\x96\xa1\xf1\x92', b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB2\x00\x00\x00\x00\x00\x00\x08\xc9O:', + b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB4\x00\x00\x00\x00\x00\x00g!l[', b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', From b74f2d102daa6acea69d0c673dbb0172f31897f3 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 6 Jan 2023 19:54:56 -0500 Subject: [PATCH 0578/1179] Hyundai: Add FW Versions for Tucson 2023 (#26887) --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index dd7f347863..1adf78aa84 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1477,6 +1477,7 @@ FW_VERSIONS = { CAR.TUCSON_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T', + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW010 14X', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ', From 0d85a2c373c3e139237c6bc969be79312a99bd63 Mon Sep 17 00:00:00 2001 From: Rafael Pinilla <80814874+Rafale83@users.noreply.github.com> Date: Sat, 7 Jan 2023 18:40:52 +0100 Subject: [PATCH 0579/1179] European Lexus UX250h 2019: add engine FW (#26895) * Update values.py Added mention to all 2019 Lexus UX250h Fw in CORROLLAH section * Update values.py Syntax error in REMs --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 64a0bed0b2..e945130e90 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -831,6 +831,7 @@ FW_VERSIONS = { b'\x01896630ZJ1000\x00\x00\x00\x00', b'\x01896630ZU8000\x00\x00\x00\x00', b'\x01896637621000\x00\x00\x00\x00', + b'\x01896637623000\x00\x00\x00\x00', b'\x01896637624000\x00\x00\x00\x00', b'\x01896637626000\x00\x00\x00\x00', b'\x01896637639000\x00\x00\x00\x00', From bf34110572cb801564346ffb2f234cd152a7b100 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 7 Jan 2023 11:05:56 -0800 Subject: [PATCH 0580/1179] docs: update CAN FD footnote (#26896) * docs: update CAN FD footnote * touch up --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index d53ea39893..930b52c8a2 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -236,7 +236,7 @@ A supported vehicle is one that just works when you install a comma three. All s 2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-5Requires a red panda, additional harness box, additional OBD-C cable, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle.
+5Requires a red panda for this CAN FD. All the hardware needed is sold in the CAN FD kit.
6openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
7Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
8Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1adf78aa84..dc19c5511d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -123,9 +123,9 @@ class CAR: class Footnote(Enum): CANFD = CarFootnote( - "Requires a red panda, additional harness box, " + - "additional OBD-C cable, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle.", - Column.MODEL, shop_footnote=True) + "Requires a red panda for this CAN FD. " + + "All the hardware needed is sold in the CAN FD kit.", + Column.MODEL, docs_only=True) @dataclass From 2c7df6efc87f4f16aa0801ed40bc0e2542578031 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 8 Jan 2023 03:07:30 +0800 Subject: [PATCH 0581/1179] replay: show absolute time (#26869) --- tools/replay/consoleui.cc | 12 ++---------- tools/replay/replay.h | 1 + tools/replay/route.cc | 1 + tools/replay/route.h | 3 +++ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tools/replay/consoleui.cc b/tools/replay/consoleui.cc index 77357a2873..5ad702590c 100644 --- a/tools/replay/consoleui.cc +++ b/tools/replay/consoleui.cc @@ -50,14 +50,6 @@ void add_str(WINDOW *w, const char *str, Color color = Color::Default, bool bold if (color != Color::Default) wattroff(w, COLOR_PAIR(color)); } -std::string format_seconds(int s) { - int total_minutes = s / 60; - int seconds = s % 60; - int hours = total_minutes / 60; - int minutes = total_minutes % 60; - return util::string_format("%02d:%02d:%02d", hours, minutes, seconds); -} - } // namespace ConsoleUI::ConsoleUI(Replay *replay, QObject *parent) : replay(replay), sm({"carState", "liveParameters"}), QObject(parent) { @@ -177,8 +169,8 @@ void ConsoleUI::updateStatus() { } auto [status_str, status_color] = status_text[status]; write_item(0, 0, "STATUS: ", status_str, " ", false, status_color); - std::string suffix = " / " + format_seconds(replay->totalSeconds()); - write_item(0, 25, "TIME: ", format_seconds(replay->currentSeconds()), suffix, true); + std::string current_segment = " - " + std::to_string((int)(replay->currentSeconds() / 60)); + write_item(0, 25, "TIME: ", replay->currentDateTime().toString("ddd MMMM dd hh:mm:ss").toStdString(), current_segment, true); auto p = sm["liveParameters"].getLiveParameters(); write_item(1, 0, "STIFFNESS: ", util::string_format("%.2f %%", p.getStiffnessFactor() * 100), " "); diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 2c68443df0..6788a97d03 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -64,6 +64,7 @@ public: inline void removeFlag(REPLAY_FLAGS flag) { flags_ &= ~flag; } inline const Route* route() const { return route_.get(); } inline double currentSeconds() const { return double(cur_mono_time_ - route_start_ts_) / 1e9; } + inline QDateTime currentDateTime() const { return route_->datetime().addSecs(currentSeconds()); } inline uint64_t routeStartTime() const { return route_start_ts_; } inline int toSeconds(uint64_t mono_time) const { return (mono_time - route_start_ts_) / 1e9; } inline int totalSeconds() const { return segments_.size() * 60; } diff --git a/tools/replay/route.cc b/tools/replay/route.cc index f0d6ec5a12..9d57b9118e 100644 --- a/tools/replay/route.cc +++ b/tools/replay/route.cc @@ -31,6 +31,7 @@ bool Route::load() { rInfo("invalid route format"); return false; } + date_time_ = QDateTime::fromString(route_.timestamp, "yyyy-MM-dd--HH-mm-ss"); return data_dir_.isEmpty() ? loadFromServer() : loadFromLocal(); } diff --git a/tools/replay/route.h b/tools/replay/route.h index 6b78ebad87..86adf6a14d 100644 --- a/tools/replay/route.h +++ b/tools/replay/route.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "tools/replay/framereader.h" @@ -27,6 +28,7 @@ public: Route(const QString &route, const QString &data_dir = {}); bool load(); inline const QString &name() const { return route_.str; } + inline const QDateTime datetime() const { return date_time_; } inline const QString &dir() const { return data_dir_; } inline const RouteIdentifier &identifier() const { return route_; } inline const std::map &segments() const { return segments_; } @@ -41,6 +43,7 @@ protected: RouteIdentifier route_ = {}; QString data_dir_; std::map segments_; + QDateTime date_time_; }; class Segment : public QObject { From ae256dceba4fff8c036777b118873d2fbcfab42c Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 7 Jan 2023 13:18:28 -0800 Subject: [PATCH 0582/1179] revert: docs: update CAN FD footnote (#26896) partial revert, we still need the footnote to be exported for the shop --- selfdrive/car/hyundai/values.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index dc19c5511d..16f1f42679 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -122,10 +122,11 @@ class CAR: class Footnote(Enum): + # footnotes which mention "red panda" will be replaced with the CAN FD panda kit on the shop page CANFD = CarFootnote( "Requires a red panda for this CAN FD. " + "All the hardware needed is sold in the CAN FD kit.", - Column.MODEL, docs_only=True) + Column.MODEL, shop_footnote=True) @dataclass From b6440304d59d13b918842f68ce9f3417e3e0ecbc Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 7 Jan 2023 18:53:14 -0700 Subject: [PATCH 0583/1179] Navigation: add destination marker (#26873) * add navigation destination marker * fix removal * update default marker icon * update default marker Co-authored-by: Kurt Nistelberger --- .../assets/navigation/default_marker.svg | 5 +++++ selfdrive/ui/qt/maps/map.cc | 19 +++++++++++++++++-- selfdrive/ui/qt/maps/map.h | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 selfdrive/assets/navigation/default_marker.svg diff --git a/selfdrive/assets/navigation/default_marker.svg b/selfdrive/assets/navigation/default_marker.svg new file mode 100644 index 0000000000..116a45e251 --- /dev/null +++ b/selfdrive/assets/navigation/default_marker.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index b5519daccf..3e1d08740d 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -47,7 +47,7 @@ MapWindow::MapWindow(const QMapboxGLSettings &settings) : m_settings(settings), map_eta->setVisible(false); auto last_gps_position = coordinate_from_param("LastGPSPosition"); - if (last_gps_position) { + if (last_gps_position.has_value()) { last_position = *last_gps_position; } @@ -82,6 +82,7 @@ void MapWindow::initLayers() { m_map->setPaintProperty("navLayer", "line-color", QColor("#31a1ee")); m_map->setPaintProperty("navLayer", "line-width", 7.5); m_map->setLayoutProperty("navLayer", "line-cap", "round"); + m_map->addAnnotationIcon("default_marker", QImage("../assets/navigation/default_marker.svg")); } if (!m_map->layerExists("carPosLayer")) { qDebug() << "Initializing carPosLayer"; @@ -220,7 +221,6 @@ void MapWindow::updateState(const UIState &s) { emit instructionsChanged(i); } } else { - m_map->setPitch(MIN_PITCH); clearRoute(); } } @@ -237,6 +237,7 @@ void MapWindow::updateState(const UIState &s) { m_map->setLayoutProperty("navLayer", "visibility", "visible"); route_rcv_frame = sm.rcv_frame("navRoute"); + update_destination_marker(); } } @@ -274,6 +275,7 @@ void MapWindow::clearRoute() { if (!m_map.isNull()) { m_map->setLayoutProperty("navLayer", "visibility", "none"); m_map->setPitch(MIN_PITCH); + update_destination_marker(); } map_instructions->hideIfNoError(); @@ -361,6 +363,19 @@ void MapWindow::offroadTransition(bool offroad) { last_bearing = {}; } +void MapWindow::update_destination_marker() { + if (marker_id != -1) { + m_map->removeAnnotation(marker_id); + marker_id = -1; + } + + auto nav_dest = coordinate_from_param("NavDestination"); + if (nav_dest.has_value()) { + auto ano = QMapbox::SymbolAnnotation {*nav_dest, "default_marker"}; + marker_id = m_map->addAnnotation(QVariant::fromValue(ano)); + } +} + MapInstructions::MapInstructions(QWidget * parent) : QWidget(parent) { is_rhd = Params().getBool("IsRhdDetected"); QHBoxLayout *main_layout = new QHBoxLayout(this); diff --git a/selfdrive/ui/qt/maps/map.h b/selfdrive/ui/qt/maps/map.h index c3d5e92530..8151bdecfd 100644 --- a/selfdrive/ui/qt/maps/map.h +++ b/selfdrive/ui/qt/maps/map.h @@ -79,6 +79,7 @@ private: QMapboxGLSettings m_settings; QScopedPointer m_map; + QMapbox::AnnotationID marker_id = -1; void initLayers(); @@ -111,6 +112,7 @@ private: MapETA* map_eta; void clearRoute(); + void update_destination_marker(); uint64_t route_rcv_frame = 0; private slots: From 2b611862becd0cafbe6949961da04dfa4d252b4e Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 7 Jan 2023 17:56:16 -0800 Subject: [PATCH 0584/1179] match style --- selfdrive/ui/qt/maps/map.cc | 6 +++--- selfdrive/ui/qt/maps/map.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index 3e1d08740d..c625564f1d 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -237,7 +237,7 @@ void MapWindow::updateState(const UIState &s) { m_map->setLayoutProperty("navLayer", "visibility", "visible"); route_rcv_frame = sm.rcv_frame("navRoute"); - update_destination_marker(); + updateDestinationMarker(); } } @@ -275,7 +275,7 @@ void MapWindow::clearRoute() { if (!m_map.isNull()) { m_map->setLayoutProperty("navLayer", "visibility", "none"); m_map->setPitch(MIN_PITCH); - update_destination_marker(); + updateDestinationMarker(); } map_instructions->hideIfNoError(); @@ -363,7 +363,7 @@ void MapWindow::offroadTransition(bool offroad) { last_bearing = {}; } -void MapWindow::update_destination_marker() { +void MapWindow::updateDestinationMarker() { if (marker_id != -1) { m_map->removeAnnotation(marker_id); marker_id = -1; diff --git a/selfdrive/ui/qt/maps/map.h b/selfdrive/ui/qt/maps/map.h index 8151bdecfd..0d8b93a5f4 100644 --- a/selfdrive/ui/qt/maps/map.h +++ b/selfdrive/ui/qt/maps/map.h @@ -112,7 +112,7 @@ private: MapETA* map_eta; void clearRoute(); - void update_destination_marker(); + void updateDestinationMarker(); uint64_t route_rcv_frame = 0; private slots: From 2204a7153f3f63716eedf81a8aeee9f2ed3e3c2e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 9 Jan 2023 07:51:08 +0800 Subject: [PATCH 0585/1179] replay: remove need for fake dongle id (#26899) --- tools/replay/route.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/replay/route.cc b/tools/replay/route.cc index 9d57b9118e..619aeb3f5f 100644 --- a/tools/replay/route.cc +++ b/tools/replay/route.cc @@ -19,15 +19,15 @@ Route::Route(const QString &route, const QString &data_dir) : data_dir_(data_dir } RouteIdentifier Route::parseRoute(const QString &str) { - QRegExp rx(R"(^([a-z0-9]{16})([|_/])(\d{4}-\d{2}-\d{2}--\d{2}-\d{2}-\d{2})(?:(--|/)(\d*))?$)"); + QRegExp rx(R"(^(?:([a-z0-9]{16})([|_/]))?(\d{4}-\d{2}-\d{2}--\d{2}-\d{2}-\d{2})(?:(--|/)(\d*))?$)"); if (rx.indexIn(str) == -1) return {}; const QStringList list = rx.capturedTexts(); - return {list[1], list[3], list[5].toInt(), list[1] + "|" + list[3]}; + return {.dongle_id = list[1], .timestamp = list[3], .segment_id = list[5].toInt(), .str = list[1] + "|" + list[3]}; } bool Route::load() { - if (route_.str.isEmpty()) { + if (route_.str.isEmpty() || (data_dir_.isEmpty() && route_.dongle_id.isEmpty())) { rInfo("invalid route format"); return false; } From 19a15eeb539c8e8f53166b8885e09d6276d32fd8 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Mon, 9 Jan 2023 19:30:30 +0100 Subject: [PATCH 0586/1179] MacOS: homebrew arm-none-eabi-gcc works again (#26903) Revert "Fix gcc-arm-embedded for m1 mac (#24515)" This reverts commit 01a237ef02cf989a3e2dc8a529d5a0338a09e123. --- tools/mac_setup.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh index e85292da03..dd2041e0cb 100755 --- a/tools/mac_setup.sh +++ b/tools/mac_setup.sh @@ -52,14 +52,9 @@ brew "zeromq" brew "protobuf" brew "protobuf-c" brew "swig" +cask "gcc-arm-embedded" EOS -# Install gcc-arm-embedded 10.3-2021.10. 11.x is broken on M1 Macs with Xcode 13.3~ -brew uninstall gcc-arm-embedded || true -curl -L https://github.com/Homebrew/homebrew-cask/raw/d407663b8017a0a062c7fc0b929faf2e16abd1ff/Casks/gcc-arm-embedded.rb > /tmp/gcc-arm-embedded.rb -brew install --cask /tmp/gcc-arm-embedded.rb -rm /tmp/gcc-arm-embedded.rb - echo "[ ] finished brew install t=$SECONDS" BREW_PREFIX=$(brew --prefix) From a421c9464eec3a6b994df5ec010ff51b27aa4bbc Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 10 Jan 2023 05:48:04 +0800 Subject: [PATCH 0587/1179] replay: sync vision buffer (#26904) --- tools/replay/camera.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/camera.cc b/tools/replay/camera.cc index 72b385dca8..66898c9244 100644 --- a/tools/replay/camera.cc +++ b/tools/replay/camera.cc @@ -56,7 +56,7 @@ void CameraServer::cameraThread(Camera &cam) { .timestamp_eof = eidx.getTimestampEof(), }; yuv->set_frame_id(eidx.getFrameId()); - vipc_server_->send(yuv, &extra, false); + vipc_server_->send(yuv, &extra); } else { rError("camera[%d] failed to get frame: %lu", cam.type, eidx.getSegmentId()); } From a40efbdfcc3619528a2634d6b291c928c2374b4b Mon Sep 17 00:00:00 2001 From: Tim Wilson Date: Mon, 9 Jan 2023 16:01:55 -0700 Subject: [PATCH 0588/1179] GM camera ACC: always set long tune (#26892) * GM: set long tune for camera car w/o exp. mode * same tuning * update refs Co-authored-by: Shane Smiskol --- selfdrive/car/gm/interface.py | 18 +++++++++--------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 195df36a7f..856dcbaae5 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -68,20 +68,20 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.minEnableSpeed = 5 * CV.KPH_TO_MS + # Tuning for experimental long + ret.longitudinalTuning.kpV = [2.0, 1.5] + ret.longitudinalTuning.kiV = [0.72] + ret.stopAccel = -2.0 + ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling + ret.vEgoStopping = 0.25 + ret.vEgoStarting = 0.25 + ret.longitudinalActuatorDelayUpperBound = 0.5 + if experimental_long: ret.pcmCruise = False ret.openpilotLongitudinalControl = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG - # Tuning - ret.longitudinalTuning.kpV = [2.0, 1.5] - ret.longitudinalTuning.kiV = [0.72] - ret.stopAccel = -2.0 - ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling - ret.vEgoStopping = 0.25 - ret.vEgoStarting = 0.25 - ret.longitudinalActuatorDelayUpperBound = 0.5 - else: # ASCM, OBD-II harness ret.openpilotLongitudinalControl = True ret.networkLocation = NetworkLocation.gateway diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 603d2b2d96..24ec1c62de 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -557ffbf5a1c9cafba1ff8d6f3e2642df98b2d6e6 \ No newline at end of file +6d30c77af7b3210b03f65b433c0a043a96ee39bc \ No newline at end of file From dac7a24677ab680a0ff8fe209cc73cb14d6672a5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 9 Jan 2023 16:21:47 -0800 Subject: [PATCH 0589/1179] car interfaces: test longitudinal params are set correctly (#26894) * add long unit tests and fix * revert * remove debug * cleanup Co-authored-by: Laptop Researcher --- selfdrive/car/tests/test_car_interfaces.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 48d85584b3..11e7be7f44 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -35,6 +35,12 @@ class TestCarInterfaces(unittest.TestCase): self.assertGreater(car_params.centerToFront, 0) self.assertGreater(car_params.maxLateralAccel, 0) + # Longitudinal sanity checks + self.assertEqual(len(car_params.longitudinalTuning.kpV), len(car_params.longitudinalTuning.kpBP)) + self.assertEqual(len(car_params.longitudinalTuning.kiV), len(car_params.longitudinalTuning.kiBP)) + self.assertEqual(len(car_params.longitudinalTuning.deadzoneV), len(car_params.longitudinalTuning.deadzoneBP)) + + # Lateral sanity checks if car_params.steerControlType != car.CarParams.SteerControlType.angle: tune = car_params.lateralTuning if tune.which() == 'pid': From 9b9c2a657ed0ba326727339269654f9497997a70 Mon Sep 17 00:00:00 2001 From: David Peterson Date: Mon, 9 Jan 2023 20:25:43 -0500 Subject: [PATCH 0590/1179] Car docs: add video for Nissan Leaf (#26901) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-22”), video_link= "https://youtu.be/vaMbtAh_0cY&t=0s"), Add Youtube video 2019 Leaf * Update selfdrive/car/nissan/values.py Co-authored-by: Shane Smiskol --- selfdrive/car/nissan/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/nissan/values.py b/selfdrive/car/nissan/values.py index 6371b56be8..e9af828e2b 100644 --- a/selfdrive/car/nissan/values.py +++ b/selfdrive/car/nissan/values.py @@ -39,7 +39,7 @@ class NissanCarInfo(CarInfo): CAR_INFO: Dict[str, Optional[Union[NissanCarInfo, List[NissanCarInfo]]]] = { CAR.XTRAIL: NissanCarInfo("Nissan X-Trail 2017"), - CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-22"), + CAR.LEAF: NissanCarInfo("Nissan Leaf 2018-22", video_link="https://youtu.be/vaMbtAh_0cY"), CAR.LEAF_IC: None, # same platforms CAR.ROGUE: NissanCarInfo("Nissan Rogue 2018-20"), CAR.ALTIMA: NissanCarInfo("Nissan Altima 2019-20", harness=Harness.nissan_b), From 1a907b4c7a3167ad21b992fd74e2439019163086 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 9 Jan 2023 21:14:02 -0500 Subject: [PATCH 0591/1179] HKG: add FW Versions for 2019 Kia Stinger (#26897) * HKG: Add FW Versions for 2019 Kia Stinger * Update selfdrive/car/hyundai/values.py * fix * use shorter query Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 16f1f42679..736ebbb553 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -799,6 +799,7 @@ FW_VERSIONS = { b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ', b'\xf1\x00CK__ SCC F_CUP 1.00 1.03 96400-J5100 ', b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5000 ', + b'\xf1\x00CK__ SCC F_CUP 1.00 1.02 96400-J5100 ', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x81606DE051\x00\x00\x00\x00\x00\x00\x00\x00', @@ -806,6 +807,7 @@ FW_VERSIONS = { 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', + b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5200 4C2CL104', @@ -813,6 +815,7 @@ FW_VERSIONS = { b'\xf1\x00CK MDPS R 1.00 1.04 57700-J5420 4C4VL104', b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5420 4C4VL106', b'\xf1\x00CK MDPS R 1.00 1.07 57700-J5220 4C2VL107', + b'\xf1\x00CK MDPS R 1.00 1.06 57700-J5220 4C2VL106', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822', @@ -820,6 +823,7 @@ FW_VERSIONS = { b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00bcsh8p54 E25\x00\x00\x00\x00\x00\x00\x00SCK0T33NB2\xb3\xee\xba\xdc', b'\xf1\x87VCJLE17622572DK0vd6D\x99\x98y\x97vwVffUfvfC%CuT&Dx\x87o\xff{\x1c\xf1\x81E21\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SCK0T33NB0\x88\xa2\xe6\xf0', 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\x88\xa2\xe6\xf0', b'\xf1\x87VDHLG17000192DK2xdFffT\xa5VUD$DwT\x86wveVeeD&T\x99\xba\x8f\xff\xcc\x99\xf1\x89E21\x00\x00\x00\x00\x00\x00\x00\xf1\x82SCK0T33NB0', From d12146fbd657042bb6a74caa4c10b08a09ba074d Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Mon, 9 Jan 2023 20:57:51 -0600 Subject: [PATCH 0592/1179] Add several missing LEXUS_RC firmwares (#26905) * Add several missing LEXUS_RC firmwares `@Vranesh#9912` 2020 RC350 DongleID/route d6303cdeea512a4e|2023-01-09--17-11-55 * lexus now has two engines * todo Co-authored-by: Shane Smiskol --- selfdrive/car/fw_query_definitions.py | 1 + selfdrive/car/toyota/values.py | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index c7e4d4eb30..a1695733fa 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -62,6 +62,7 @@ class Request: @dataclass class FwQueryConfig: requests: List[Request] + # TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus # Overrides and removes from essential ecus for specific models and ecus (exact matching) non_essential_ecus: Dict[capnp.lib.capnp._EnumModule, List[str]] = field(default_factory=dict) # Ecus added for data collection, not to be fingerprinted on diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index e945130e90..586b1a835e 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -230,7 +230,7 @@ FW_QUERY_CONFIG = FwQueryConfig( # FIXME: On some models, abs can sometimes be missing Ecu.abs: [CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_IS], # On some models, the engine can show on two different addresses - Ecu.engine: [CAR.CAMRY, CAR.COROLLA_TSS2, CAR.CHR, CAR.LEXUS_IS], + Ecu.engine: [CAR.CAMRY, CAR.COROLLA_TSS2, CAR.CHR, CAR.LEXUS_IS, CAR.LEXUS_RC], } ) @@ -1738,22 +1738,29 @@ FW_VERSIONS = { ], }, CAR.LEXUS_RC: { + (Ecu.engine, 0x700, None): [ + b'\x01896632478200\x00\x00\x00\x00', + ], (Ecu.engine, 0x7e0, None): [ b'\x0232484000\x00\x00\x00\x00\x00\x00\x00\x0052422000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ + b'F152624150\x00\x00\x00\x00\x00\x00', b'F152624221\x00\x00\x00\x00\x00\x00', ], (Ecu.dsu, 0x791, None): [ + b'881512407000\x00\x00\x00\x00', b'881512409100\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B24081\x00\x00\x00\x00\x00\x00', + b'8965B24320\x00\x00\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ b'8821F4702300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'8646F2401200\x00\x00\x00\x00', b'8646F2402200\x00\x00\x00\x00', ], }, From 9e364ff76f9c0b23ebe557b95b4a584dff052e97 Mon Sep 17 00:00:00 2001 From: Kyle Dibble-Dabney <6963660+dibble9012@users.noreply.github.com> Date: Mon, 9 Jan 2023 22:01:03 -0500 Subject: [PATCH 0593/1179] Added fingerprint for 2023 EV6, fwdCamera (#26900) --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 736ebbb553..1a81e1b167 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1466,6 +1466,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', + b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630', ], }, CAR.IONIQ_5: { From 4e9bddee5cbabe4807e690a93408a23ce66225d5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 10 Jan 2023 13:02:43 -0800 Subject: [PATCH 0594/1179] longcontrol: enter stopping state immediately (#26879) * enter stopping state immediately * Update selfdrive/controls/lib/longcontrol.py --- selfdrive/controls/lib/longcontrol.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 545a4c43ff..e8095813f2 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -30,10 +30,8 @@ def long_control_state_trans(CP, active, long_control_state, v_ego, v_target, long_control_state = LongCtrlState.off else: - if long_control_state == LongCtrlState.off: + if long_control_state in (LongCtrlState.off, LongCtrlState.pid): long_control_state = LongCtrlState.pid - - elif long_control_state == LongCtrlState.pid: if stopping_condition: long_control_state = LongCtrlState.stopping From b45dda2d0a365946e4cfc3c4a08023c05e2d58c7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 10 Jan 2023 14:46:43 -0800 Subject: [PATCH 0595/1179] Longitudinal tests: test forceDecel (#26765) * test with forceDecel * test all combos * fix * fix * fix * ... * remove print * clean up * just set cruise to 0 * update ref commit Co-authored-by: Bruce Wayne --- .../lib/longitudinal_mpc_lib/long_mpc.py | 2 +- .../controls/lib/longitudinal_planner.py | 7 +- .../test/longitudinal_maneuvers/maneuver.py | 6 ++ .../test/longitudinal_maneuvers/plant.py | 4 +- .../test_longitudinal.py | 68 +++++++++++-------- selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 51 insertions(+), 38 deletions(-) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index dc27fd27a9..c017951232 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -306,7 +306,7 @@ class LongitudinalMpc: self.cruise_min_a = min_a self.max_a = max_a - def update(self, carstate, radarstate, v_cruise, x, v, a, j): + def update(self, radarstate, v_cruise, x, v, a, j): v_ego = self.x0[1] self.status = radarstate.leadOne.status or radarstate.leadTwo.status diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index a0f6318323..0febfbafd9 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -15,7 +15,6 @@ from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, CONTROL_N from system.swaglog import cloudlog LON_MPC_STEP = 0.2 # first step is 0.2s -AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distracted A_CRUISE_MIN = -1.2 A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6] A_CRUISE_MAX_BP = [0., 10.0, 25., 40.] @@ -111,9 +110,7 @@ class LongitudinalPlanner: self.v_model_error = sm['modelV2'].temporalPose.trans[0] - v_ego if force_slow_decel: - # if required so, force a smooth deceleration - accel_limits_turns[1] = min(accel_limits_turns[1], AWARENESS_DECEL) - accel_limits_turns[0] = min(accel_limits_turns[0], accel_limits_turns[1]) + v_cruise = 0.0 # clip limits, cannot init MPC outside of bounds accel_limits_turns[0] = min(accel_limits_turns[0], self.a_desired + 0.05) accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05) @@ -122,7 +119,7 @@ class LongitudinalPlanner: self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1]) self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired) x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error) - self.mpc.update(sm['carState'], sm['radarState'], v_cruise, x, v, a, j) + self.mpc.update(sm['radarState'], v_cruise, x, v, a, j) self.v_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.v_solution) self.a_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.a_solution) diff --git a/selfdrive/test/longitudinal_maneuvers/maneuver.py b/selfdrive/test/longitudinal_maneuvers/maneuver.py index 65935f8979..00ddfe627e 100644 --- a/selfdrive/test/longitudinal_maneuvers/maneuver.py +++ b/selfdrive/test/longitudinal_maneuvers/maneuver.py @@ -19,6 +19,7 @@ class Maneuver: self.ensure_start = kwargs.get("ensure_start", False) self.enabled = kwargs.get("enabled", True) self.e2e = kwargs.get("e2e", False) + self.force_decel = kwargs.get("force_decel", False) self.duration = duration self.title = title @@ -32,6 +33,7 @@ class Maneuver: only_lead2=self.only_lead2, only_radar=self.only_radar, e2e=self.e2e, + force_decel=self.force_decel, ) valid = True @@ -60,6 +62,10 @@ class Maneuver: if self.ensure_start and log['v_rel'] > 0 and log['speeds'][-1] <= 0.1: print('LongitudinalPlanner not starting!') valid = False + if self.force_decel and log['speed'] > 1e-1 and log['acceleration'] > -0.04: + print('Not stopping with force decel') + valid = False + print("maneuver end", valid) return valid, np.array(logs) diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index 8e150d800c..59cb0e1fe3 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -15,7 +15,7 @@ class Plant: messaging_initialized = False def __init__(self, lead_relevancy=False, speed=0.0, distance_lead=2.0, - enabled=True, only_lead2=False, only_radar=False, e2e=False): + enabled=True, only_lead2=False, only_radar=False, e2e=False, force_decel=False): self.rate = 1. / DT_MDL if not Plant.messaging_initialized: @@ -39,6 +39,7 @@ class Plant: self.only_lead2 = only_lead2 self.only_radar = only_radar self.e2e = e2e + self.force_decel = force_decel self.rk = Ratekeeper(self.rate, print_delay_threshold=100.0) self.ts = 1. / self.rate @@ -111,6 +112,7 @@ class Plant: control.controlsState.longControlState = LongCtrlState.pid if self.enabled else LongCtrlState.off control.controlsState.vCruise = float(v_cruise * 3.6) control.controlsState.experimentalMode = self.e2e + control.controlsState.forceDecel = self.force_decel car_state.carState.vEgo = float(self.speed) car_state.carState.standstill = self.speed < 0.01 diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py index 686b35e456..bc477ca9fe 100755 --- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py +++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 +import itertools import os -from parameterized import parameterized +from parameterized import parameterized_class import unittest from common.params import Params @@ -9,8 +10,8 @@ from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver # TODO: make new FCW tests -def create_maneuvers(e2e): - return [ +def create_maneuvers(kwargs): + maneuvers = [ Maneuver( 'approach stopped car at 25m/s, initial distance: 120m', duration=20., @@ -19,7 +20,7 @@ def create_maneuvers(e2e): initial_distance_lead=120., speed_lead_values=[30., 0.], breakpoints=[0., 1.], - e2e=e2e, + **kwargs, ), Maneuver( 'approach stopped car at 20m/s, initial distance 90m', @@ -29,7 +30,7 @@ def create_maneuvers(e2e): initial_distance_lead=90., speed_lead_values=[20., 0.], breakpoints=[0., 1.], - e2e=e2e, + **kwargs, ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 1m/s^2', @@ -39,7 +40,7 @@ def create_maneuvers(e2e): initial_distance_lead=35., speed_lead_values=[20., 20., 0.], breakpoints=[0., 15., 35.0], - e2e=e2e, + **kwargs, ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 2m/s^2', @@ -49,7 +50,7 @@ def create_maneuvers(e2e): initial_distance_lead=35., speed_lead_values=[20., 20., 0.], breakpoints=[0., 15., 25.0], - e2e=e2e, + **kwargs, ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 3m/s^2', @@ -59,7 +60,7 @@ def create_maneuvers(e2e): initial_distance_lead=35., speed_lead_values=[20., 20., 0.], breakpoints=[0., 15., 21.66], - e2e=e2e, + **kwargs, ), Maneuver( 'steady state following a car at 20m/s, then lead decel to 0mph at 3+m/s^2', @@ -71,7 +72,7 @@ def create_maneuvers(e2e): prob_lead_values=[0., 1., 1.], cruise_values=[20., 20., 20.], breakpoints=[2., 2.01, 8.8], - e2e=e2e, + **kwargs, ), Maneuver( "approach stopped car at 20m/s, with prob_lead_values", @@ -83,7 +84,7 @@ def create_maneuvers(e2e): prob_lead_values=[0.0, 0., 1.], cruise_values=[20., 20., 20.], breakpoints=[0.0, 2., 2.01], - e2e=e2e, + **kwargs, ), Maneuver( "approach slower cut-in car at 20m/s", @@ -94,7 +95,7 @@ def create_maneuvers(e2e): speed_lead_values=[15., 15.], breakpoints=[1., 11.], only_lead2=True, - e2e=e2e, + **kwargs, ), Maneuver( "stay stopped behind radar override lead", @@ -106,7 +107,7 @@ def create_maneuvers(e2e): prob_lead_values=[0., 0.], breakpoints=[1., 11.], only_radar=True, - e2e=e2e, + **kwargs, ), Maneuver( "NaN recovery", @@ -117,10 +118,20 @@ def create_maneuvers(e2e): speed_lead_values=[0., 0., 0.0], breakpoints=[1., 1.01, 11.], cruise_values=[float("nan"), 15., 15.], - e2e=e2e, + **kwargs, ), - # controls relies on planner commanding to move for stock-ACC resume spamming Maneuver( + 'cruising at 25 m/s while disabled', + duration=20., + initial_speed=25., + lead_relevancy=False, + enabled=False, + **kwargs, + ), + ] + if not kwargs['force_decel']: + # controls relies on planner commanding to move for stock-ACC resume spamming + maneuvers.append(Maneuver( "resume from a stop", duration=20., initial_speed=0., @@ -129,20 +140,16 @@ def create_maneuvers(e2e): speed_lead_values=[0., 0., 2.], breakpoints=[1., 10., 15.], ensure_start=True, - e2e=e2e, - ), - Maneuver( - 'cruising at 25 m/s while disabled', - duration=20., - initial_speed=25., - lead_relevancy=False, - enabled=False, - e2e=e2e, - ), - ] + **kwargs, + )) + return maneuvers +@parameterized_class(("e2e", "force_decel"), itertools.product([True, False], repeat=2)) class LongitudinalControl(unittest.TestCase): + e2e: bool + force_decel: bool + @classmethod def setUpClass(cls): os.environ['SIMULATION'] = "1" @@ -154,11 +161,12 @@ class LongitudinalControl(unittest.TestCase): params.put_bool("Passive", bool(os.getenv("PASSIVE"))) params.put_bool("OpenpilotEnabledToggle", True) - @parameterized.expand([(man,) for e2e in [True, False] for man in create_maneuvers(e2e)]) - def test_maneuver(self, maneuver): - print(maneuver.title, f'in {"e2e" if maneuver.e2e else "acc"} mode') - valid, _ = maneuver.evaluate() - self.assertTrue(valid, msg=maneuver.title) + def test_maneuver(self): + for maneuver in create_maneuvers({"e2e": self.e2e, "force_decel": self.force_decel}): + with self.subTest(title=maneuver.title, e2e=maneuver.e2e, force_decel=maneuver.force_decel): + print(maneuver.title, f'in {"e2e" if maneuver.e2e else "acc"} mode') + valid, _ = maneuver.evaluate() + self.assertTrue(valid) if __name__ == "__main__": diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 24ec1c62de..c23ff8a140 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -6d30c77af7b3210b03f65b433c0a043a96ee39bc \ No newline at end of file +c39b74fdc14bb22a1c95cd5deedd4f4fcadf8494 From 5f66a9a6213f6c42161584979a2f760f9ad9df47 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 10 Jan 2023 16:20:27 -0800 Subject: [PATCH 0596/1179] jenkins fixups --- Jenkinsfile | 3 ++- selfdrive/test/process_replay/model_replay.py | 2 +- selfdrive/test/setup_device_ci.sh | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 37621dde5c..f49ccf4315 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -90,7 +90,8 @@ pipeline { } } steps { - sh "git config --global --add safe.directory ${WORKSPACE}" + sh "git config --global --add safe.directory '*'" + sh "git submodule update --init --recursive" sh "git lfs pull" lock(resource: "", label: "simulator", inversePrecedence: true, quantity: 1) { sh "${WORKSPACE}/tools/sim/build_container.sh" diff --git a/selfdrive/test/process_replay/model_replay.py b/selfdrive/test/process_replay/model_replay.py index 324801fead..68cbb28aaf 100755 --- a/selfdrive/test/process_replay/model_replay.py +++ b/selfdrive/test/process_replay/model_replay.py @@ -223,7 +223,7 @@ if __name__ == "__main__": try: expected_msgs = 2*MAX_FRAMES if not NO_NAV: - expected_msgs += NAV_FRAMES*2 + expected_msgs += NAV_FRAMES*3 cmp_log = list(LogReader(BASE_URL + log_fn))[:expected_msgs] ignore = [ diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh index 9e06b98662..b7d586a83b 100755 --- a/selfdrive/test/setup_device_ci.sh +++ b/selfdrive/test/setup_device_ci.sh @@ -56,7 +56,7 @@ cd $SOURCE_DIR rm -f .git/index.lock git reset --hard -git fetch --verbose origin $GIT_COMMIT +git fetch --no-tags --no-recurse-submodules -j4 --verbose --depth 1 origin $GIT_COMMIT find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \; git reset --hard $GIT_COMMIT git checkout $GIT_COMMIT @@ -69,6 +69,7 @@ git lfs pull (ulimit -n 65535 && git lfs prune) echo "git checkout done, t=$SECONDS" +du -hs $SOURCE_DIR $SOURCE_DIR/.git rsync -a --delete $SOURCE_DIR $TEST_DIR From f0d0d999813ee3c5cc49c2b47623296c70d37318 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 10 Jan 2023 19:59:39 -0800 Subject: [PATCH 0597/1179] process replay: test body with joystick mode (#26916) * no need to check sm * fix * Update ref_commit * revert --- selfdrive/controls/controlsd.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index fea19adbdb..b5d5e3d8a2 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -103,7 +103,7 @@ class Controls: else: self.CI, self.CP = CI, CI.CP - self.joystick_mode = self.params.get_bool("JoystickDebugMode") or (self.CP.notCar and sm is None) + self.joystick_mode = self.params.get_bool("JoystickDebugMode") or self.CP.notCar # set alternative experiences from parameters self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c23ff8a140..76f2ef06ba 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c39b74fdc14bb22a1c95cd5deedd4f4fcadf8494 +d9432dcfb875a76be051137969e371c9926611e9 From cb88b3ed6528a7ad840be7bcd33fe7023b4f3719 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 10 Jan 2023 23:51:10 -0500 Subject: [PATCH 0598/1179] controlsd: set latActive with max minimum steer speed (#26805) * refactor minimum lateral speed handling * rename for clarity * simplify without joystick at standstill * intermediate standstill variable, check notCar * check joystick for now * cmt Co-authored-by: Shane Smiskol --- selfdrive/controls/controlsd.py | 6 ++++-- selfdrive/controls/lib/latcontrol.py | 2 +- selfdrive/controls/lib/latcontrol_angle.py | 4 ++-- selfdrive/controls/lib/latcontrol_indi.py | 4 ++-- selfdrive/controls/lib/latcontrol_pid.py | 4 ++-- selfdrive/controls/lib/latcontrol_torque.py | 4 ++-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index b5d5e3d8a2..1d92cd4fb2 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -17,7 +17,7 @@ from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can from selfdrive.controls.lib.lateral_planner import CAMERA_OFFSET from selfdrive.controls.lib.drive_helpers import VCruiseHelper, get_lag_adjusted_curvature -from selfdrive.controls.lib.latcontrol import LatControl +from selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED from selfdrive.controls.lib.longcontrol import LongControl from selfdrive.controls.lib.latcontrol_pid import LatControlPID from selfdrive.controls.lib.latcontrol_indi import LatControlINDI @@ -569,9 +569,11 @@ class Controls: CC = car.CarControl.new_message() CC.enabled = self.enabled + # Check which actuators can be enabled + standstill = CS.vEgo <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill CC.latActive = self.active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \ - CS.vEgo > self.CP.minSteerSpeed and not CS.standstill + (not standstill or self.joystick_mode) CC.longActive = self.enabled and not self.events.any(ET.OVERRIDE_LONGITUDINAL) and self.CP.openpilotLongitudinalControl actuators = CC.actuators diff --git a/selfdrive/controls/lib/latcontrol.py b/selfdrive/controls/lib/latcontrol.py index cefbc1078c..d38959c560 100644 --- a/selfdrive/controls/lib/latcontrol.py +++ b/selfdrive/controls/lib/latcontrol.py @@ -3,7 +3,7 @@ from abc import abstractmethod, ABC from common.numpy_fast import clip from common.realtime import DT_CTRL -MIN_STEER_SPEED = 0.3 +MIN_LATERAL_CONTROL_SPEED = 0.3 # m/s class LatControl(ABC): diff --git a/selfdrive/controls/lib/latcontrol_angle.py b/selfdrive/controls/lib/latcontrol_angle.py index d692f80b4b..9ed140d38e 100644 --- a/selfdrive/controls/lib/latcontrol_angle.py +++ b/selfdrive/controls/lib/latcontrol_angle.py @@ -1,7 +1,7 @@ import math from cereal import log -from selfdrive.controls.lib.latcontrol import LatControl, MIN_STEER_SPEED +from selfdrive.controls.lib.latcontrol import LatControl STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees @@ -14,7 +14,7 @@ class LatControlAngle(LatControl): def update(self, active, CS, VM, params, last_actuators, steer_limited, desired_curvature, desired_curvature_rate, llk): angle_log = log.ControlsState.LateralAngleState.new_message() - if CS.vEgo < MIN_STEER_SPEED or not active: + if not active: angle_log.active = False angle_steers_des = float(CS.steeringAngleDeg) else: diff --git a/selfdrive/controls/lib/latcontrol_indi.py b/selfdrive/controls/lib/latcontrol_indi.py index 2bc3cef76b..dca82c6729 100644 --- a/selfdrive/controls/lib/latcontrol_indi.py +++ b/selfdrive/controls/lib/latcontrol_indi.py @@ -5,7 +5,7 @@ from cereal import log from common.filter_simple import FirstOrderFilter from common.numpy_fast import clip, interp from common.realtime import DT_CTRL -from selfdrive.controls.lib.latcontrol import LatControl, MIN_STEER_SPEED +from selfdrive.controls.lib.latcontrol import LatControl class LatControlINDI(LatControl): @@ -82,7 +82,7 @@ class LatControlINDI(LatControl): rate_des = VM.get_steer_from_curvature(-desired_curvature_rate, CS.vEgo, 0) indi_log.steeringRateDesiredDeg = math.degrees(rate_des) - if CS.vEgo < MIN_STEER_SPEED or not active: + if not active: indi_log.active = False self.steer_filter.x = 0.0 output_steer = 0 diff --git a/selfdrive/controls/lib/latcontrol_pid.py b/selfdrive/controls/lib/latcontrol_pid.py index 6bd678073e..6696d2e304 100644 --- a/selfdrive/controls/lib/latcontrol_pid.py +++ b/selfdrive/controls/lib/latcontrol_pid.py @@ -1,7 +1,7 @@ import math from cereal import log -from selfdrive.controls.lib.latcontrol import LatControl, MIN_STEER_SPEED +from selfdrive.controls.lib.latcontrol import LatControl from selfdrive.controls.lib.pid import PIDController @@ -28,7 +28,7 @@ class LatControlPID(LatControl): pid_log.steeringAngleDesiredDeg = angle_steers_des pid_log.angleError = error - if CS.vEgo < MIN_STEER_SPEED or not active: + if not active: output_steer = 0.0 pid_log.active = False self.pid.reset() diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index d10d39d945..2f56094379 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -2,7 +2,7 @@ import math from cereal import log from common.numpy_fast import interp -from selfdrive.controls.lib.latcontrol import LatControl, MIN_STEER_SPEED +from selfdrive.controls.lib.latcontrol import LatControl from selfdrive.controls.lib.pid import PIDController from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY @@ -39,7 +39,7 @@ class LatControlTorque(LatControl): def update(self, active, CS, VM, params, last_actuators, steer_limited, desired_curvature, desired_curvature_rate, llk): pid_log = log.ControlsState.LateralTorqueState.new_message() - if CS.vEgo < MIN_STEER_SPEED or not active: + if not active: output_torque = 0.0 pid_log.active = False else: From 29470d2d2d5f53d4b26a220192a08adbde5eeb5d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 10 Jan 2023 22:28:54 -0800 Subject: [PATCH 0599/1179] VW: match panda standstill check (#25761) * test models: check panda standstill * match panda * reverse exception * check == 0 * bumppanda Co-authored-by: Adeeb Shihadeh --- panda | 2 +- selfdrive/car/tests/test_models.py | 2 +- selfdrive/car/volkswagen/carstate.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panda b/panda index 345147fe2b..0b3b906036 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 345147fe2bc3a06c44709426f9fcd298588b9fe4 +Subproject commit 0b3b9060365739eeeddb1528cfe4018fec4efe7a diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 641c109316..b6f78c4b47 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -238,7 +238,7 @@ class TestCarModelBase(unittest.TestCase): # TODO: check rest of panda's carstate (steering, ACC main on, etc.) checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev() - if self.CP.carName not in ("hyundai", "volkswagen", "body"): + if self.CP.carName not in ("hyundai", "body"): # TODO: fix standstill mismatches for other makes checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving() diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 7ea9aa871b..64d1246880 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -44,7 +44,7 @@ class CarState(CarStateBase): ret.vEgoRaw = float(np.mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr])) ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) - ret.standstill = ret.vEgo < 0.1 + ret.standstill = ret.vEgoRaw == 0 # Update steering angle, rate, yaw rate, and driver input torque. VW send # the sign/direction in a separate signal so they must be recombined. @@ -160,7 +160,7 @@ class CarState(CarStateBase): # vEgo obtained from Bremse_1 vehicle speed rather than Bremse_3 wheel speeds because Bremse_3 isn't present on NSF ret.vEgoRaw = pt_cp.vl["Bremse_1"]["Geschwindigkeit_neu__Bremse_1_"] * CV.KPH_TO_MS ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) - ret.standstill = ret.vEgo < 0.1 + ret.standstill = ret.vEgoRaw == 0 # Update steering angle, rate, yaw rate, and driver input torque. VW send # the sign/direction in a separate signal so they must be recombined. From f41caec2dec08aa3bbf8e0b3b6efa7600a8f6f0f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 11 Jan 2023 15:02:24 -0800 Subject: [PATCH 0600/1179] bump cereal, can in qlogs --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index f200875ca3..c0d9abf6f7 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit f200875ca300d3a7b9293c4effcc9456e359e505 +Subproject commit c0d9abf6f7c7de140c41af10e322e226d900ef99 From 9884957e3e07e09df6c021222949a4a77e2bd8ff Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 12 Jan 2023 07:32:13 +0800 Subject: [PATCH 0601/1179] cabana: sync play button state (#26917) sync play button --- tools/cabana/canmessages.cc | 5 +++++ tools/cabana/canmessages.h | 4 +++- tools/cabana/videowidget.cc | 13 +++++-------- tools/cabana/videowidget.h | 1 - 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index ad3ee80e3d..6e19eb440f 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -91,6 +91,11 @@ void CANMessages::seekTo(double ts) { emit updated(); } +void CANMessages::pause(bool pause) { + replay->pause(pause); + emit (pause ? paused() : resume()); +} + void CANMessages::settingChanged() { replay->setSegmentCacheLimit(settings.cached_segment_limit); } diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 4dac4fe9df..ea43933565 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -38,10 +38,12 @@ public: inline const std::vector *events() const { return replay->events(); } inline void setSpeed(float speed) { replay->setSpeed(speed); } inline bool isPaused() const { return replay->isPaused(); } - inline void pause(bool pause) { replay->pause(pause); } + void pause(bool pause); inline const std::vector> getTimeline() { return replay->getTimeline(); } signals: + void paused(); + void resume(); void seekedTo(double sec); void streamStarted(); void eventsMerged(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 7e40ba2adb..ed4354ce65 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -63,22 +63,19 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { } main_layout->addLayout(control_layout); - 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, &CameraWidget::clicked, [this]() { pause(!can->isPaused()); }); - QObject::connect(play_btn, &QPushButton::clicked, [=]() { pause(!can->isPaused()); }); + QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); + QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); + QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); + QObject::connect(can, &CANMessages::paused, [this]() { play_btn->setText("▶"); }); + QObject::connect(can, &CANMessages::resume, [this]() { play_btn->setText("⏸"); }); QObject::connect(can, &CANMessages::streamStarted, [this]() { end_time_label->setText(formatTime(can->totalSeconds())); slider->setRange(0, can->totalSeconds() * 1000); }); } -void VideoWidget::pause(bool pause) { - play_btn->setText(!pause ? "⏸" : "▶"); - can->pause(pause); -} - void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { if (!is_zoomed) { min = 0; diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 86cdc6f114..ec8bc4bec4 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -44,7 +44,6 @@ public: protected: void updateState(); - void pause(bool pause); CameraWidget *cam_widget; QLabel *end_time_label; From 35626303b16734b17cb3dd266c5dd6f18f8941a9 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 11 Jan 2023 18:45:15 -0500 Subject: [PATCH 0602/1179] VW MQB: Add FW for 2019 Volkswagen Golf (#26920) --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 24ea0a03ba..af73683e22 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -373,6 +373,7 @@ FW_VERSIONS = { b'\xf1\x8704L906056CR\xf1\x895813', b'\xf1\x8704L906056HE\xf1\x893758', b'\xf1\x8704L906056HN\xf1\x896590', + b'\xf1\x8704L906056HT\xf1\x896591', b'\xf1\x870EA906016A \xf1\x898343', b'\xf1\x870EA906016E \xf1\x894219', b'\xf1\x870EA906016F \xf1\x894238', @@ -405,6 +406,7 @@ FW_VERSIONS = { b'\xf1\x870CW300041H \xf1\x891010', b'\xf1\x870CW300042F \xf1\x891604', b'\xf1\x870CW300043B \xf1\x891601', + b'\xf1\x870CW300043E \xf1\x891603', b'\xf1\x870CW300044S \xf1\x894530', b'\xf1\x870CW300044T \xf1\x895245', b'\xf1\x870CW300045 \xf1\x894531', @@ -442,6 +444,7 @@ FW_VERSIONS = { b'\xf1\x875Q0959655AA\xf1\x890388\xf1\x82\x111413001113120053114317121C111C9113', b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\x1314160011123300314211012230229333463100', b'\xf1\x875Q0959655BS\xf1\x890403\xf1\x82\x1314160011123300314240012250229333463100', + b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x13141600111233003142404A2251229333463100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x13141600111233003142404A2252229333463100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x13141600111233003142405A2252229333463100', b'\xf1\x875Q0959655C \xf1\x890361\xf1\x82\x111413001112120004110415121610169112', From ccb43271977174e1a6de11b15ad07cd04c2ed056 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 11 Jan 2023 19:14:05 -0500 Subject: [PATCH 0603/1179] HKG CAN-FD: set cruise state available with car signal (#26812) * HKG CAN-FD: set cruise state available with car signal * Whoops * Check this signal * No should be in SCC_CONTROL * use TCS * add back * match CAN * think these are missing Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/carstate.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index fc196528d7..53389279f7 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -156,6 +156,9 @@ class CarState(CarStateBase): def update_canfd(self, cp, cp_cam): ret = car.CarState.new_message() + self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1 + speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS + if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR): if self.CP.carFingerprint in EV_CAR: ret.gas = cp.vl["ACCELERATOR"]["ACCELERATOR_PEDAL"] / 255. @@ -197,14 +200,18 @@ class CarState(CarStateBase): ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0 ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0 - ret.cruiseState.available = True - self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1 - if not self.CP.openpilotLongitudinalControl: - speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS + # cruise state + if self.CP.openpilotLongitudinalControl: + # These are not used for engage/disengage since openpilot keeps track of state using the buttons + ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0 + ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1 + ret.cruiseState.standstill = False + else: cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp - ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor - ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 + ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1 ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) + ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 + ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"]) cruise_btn_msg = "CRUISE_BUTTONS_ALT" if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" @@ -435,6 +442,7 @@ class CarState(CarStateBase): ("DriverBraking", "TCS"), ("ACCEnable", "TCS"), + ("ACC_REQ", "TCS"), ("COUNTER", cruise_btn_msg), ("CRUISE_BUTTONS", cruise_btn_msg), @@ -476,6 +484,7 @@ class CarState(CarStateBase): ("ACCMode", "SCC_CONTROL"), ("VSetDis", "SCC_CONTROL"), ("CRUISE_STANDSTILL", "SCC_CONTROL"), + ("MainMode_ACC", "SCC_CONTROL"), ] checks += [ ("SCC_CONTROL", 50), From a24afa18d3b43f9ea02a15d99ba8eb07b8cc9709 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 11 Jan 2023 17:22:24 -0800 Subject: [PATCH 0604/1179] Hyundai CAN-FD: set available from TCS ACC available (#26921) * available on TCS signal always * cmt enh * better comment * better --- selfdrive/car/hyundai/carstate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 53389279f7..47621d3c2c 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -201,14 +201,14 @@ class CarState(CarStateBase): ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0 # cruise state + # CAN FD cars enable on main button press, set available if no TCS faults preventing engagement + ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0 if self.CP.openpilotLongitudinalControl: # These are not used for engage/disengage since openpilot keeps track of state using the buttons - ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0 ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1 ret.cruiseState.standstill = False else: cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp - ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1 ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2) ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1 ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor @@ -484,7 +484,6 @@ class CarState(CarStateBase): ("ACCMode", "SCC_CONTROL"), ("VSetDis", "SCC_CONTROL"), ("CRUISE_STANDSTILL", "SCC_CONTROL"), - ("MainMode_ACC", "SCC_CONTROL"), ] checks += [ ("SCC_CONTROL", 50), From 257a45dd18d30971dce0a02f285874423b2bfe9d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 11 Jan 2023 20:25:01 -0800 Subject: [PATCH 0605/1179] HKG: filter on steering pressed (#26924) * filter on can steering pressed * Update ref_commit --- selfdrive/car/hyundai/carstate.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 47621d3c2c..da1a7bfa78 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -86,7 +86,7 @@ class CarState(CarStateBase): 50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"]) ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"] ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"] - ret.steeringPressed = abs(ret.steeringTorque) > self.params.STEER_THRESHOLD + ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5) ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0 # cruise state diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 76f2ef06ba..157d146ade 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -d9432dcfb875a76be051137969e371c9926611e9 +ff0348b1957c8f992125df77a36b3c0553a26e6a From 2d403cbf9c14ed51e1e6d65bd33330a5775dec66 Mon Sep 17 00:00:00 2001 From: Niels Ole Salscheider Date: Thu, 12 Jan 2023 05:33:45 +0100 Subject: [PATCH 0606/1179] VW MQB: Add FW for 2017 Seat Leon (#26883) * VW MQB: Add FW for 2017 Seat Leon * missing srs Co-authored-by: Comma Device Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index af73683e22..f627e517be 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -937,19 +937,23 @@ FW_VERSIONS = { b'\xf1\x8704L906026BP\xf1\x891198', b'\xf1\x8704L906026BP\xf1\x897608', b'\xf1\x8705E906018AS\xf1\x899596', + b'\xf1\x878V0906264H \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870CW300041G \xf1\x891003', b'\xf1\x870CW300050J \xf1\x891908', b'\xf1\x870D9300042M \xf1\x895016', ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AC\xf1\x890189\xf1\x82\r11110011110011021511110200', b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r12110012120012021612110200', + b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\x0e1312001313001305171311052900', b'\xf1\x873Q0959655CM\xf1\x890720\xf1\x82\0161312001313001305171311052900', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521N01342A1', b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00511N01805A0', + b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521N01309A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\00521N05808A1', ], (Ecu.fwdRadar, 0x757, None): [ From 69f8ac0b6508559549e99c5f12b7d9105ce1baa8 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Thu, 12 Jan 2023 00:17:58 -0500 Subject: [PATCH 0607/1179] HKG: Car Port for Kia Sorento 2022 (#26874) * HKG: Car Port for Kia Sorento 2022 * Harness K * SCC is on bus 4 * Add test route * seems reasonable * more interesting segment Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/hyundai/interface.py | 9 ++++++--- selfdrive/car/hyundai/values.py | 17 ++++++++++++++--- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index eea69d295f..1b5ef8f7a7 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,6 +6,7 @@ Version 0.9.1 (2022-12-XX) * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support +* Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! Version 0.9.0 (2022-11-21) diff --git a/docs/CARS.md b/docs/CARS.md index 930b52c8a2..ac374501dc 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 222 Supported Cars +# 223 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| @@ -110,6 +110,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| +|Kia|Sorento 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| |Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| |Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| |Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 6881be5a33..6d6d9833df 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -185,10 +185,13 @@ class CarInterface(CarInterfaceBase): ret.mass = 1767. + STD_CARGO_KG # SX Prestige trim support only ret.wheelbase = 2.756 ret.steerRatio = 13.6 - elif candidate == CAR.KIA_SORENTO_PHEV_4TH_GEN: - ret.mass = 4095.8 * CV.LB_TO_KG + STD_CARGO_KG # weight from EX and above trims, average of FWD and AWD versions (EX, X-Line EX AWD, SX, SX Pestige, X-Line SX Prestige AWD) + elif candidate in (CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN): ret.wheelbase = 2.81 - ret.steerRatio = 13.27 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sorento-phev/2022/specifications + ret.steerRatio = 13.5 # average of the platforms + if candidate == CAR.KIA_SORENTO_4TH_GEN: + ret.mass = 3957 * CV.LB_TO_KG + STD_CARGO_KG + else: + ret.mass = 4537 * CV.LB_TO_KG + STD_CARGO_KG # Genesis elif candidate == CAR.GENESIS_GV60_EV_1ST_GEN: diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1a81e1b167..229ca992d5 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -105,6 +105,7 @@ class CAR: KIA_SELTOS = "KIA SELTOS 2021" KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN" KIA_SORENTO = "KIA SORENTO GT LINE 2018" + KIA_SORENTO_4TH_GEN = "KIA SORENTO 4TH GEN" KIA_SORENTO_PHEV_4TH_GEN = "KIA SORENTO PLUG-IN HYBRID 4TH GEN" KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN" KIA_STINGER = "KIA STINGER GT2 2018" @@ -211,7 +212,8 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), ], - CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a), + CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2022-23", harness=Harness.hyundai_k), + CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", harness=Harness.hyundai_a), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022", "All", harness=Harness.hyundai_k), @@ -1543,6 +1545,14 @@ FW_VERSIONS = { b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ', ], }, + CAR.KIA_SORENTO_4TH_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.05 99210-R5000 210623', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ', + ], + }, } CHECKSUM = { @@ -1560,10 +1570,10 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN} # The radar does SCC on these cars when HDA I, rather than the camera -CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} +CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_SORENTO_4TH_GEN} # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } @@ -1628,4 +1638,5 @@ DBC = { CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None), + CAR.KIA_SORENTO_4TH_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 3edc406e19..ac0521cc68 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -100,6 +100,7 @@ routes = [ CarTestRoute("db68bbe12250812c|2022-12-05--00-54-12", HYUNDAI.TUCSON_4TH_GEN), # 2023 CarTestRoute("36e10531feea61a4|2022-07-25--13-37-42", HYUNDAI.TUCSON_HYBRID_4TH_GEN), CarTestRoute("5875672fc1d4bf57|2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO), + CarTestRoute("1d0d000db3370fd0|2023-01-04--22-28-42", HYUNDAI.KIA_SORENTO_4TH_GEN, segment=5), CarTestRoute("628935d7d3e5f4f7|2022-11-30--01-12-46", HYUNDAI.KIA_SORENTO_PHEV_4TH_GEN), CarTestRoute("9c917ba0d42ffe78|2020-04-17--12-43-19", HYUNDAI.PALISADE), CarTestRoute("05a8f0197fdac372|2022-10-19--14-14-09", HYUNDAI.IONIQ_5), # HDA2 diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index d7b2ec4079..3a9f92c046 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -36,6 +36,7 @@ KIA SPORTAGE HYBRID 5TH GEN: [2.5, 2.5, 0.1] GENESIS GV70 1ST GEN: [2.42, 2.42, 0.1] KIA SORENTO PLUG-IN HYBRID 4TH GEN: [2.5, 2.5, 0.1] GENESIS GV60 ELECTRIC 1ST GEN: [2.5, 2.5, 0.1] +KIA SORENTO 4TH GEN: [2.5, 2.5, 0.1] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From f3fa4d759d5967e8590492005b8ede8bd17a6981 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 12 Jan 2023 13:21:11 +0800 Subject: [PATCH 0608/1179] cabana: fix find similar bits (#26918) * dynamic find bit * change * Revert "change" This reverts commit 12cf513e2725a52ee40b8999521adcd6ecb00221. * change sorting and headers * make perc a float Co-authored-by: Shane Smiskol --- tools/cabana/tools/findsimilarbits.cc | 48 +++++++++++++++++++-------- tools/cabana/tools/findsimilarbits.h | 9 +++-- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 5fa5bcf7b8..cb5dbc0845 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -25,14 +25,28 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent) { } bus_combo->model()->sort(0); bus_combo->setCurrentIndex(0); + + msg_cb = new QComboBox(this); + for (auto &[address, msg] : dbc()->messages()) { + msg_cb->addItem(msg.name, address); + } + msg_cb->model()->sort(0); + msg_cb->setCurrentIndex(0); + + byte_idx_sb = new QSpinBox(this); + byte_idx_sb->setRange(0, 63); + + bit_idx_sb = new QSpinBox(this); + bit_idx_sb->setRange(0, 7); + form_layout->addWidget(new QLabel("Bus")); form_layout->addWidget(bus_combo); + form_layout->addWidget(msg_cb); + form_layout->addWidget(new QLabel("Byte Index")); + form_layout->addWidget(byte_idx_sb); + form_layout->addWidget(new QLabel("Bit Index")); + form_layout->addWidget(bit_idx_sb); - bit_combo = new QComboBox(this); - bit_combo->addItems({"0", "1"}); - bit_combo->setCurrentIndex(1); - form_layout->addWidget(new QLabel("Bit")); - form_layout->addWidget(bit_combo); min_msgs = new QLineEdit(this); min_msgs->setValidator(new QIntValidator(this)); @@ -56,10 +70,11 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent) { void FindSimilarBitsDlg::find() { search_btn->setEnabled(false); table->clear(); - auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), bit_combo->currentIndex(), min_msgs->text().toInt()); + uint32_t selected_address = msg_cb->currentData().toUInt(); + auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), min_msgs->text().toInt()); table->setRowCount(msg_mismatched.size()); table->setColumnCount(6); - table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total", "perc%"}); + table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total msgs", "% mismatched"}); for (int i = 0; i < msg_mismatched.size(); ++i) { auto &m = msg_mismatched[i]; table->setItem(i, 0, new QTableWidgetItem(QString("%1").arg(m.address, 1, 16))); @@ -72,18 +87,25 @@ void FindSimilarBitsDlg::find() { search_btn->setEnabled(true); } -QList FindSimilarBitsDlg::calcBits(uint8_t bus, int bit_to_find, int min_msgs_cnt) { +QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt) { QHash> mismatches; QHash msg_count; auto events = can->events(); + qDebug() << bus << selected_address << byte_idx << bit_idx; + int bit_to_find = -1; for (auto e : *events) { if (e->which == cereal::Event::Which::CAN) { for (const auto &c : e->event.getCan()) { if (c.getSrc() == bus) { - uint32_t address = c.getAddress(); - ++msg_count[address]; - auto &mismatched = mismatches[address]; const auto dat = c.getDat(); + uint32_t address = c.getAddress(); + if (address == selected_address && dat.size() > byte_idx) { + bit_to_find = ((dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + } + ++msg_count[address]; + if (bit_to_find == -1) continue; + + auto &mismatched = mismatches[address]; if (mismatched.size() < dat.size() * 8) { mismatched.resize(dat.size() * 8); } @@ -104,12 +126,12 @@ QList FindSimilarBitsDlg::calcBits(uint8_ if (auto cnt = msg_count[it.key()]; cnt > min_msgs_cnt) { auto &mismatched = it.value(); for (int i = 0; i < mismatched.size(); ++i) { - if (uint32_t perc = (mismatched[i] / (double)cnt) * 100; perc < 50) { + if (float perc = (mismatched[i] / (double)cnt) * 100; perc < 50) { result.push_back({it.key(), (uint32_t)i / 8, (uint32_t)i % 8, mismatched[i], cnt, perc}); } } } } - std::sort(result.begin(), result.end(), [](auto &l, auto &r) { return l.perc > r.perc; }); + std::sort(result.begin(), result.end(), [](auto &l, auto &r) { return l.perc < r.perc; }); return result; } diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 79db4a1c69..8083999909 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -3,6 +3,7 @@ #include #include #include +#include #include class FindSimilarBitsDlg : public QDialog { @@ -11,13 +12,15 @@ public: private: struct mismatched_struct { - uint32_t address, byte_idx, bit_idx, mismatches, total, perc; + uint32_t address, byte_idx, bit_idx, mismatches, total; + float perc; }; - QList calcBits(uint8_t bus, int bit_to_find, int min_msgs_cnt); + QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt); void find(); QTableWidget *table; - QComboBox *bus_combo, *bit_combo; + QComboBox *bus_combo, *msg_cb; + QSpinBox *byte_idx_sb, *bit_idx_sb; QPushButton *search_btn; QLineEdit *min_msgs; }; From a0f55f72fcc119f7a2ff902c1e347b3779c2c318 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 11 Jan 2023 22:31:25 -0800 Subject: [PATCH 0609/1179] increase nav default marker --- selfdrive/assets/navigation/default_marker.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/assets/navigation/default_marker.svg b/selfdrive/assets/navigation/default_marker.svg index 116a45e251..43d5290a96 100644 --- a/selfdrive/assets/navigation/default_marker.svg +++ b/selfdrive/assets/navigation/default_marker.svg @@ -1,5 +1,5 @@ - + From de6f9010fa6e3daf87c7cbe855af98b73fdc6d56 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 11 Jan 2023 23:30:11 -0800 Subject: [PATCH 0610/1179] Car docs: show video link (#26907) * add videos to gh docs * fix * add icon * fix * try this * white inner triangle * width * try height * use video_icon in template * clean up * rename * smaller --- docs/CARS.md | 450 +++++++++++++++--------------- docs/assets/icon-youtube.svg | 12 + selfdrive/car/CARS_template.md | 3 +- selfdrive/car/docs_definitions.py | 6 +- 4 files changed, 244 insertions(+), 227 deletions(-) create mode 100644 docs/assets/icon-youtube.svg diff --git a/docs/CARS.md b/docs/CARS.md index ac374501dc..1b76069f6a 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -6,231 +6,231 @@ A supported vehicle is one that just works when you install a comma three. All s # 223 Supported Cars -|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness| -|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| -|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None| -|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Genesis|GV60 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| -|Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM| -|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B| -|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec| -|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| -|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| -|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| -|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J| -|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| -|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q| -|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| -|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| -|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| -|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I| -|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Hyundai|Santa Cruz 2021-22[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D| -|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Hyundai|Tucson Hybrid 2022[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA| -|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| -|Kia|EV6 (with HDA II) 2022[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P| -|Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| -|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F| -|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B| -|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E| -|Kia|Sorento 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| -|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A| -|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C| -|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K| -|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| -|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda| -|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B| -|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| -|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| -|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A| -|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| -|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B| -|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A| -|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota| -|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| -|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| -|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533| +|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| +|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| +|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| +|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Genesis|GV60 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| +|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| +|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|| +|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|| +|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| +|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| +|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O|| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Santa Cruz 2021-22[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| +|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Tucson Hybrid 2022[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|| +|Kia|EV6 (with HDA II) 2022[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|| +|Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| +|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| +|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Kia|Sorento 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| +|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B|| +|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| +|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| +|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| +|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| +|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| +|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
diff --git a/docs/assets/icon-youtube.svg b/docs/assets/icon-youtube.svg new file mode 100644 index 0000000000..4e2c9fdfa9 --- /dev/null +++ b/docs/assets/icon-youtube.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/selfdrive/car/CARS_template.md b/selfdrive/car/CARS_template.md index 2fce0f9036..1c80ea3d93 100644 --- a/selfdrive/car/CARS_template.md +++ b/selfdrive/car/CARS_template.md @@ -1,5 +1,6 @@ {% set footnote_tag = '[{}](#footnotes)' -%} {% set star_icon = '[![star](assets/icon-star-{}.svg)](##)' -%} +{% set video_icon = '' -%} @@ -12,7 +13,7 @@ A supported vehicle is one that just works when you install a comma three. All s |{{Column | map(attribute='value') | join('|')}}| |---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%} {% for car_info in all_car_info %} -|{% for column in Column %}{{car_info.get_column(column, star_icon, footnote_tag)}}|{% endfor %} +|{% for column in Column %}{{car_info.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %} {% endfor %} diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index 03e9e721b5..c3063bc47c 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -21,6 +21,7 @@ class Column(Enum): STEERING_TORQUE = "Steering Torque" AUTO_RESUME = "Resume from stop" HARNESS = "Harness" + VIDEO = "Video" class Star(Enum): @@ -159,6 +160,7 @@ class CarInfo: Column.STEERING_TORQUE: Star.EMPTY, Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY, Column.HARNESS: self.harness.value, + Column.VIDEO: self.video_link if self.video_link is not None else "", # replaced with an image and link from template in get_column } # Set steering torque star from max lateral acceleration @@ -202,12 +204,14 @@ class CarInfo: else: raise Exception(f"This notCar does not have a detail sentence: {CP.carFingerprint}") - def get_column(self, column: Column, star_icon: str, footnote_tag: str) -> str: + def get_column(self, column: Column, star_icon: str, video_icon: str, footnote_tag: str) -> str: item: Union[str, Star] = self.row[column] if isinstance(item, Star): item = star_icon.format(item.value) elif column == Column.MODEL and len(self.years): item += f" {self.years}" + elif column == Column.VIDEO and len(item) > 0: + item = video_icon.format(item) footnotes = get_footnotes(self.footnotes, column) if len(footnotes): From b68dabb689104ef0819a6c881b800076deb866f6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 11 Jan 2023 23:44:50 -0800 Subject: [PATCH 0611/1179] Car interface: require fingerprint and FW versions to get params (#26766) * require fingerprint and FW versions * add get_non_essential_params() * comment * all required * classmethod, need to allow subclasses to override _get_params * fix that * fix --- selfdrive/car/docs.py | 2 +- selfdrive/car/interfaces.py | 13 +++++++------ selfdrive/car/tests/test_car_interfaces.py | 2 +- selfdrive/car/tests/test_fw_fingerprint.py | 2 +- selfdrive/controls/lib/tests/test_latcontrol.py | 2 +- selfdrive/controls/lib/tests/test_vehicle_model.py | 2 +- selfdrive/controls/tests/test_state_machine.py | 2 +- selfdrive/debug/cycle_alerts.py | 2 +- selfdrive/debug/internal/test_paramsd.py | 2 +- selfdrive/test/longitudinal_maneuvers/plant.py | 2 +- selfdrive/test/process_replay/process_replay.py | 2 +- 11 files changed, 17 insertions(+), 16 deletions(-) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 03313e2ff6..bc03619d0d 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -29,7 +29,7 @@ def get_all_car_info() -> List[CarInfo]: all_car_info: List[CarInfo] = [] footnotes = get_all_footnotes() for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items(): - CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")]) + CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=False) if CP.dashcamOnly or car_info is None: continue diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index ad1fd22b90..7192f5252c 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -88,13 +88,14 @@ class CarInterfaceBase(ABC): return ACCEL_MIN, ACCEL_MAX @classmethod - def get_params(cls, candidate: str, fingerprint: Optional[Dict[int, Dict[int, int]]] = None, car_fw: Optional[List[car.CarParams.CarFw]] = None, experimental_long: bool = False): - if fingerprint is None: - fingerprint = gen_empty_fingerprint() - - if car_fw is None: - car_fw = list() + def get_non_essential_params(cls, candidate: str): + """ + Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints. + """ + return cls.get_params(candidate, gen_empty_fingerprint(), list(), False) + @classmethod + def get_params(cls, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool): ret = CarInterfaceBase.get_std_params(candidate) ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 11e7be7f44..deb0454b9c 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -25,7 +25,7 @@ class TestCarInterfaces(unittest.TestCase): car_fw = [] - car_params = CarInterface.get_params(car_name, fingerprints, car_fw) + car_params = CarInterface.get_params(car_name, fingerprints, car_fw, experimental_long=False) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index 2e43103852..e9f23145cd 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -67,7 +67,7 @@ class TestFwFingerprint(unittest.TestCase): blacklisted_addrs = (0x7c4, 0x7d0) # includes A/C ecu and an unknown ecu for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): - CP = interfaces[car_model][0].get_params(car_model) + CP = interfaces[car_model][0].get_non_essential_params(car_model) if CP.carName == 'subaru': for ecu in ecus.keys(): self.assertNotIn(ecu[1], blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})') diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py index f15ab2fa56..993774f719 100755 --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -20,7 +20,7 @@ class TestLatControl(unittest.TestCase): @parameterized.expand([(HONDA.CIVIC, LatControlPID), (TOYOTA.RAV4, LatControlTorque), (TOYOTA.PRIUS, LatControlINDI), (NISSAN.LEAF, LatControlAngle)]) def test_saturation(self, car_name, controller): CarInterface, CarController, CarState = interfaces[car_name] - CP = CarInterface.get_params(car_name) + CP = CarInterface.get_non_essential_params(car_name) CI = CarInterface(CP, CarController, CarState) VM = VehicleModel(CP) diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py index 3e08cb0aa0..03d97a7e3f 100755 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -12,7 +12,7 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_sol, creat class TestVehicleModel(unittest.TestCase): def setUp(self): - CP = CarInterface.get_params(CAR.CIVIC) + CP = CarInterface.get_non_essential_params(CAR.CIVIC) self.VM = VehicleModel(CP) def test_round_trip_yaw_rate(self): diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index 8f263a98e7..d5f468f214 100755 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -31,7 +31,7 @@ class TestStateMachine(unittest.TestCase): def setUp(self): CarInterface, CarController, CarState = interfaces["mock"] - CP = CarInterface.get_params("mock") + CP = CarInterface.get_non_essential_params("mock") CI = CarInterface(CP, CarController, CarState) self.controlsd = Controls(CI=CI) diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index b40c8e304c..71c7b34be5 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -51,7 +51,7 @@ def cycle_alerts(duration=200, is_metric=False): cameras = ['roadCameraState', 'wideRoadCameraState', 'driverCameraState'] CS = car.CarState.new_message() - CP = CarInterface.get_params("HONDA CIVIC 2016") + CP = CarInterface.get_non_essential_params("HONDA CIVIC 2016") sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', 'managerState'] + cameras) diff --git a/selfdrive/debug/internal/test_paramsd.py b/selfdrive/debug/internal/test_paramsd.py index 3d8e422c35..81524496f7 100755 --- a/selfdrive/debug/internal/test_paramsd.py +++ b/selfdrive/debug/internal/test_paramsd.py @@ -20,7 +20,7 @@ T_SIM = 5 * 60 # s DT = 0.01 -CP = CarInterface.get_params(CAR.CIVIC) +CP = CarInterface.get_non_essential_params(CAR.CIVIC) VM = VehicleModel(CP) x, y = 0, 0 # m, m diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index 59cb0e1fe3..bd0556aa07 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -49,7 +49,7 @@ class Plant: from selfdrive.car.honda.values import CAR from selfdrive.car.honda.interface import CarInterface - self.planner = LongitudinalPlanner(CarInterface.get_params(CAR.CIVIC), init_v=self.speed) + self.planner = LongitudinalPlanner(CarInterface.get_non_essential_params(CAR.CIVIC), init_v=self.speed) @property def current_time(self): diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index c5465fc025..22ec099285 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -180,7 +180,7 @@ def fingerprint(msgs, fsm, can_sock, fingerprint): def get_car_params(msgs, fsm, can_sock, fingerprint): if fingerprint: CarInterface, _, _ = interfaces[fingerprint] - CP = CarInterface.get_params(fingerprint) + CP = CarInterface.get_non_essential_params(fingerprint) else: can = FakeSocket(wait=False) sendcan = FakeSocket(wait=False) From 97b931a12ae94567062891586496e7a73bd3ebbd Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 13 Jan 2023 03:27:20 +0800 Subject: [PATCH 0612/1179] cabana: fix chart glitches (#26928) --- tools/cabana/chartswidget.cc | 8 ++++++-- tools/cabana/chartswidget.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index cf01533aaa..952ed2d83f 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -47,6 +47,10 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QApplication::style()->standardPalette().color(QPalette::Background).value(); updateToolBar(); + align_charts_timer = new QTimer(this); + align_charts_timer->setSingleShot(true); + align_charts_timer->callOnTimeout(this, &ChartsWidget::alignCharts); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &CANMessages::updated, this, &ChartsWidget::updateState); @@ -159,7 +163,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); - QObject::connect(chart, &ChartView::axisYUpdated, this, &ChartsWidget::alignCharts); + QObject::connect(chart, &ChartView::axisYUpdated, [this]() { align_charts_timer->start(100); }); charts_layout->insertWidget(0, chart); charts.push_back(chart); } @@ -453,7 +457,7 @@ void ChartView::updateAxisY() { double range = max_y - min_y; applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05); } - QTimer::singleShot(0, this, &ChartView::axisYUpdated); + emit axisYUpdated(); } void ChartView::applyNiceNumbers(qreal min, qreal max) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 7a8325382d..819432920b 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -111,6 +112,7 @@ private: QAction *dock_btn; QAction *reset_zoom_btn; QAction *remove_all_btn; + QTimer *align_charts_timer; QVBoxLayout *charts_layout; QList charts; uint32_t max_chart_range = 0; From f14deae475f32af5b04fc2ef3744a77445ad8177 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 12 Jan 2023 11:28:04 -0800 Subject: [PATCH 0613/1179] Revert "Car interface: require fingerprint and FW versions to get params (#26766)" This reverts commit b68dabb689104ef0819a6c881b800076deb866f6. --- selfdrive/car/docs.py | 2 +- selfdrive/car/interfaces.py | 13 ++++++------- selfdrive/car/tests/test_car_interfaces.py | 2 +- selfdrive/car/tests/test_fw_fingerprint.py | 2 +- selfdrive/controls/lib/tests/test_latcontrol.py | 2 +- selfdrive/controls/lib/tests/test_vehicle_model.py | 2 +- selfdrive/controls/tests/test_state_machine.py | 2 +- selfdrive/debug/cycle_alerts.py | 2 +- selfdrive/debug/internal/test_paramsd.py | 2 +- selfdrive/test/longitudinal_maneuvers/plant.py | 2 +- selfdrive/test/process_replay/process_replay.py | 2 +- 11 files changed, 16 insertions(+), 17 deletions(-) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index bc03619d0d..03313e2ff6 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -29,7 +29,7 @@ def get_all_car_info() -> List[CarInfo]: all_car_info: List[CarInfo] = [] footnotes = get_all_footnotes() for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items(): - CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=False) + CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")]) if CP.dashcamOnly or car_info is None: continue diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 7192f5252c..ad1fd22b90 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -88,14 +88,13 @@ class CarInterfaceBase(ABC): return ACCEL_MIN, ACCEL_MAX @classmethod - def get_non_essential_params(cls, candidate: str): - """ - Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints. - """ - return cls.get_params(candidate, gen_empty_fingerprint(), list(), False) + def get_params(cls, candidate: str, fingerprint: Optional[Dict[int, Dict[int, int]]] = None, car_fw: Optional[List[car.CarParams.CarFw]] = None, experimental_long: bool = False): + if fingerprint is None: + fingerprint = gen_empty_fingerprint() + + if car_fw is None: + car_fw = list() - @classmethod - def get_params(cls, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool): ret = CarInterfaceBase.get_std_params(candidate) ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index deb0454b9c..11e7be7f44 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -25,7 +25,7 @@ class TestCarInterfaces(unittest.TestCase): car_fw = [] - car_params = CarInterface.get_params(car_name, fingerprints, car_fw, experimental_long=False) + car_params = CarInterface.get_params(car_name, fingerprints, car_fw) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index e9f23145cd..2e43103852 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -67,7 +67,7 @@ class TestFwFingerprint(unittest.TestCase): blacklisted_addrs = (0x7c4, 0x7d0) # includes A/C ecu and an unknown ecu for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): - CP = interfaces[car_model][0].get_non_essential_params(car_model) + CP = interfaces[car_model][0].get_params(car_model) if CP.carName == 'subaru': for ecu in ecus.keys(): self.assertNotIn(ecu[1], blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})') diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py index 993774f719..f15ab2fa56 100755 --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -20,7 +20,7 @@ class TestLatControl(unittest.TestCase): @parameterized.expand([(HONDA.CIVIC, LatControlPID), (TOYOTA.RAV4, LatControlTorque), (TOYOTA.PRIUS, LatControlINDI), (NISSAN.LEAF, LatControlAngle)]) def test_saturation(self, car_name, controller): CarInterface, CarController, CarState = interfaces[car_name] - CP = CarInterface.get_non_essential_params(car_name) + CP = CarInterface.get_params(car_name) CI = CarInterface(CP, CarController, CarState) VM = VehicleModel(CP) diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py index 03d97a7e3f..3e08cb0aa0 100755 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -12,7 +12,7 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_sol, creat class TestVehicleModel(unittest.TestCase): def setUp(self): - CP = CarInterface.get_non_essential_params(CAR.CIVIC) + CP = CarInterface.get_params(CAR.CIVIC) self.VM = VehicleModel(CP) def test_round_trip_yaw_rate(self): diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index d5f468f214..8f263a98e7 100755 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -31,7 +31,7 @@ class TestStateMachine(unittest.TestCase): def setUp(self): CarInterface, CarController, CarState = interfaces["mock"] - CP = CarInterface.get_non_essential_params("mock") + CP = CarInterface.get_params("mock") CI = CarInterface(CP, CarController, CarState) self.controlsd = Controls(CI=CI) diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index 71c7b34be5..b40c8e304c 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -51,7 +51,7 @@ def cycle_alerts(duration=200, is_metric=False): cameras = ['roadCameraState', 'wideRoadCameraState', 'driverCameraState'] CS = car.CarState.new_message() - CP = CarInterface.get_non_essential_params("HONDA CIVIC 2016") + CP = CarInterface.get_params("HONDA CIVIC 2016") sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', 'managerState'] + cameras) diff --git a/selfdrive/debug/internal/test_paramsd.py b/selfdrive/debug/internal/test_paramsd.py index 81524496f7..3d8e422c35 100755 --- a/selfdrive/debug/internal/test_paramsd.py +++ b/selfdrive/debug/internal/test_paramsd.py @@ -20,7 +20,7 @@ T_SIM = 5 * 60 # s DT = 0.01 -CP = CarInterface.get_non_essential_params(CAR.CIVIC) +CP = CarInterface.get_params(CAR.CIVIC) VM = VehicleModel(CP) x, y = 0, 0 # m, m diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index bd0556aa07..59cb0e1fe3 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -49,7 +49,7 @@ class Plant: from selfdrive.car.honda.values import CAR from selfdrive.car.honda.interface import CarInterface - self.planner = LongitudinalPlanner(CarInterface.get_non_essential_params(CAR.CIVIC), init_v=self.speed) + self.planner = LongitudinalPlanner(CarInterface.get_params(CAR.CIVIC), init_v=self.speed) @property def current_time(self): diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 22ec099285..c5465fc025 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -180,7 +180,7 @@ def fingerprint(msgs, fsm, can_sock, fingerprint): def get_car_params(msgs, fsm, can_sock, fingerprint): if fingerprint: CarInterface, _, _ = interfaces[fingerprint] - CP = CarInterface.get_non_essential_params(fingerprint) + CP = CarInterface.get_params(fingerprint) else: can = FakeSocket(wait=False) sendcan = FakeSocket(wait=False) From b00bc4f57e2c9a3acb9e3b10528b7e30cbde43f1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 12 Jan 2023 12:25:24 -0800 Subject: [PATCH 0614/1179] Car interface: require fingerprint and FW versions to get params (#26932) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * require fingerprint and FW versions * add get_non_essential_params() * comment * all required * classmethod, need to allow subclasses to override _get_params * fix that * fix * fix * wrong fix 🤦 --- selfdrive/car/docs.py | 2 +- selfdrive/car/interfaces.py | 13 +++++++------ selfdrive/car/tests/test_car_interfaces.py | 2 +- selfdrive/car/tests/test_fw_fingerprint.py | 2 +- selfdrive/car/tests/test_lateral_limits.py | 2 +- selfdrive/controls/lib/tests/test_latcontrol.py | 2 +- selfdrive/controls/lib/tests/test_vehicle_model.py | 2 +- selfdrive/controls/tests/test_state_machine.py | 2 +- selfdrive/debug/cycle_alerts.py | 2 +- selfdrive/debug/internal/test_paramsd.py | 2 +- selfdrive/test/longitudinal_maneuvers/plant.py | 2 +- selfdrive/test/process_replay/process_replay.py | 2 +- 12 files changed, 18 insertions(+), 17 deletions(-) diff --git a/selfdrive/car/docs.py b/selfdrive/car/docs.py index 03313e2ff6..bc03619d0d 100755 --- a/selfdrive/car/docs.py +++ b/selfdrive/car/docs.py @@ -29,7 +29,7 @@ def get_all_car_info() -> List[CarInfo]: all_car_info: List[CarInfo] = [] footnotes = get_all_footnotes() for model, car_info in get_interface_attr("CAR_INFO", combine_brands=True).items(): - CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")]) + CP = interfaces[model][0].get_params(model, fingerprint=gen_empty_fingerprint(), car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=False) if CP.dashcamOnly or car_info is None: continue diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index ad1fd22b90..7192f5252c 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -88,13 +88,14 @@ class CarInterfaceBase(ABC): return ACCEL_MIN, ACCEL_MAX @classmethod - def get_params(cls, candidate: str, fingerprint: Optional[Dict[int, Dict[int, int]]] = None, car_fw: Optional[List[car.CarParams.CarFw]] = None, experimental_long: bool = False): - if fingerprint is None: - fingerprint = gen_empty_fingerprint() - - if car_fw is None: - car_fw = list() + def get_non_essential_params(cls, candidate: str): + """ + Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints. + """ + return cls.get_params(candidate, gen_empty_fingerprint(), list(), False) + @classmethod + def get_params(cls, candidate: str, fingerprint: Dict[int, Dict[int, int]], car_fw: List[car.CarParams.CarFw], experimental_long: bool): ret = CarInterfaceBase.get_std_params(candidate) ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 11e7be7f44..deb0454b9c 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -25,7 +25,7 @@ class TestCarInterfaces(unittest.TestCase): car_fw = [] - car_params = CarInterface.get_params(car_name, fingerprints, car_fw) + car_params = CarInterface.get_params(car_name, fingerprints, car_fw, experimental_long=False) car_interface = CarInterface(car_params, CarController, CarState) assert car_params assert car_interface diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py index 2e43103852..e9f23145cd 100755 --- a/selfdrive/car/tests/test_fw_fingerprint.py +++ b/selfdrive/car/tests/test_fw_fingerprint.py @@ -67,7 +67,7 @@ class TestFwFingerprint(unittest.TestCase): blacklisted_addrs = (0x7c4, 0x7d0) # includes A/C ecu and an unknown ecu for car_model, ecus in FW_VERSIONS.items(): with self.subTest(car_model=car_model): - CP = interfaces[car_model][0].get_params(car_model) + CP = interfaces[car_model][0].get_non_essential_params(car_model) if CP.carName == 'subaru': for ecu in ecus.keys(): self.assertNotIn(ecu[1], blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})') diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index a82c20ce01..3efdd7404e 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -40,7 +40,7 @@ class TestLateralLimits(unittest.TestCase): @classmethod def setUpClass(cls): CarInterface, _, _ = interfaces[cls.car_model] - CP = CarInterface.get_params(cls.car_model) + CP = CarInterface.get_non_essential_params(cls.car_model) if CP.dashcamOnly: raise unittest.SkipTest("Platform is behind dashcamOnly") diff --git a/selfdrive/controls/lib/tests/test_latcontrol.py b/selfdrive/controls/lib/tests/test_latcontrol.py index f15ab2fa56..993774f719 100755 --- a/selfdrive/controls/lib/tests/test_latcontrol.py +++ b/selfdrive/controls/lib/tests/test_latcontrol.py @@ -20,7 +20,7 @@ class TestLatControl(unittest.TestCase): @parameterized.expand([(HONDA.CIVIC, LatControlPID), (TOYOTA.RAV4, LatControlTorque), (TOYOTA.PRIUS, LatControlINDI), (NISSAN.LEAF, LatControlAngle)]) def test_saturation(self, car_name, controller): CarInterface, CarController, CarState = interfaces[car_name] - CP = CarInterface.get_params(car_name) + CP = CarInterface.get_non_essential_params(car_name) CI = CarInterface(CP, CarController, CarState) VM = VehicleModel(CP) diff --git a/selfdrive/controls/lib/tests/test_vehicle_model.py b/selfdrive/controls/lib/tests/test_vehicle_model.py index 3e08cb0aa0..03d97a7e3f 100755 --- a/selfdrive/controls/lib/tests/test_vehicle_model.py +++ b/selfdrive/controls/lib/tests/test_vehicle_model.py @@ -12,7 +12,7 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_sol, creat class TestVehicleModel(unittest.TestCase): def setUp(self): - CP = CarInterface.get_params(CAR.CIVIC) + CP = CarInterface.get_non_essential_params(CAR.CIVIC) self.VM = VehicleModel(CP) def test_round_trip_yaw_rate(self): diff --git a/selfdrive/controls/tests/test_state_machine.py b/selfdrive/controls/tests/test_state_machine.py index 8f263a98e7..d5f468f214 100755 --- a/selfdrive/controls/tests/test_state_machine.py +++ b/selfdrive/controls/tests/test_state_machine.py @@ -31,7 +31,7 @@ class TestStateMachine(unittest.TestCase): def setUp(self): CarInterface, CarController, CarState = interfaces["mock"] - CP = CarInterface.get_params("mock") + CP = CarInterface.get_non_essential_params("mock") CI = CarInterface(CP, CarController, CarState) self.controlsd = Controls(CI=CI) diff --git a/selfdrive/debug/cycle_alerts.py b/selfdrive/debug/cycle_alerts.py index b40c8e304c..71c7b34be5 100755 --- a/selfdrive/debug/cycle_alerts.py +++ b/selfdrive/debug/cycle_alerts.py @@ -51,7 +51,7 @@ def cycle_alerts(duration=200, is_metric=False): cameras = ['roadCameraState', 'wideRoadCameraState', 'driverCameraState'] CS = car.CarState.new_message() - CP = CarInterface.get_params("HONDA CIVIC 2016") + CP = CarInterface.get_non_essential_params("HONDA CIVIC 2016") sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration', 'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman', 'managerState'] + cameras) diff --git a/selfdrive/debug/internal/test_paramsd.py b/selfdrive/debug/internal/test_paramsd.py index 3d8e422c35..81524496f7 100755 --- a/selfdrive/debug/internal/test_paramsd.py +++ b/selfdrive/debug/internal/test_paramsd.py @@ -20,7 +20,7 @@ T_SIM = 5 * 60 # s DT = 0.01 -CP = CarInterface.get_params(CAR.CIVIC) +CP = CarInterface.get_non_essential_params(CAR.CIVIC) VM = VehicleModel(CP) x, y = 0, 0 # m, m diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index 59cb0e1fe3..bd0556aa07 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -49,7 +49,7 @@ class Plant: from selfdrive.car.honda.values import CAR from selfdrive.car.honda.interface import CarInterface - self.planner = LongitudinalPlanner(CarInterface.get_params(CAR.CIVIC), init_v=self.speed) + self.planner = LongitudinalPlanner(CarInterface.get_non_essential_params(CAR.CIVIC), init_v=self.speed) @property def current_time(self): diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index c5465fc025..22ec099285 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -180,7 +180,7 @@ def fingerprint(msgs, fsm, can_sock, fingerprint): def get_car_params(msgs, fsm, can_sock, fingerprint): if fingerprint: CarInterface, _, _ = interfaces[fingerprint] - CP = CarInterface.get_params(fingerprint) + CP = CarInterface.get_non_essential_params(fingerprint) else: can = FakeSocket(wait=False) sendcan = FakeSocket(wait=False) From 66d0d4c7d7035375bc17bdc9da404c2a5e77d453 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 13 Jan 2023 05:27:46 +0800 Subject: [PATCH 0615/1179] cabana: filtering in both address and msg name (#26929) search in address and name Co-authored-by: Shane Smiskol --- tools/cabana/messageswidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index dbf87a3da2..a5224e108b 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -80,11 +80,11 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { void MessageListModel::setFilterString(const QString &string) { filter_str = string; - bool search_id = filter_str.contains(':'); msgs.clear(); for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { - if ((search_id ? it.key() : msgName(it.key())).contains(filter_str, Qt::CaseInsensitive)) + if (it.key().contains(filter_str, Qt::CaseInsensitive) || msgName(it.key()).contains(filter_str, Qt::CaseInsensitive)) { msgs.push_back(it.key()); + } } sortMessages(); } From 53ec07edbd591296602658080df71d91e8629540 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 13 Jan 2023 05:39:51 +0800 Subject: [PATCH 0616/1179] cabana: double click on an item in FindSimilarBitsDlg to open the message in detailView (#26930) * double click to open message * remove qDebug --- tools/cabana/mainwin.cc | 1 + tools/cabana/messageswidget.cc | 11 +++++++---- tools/cabana/messageswidget.h | 2 ++ tools/cabana/tools/findsimilarbits.cc | 8 +++++++- tools/cabana/tools/findsimilarbits.h | 5 +++++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 43aa330029..46ef8f10f9 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -281,5 +281,6 @@ void MainWindow::setOption() { void MainWindow::findSimilarBits() { FindSimilarBitsDlg dlg(this); + QObject::connect(&dlg, &FindSimilarBitsDlg::openMessage, messages_widget, &MessagesWidget::selectMessage); dlg.exec(); } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index a5224e108b..fd0bc68514 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -39,6 +39,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); + QObject::connect(model, &MessageListModel::modelReset, [this]() { selectMessage(current_msg_id); }); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid() && current.row() < model->msgs.size()) { if (model->msgs[current.row()] != current_msg_id) { @@ -47,10 +48,12 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { } } }); - QObject::connect(model, &MessageListModel::modelReset, [this]() { - if (int row = model->msgs.indexOf(current_msg_id); row != -1) - table_widget->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); - }); +} + +void MessagesWidget::selectMessage(const QString &msg_id) { + if (int row = model->msgs.indexOf(msg_id); row != -1) { + table_widget->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); + } } // MessageListModel diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 3a42bed4be..62aa23c02e 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -31,6 +31,8 @@ class MessagesWidget : public QWidget { public: MessagesWidget(QWidget *parent); + void selectMessage(const QString &message_id); + signals: void msgSelectionChanged(const QString &message_id); diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index cb5dbc0845..5c9623c7e4 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -59,12 +59,19 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent) { main_layout->addLayout(form_layout); table = new QTableWidget(this); + table->setSelectionBehavior(QAbstractItemView::SelectRows); + table->setSelectionMode(QAbstractItemView::SingleSelection); table->setEditTriggers(QAbstractItemView::NoEditTriggers); table->horizontalHeader()->setStretchLastSection(true); main_layout->addWidget(table); setMinimumSize({700, 500}); QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); + QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) { + if (index.isValid()) { + emit openMessage(bus_combo->currentText() + ":" + table->item(index.row(), 0)->text()); + } + }); } void FindSimilarBitsDlg::find() { @@ -91,7 +98,6 @@ QList FindSimilarBitsDlg::calcBits(uint8_ QHash> mismatches; QHash msg_count; auto events = can->events(); - qDebug() << bus << selected_address << byte_idx << bit_idx; int bit_to_find = -1; for (auto e : *events) { if (e->which == cereal::Event::Which::CAN) { diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 8083999909..30d78f0dea 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -7,9 +7,14 @@ #include class FindSimilarBitsDlg : public QDialog { + Q_OBJECT + public: FindSimilarBitsDlg(QWidget *parent); +signals: + void openMessage(const QString &msg_id); + private: struct mismatched_struct { uint32_t address, byte_idx, bit_idx, mismatches, total; From df394004d574d0c9c63216da56bc965da27af508 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 12 Jan 2023 14:58:47 -0800 Subject: [PATCH 0617/1179] red panda footnote: finish thought (#26933) missing `car` --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 1b76069f6a..1e862a2f45 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -237,7 +237,7 @@ A supported vehicle is one that just works when you install a comma three. All s 2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-5Requires a red panda for this CAN FD. All the hardware needed is sold in the CAN FD kit.
+5Requires a red panda for this CAN FD car. All the hardware needed is sold in the CAN FD kit.
6openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
7Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
8Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 229ca992d5..34c66623c3 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -125,7 +125,7 @@ class CAR: class Footnote(Enum): # footnotes which mention "red panda" will be replaced with the CAN FD panda kit on the shop page CANFD = CarFootnote( - "Requires a red panda for this CAN FD. " + + "Requires a red panda for this CAN FD car. " + "All the hardware needed is sold in the CAN FD kit.", Column.MODEL, shop_footnote=True) From 47cca343ec6ae611871d53d7b0660647f816f1c9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 12 Jan 2023 15:07:14 -0800 Subject: [PATCH 0618/1179] docs: open footnotes in new tab --- docs/CARS.md | 4 ++-- selfdrive/car/gm/values.py | 2 +- selfdrive/car/hyundai/values.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 1e862a2f45..48145d78a9 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -235,9 +235,9 @@ A supported vehicle is one that just works when you install a comma three. All s 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
2By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).
-3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
+3Requires a community built ASCM harness. NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).
42019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph.
-5Requires a red panda for this CAN FD car. All the hardware needed is sold in the CAN FD kit.
+5Requires a red panda for this CAN FD car. All the hardware needed is sold in the CAN FD kit.
6openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
7Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform.
8Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets.
diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index ece128c253..e633ec5f62 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -75,7 +75,7 @@ class CAR: class Footnote(Enum): OBD_II = CarFootnote( - 'Requires a community built ASCM harness. ' + + 'Requires a community built ASCM harness. ' + 'NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).', Column.MODEL) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 34c66623c3..eace661266 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -125,8 +125,8 @@ class CAR: class Footnote(Enum): # footnotes which mention "red panda" will be replaced with the CAN FD panda kit on the shop page CANFD = CarFootnote( - "Requires a red panda for this CAN FD car. " + - "All the hardware needed is sold in the CAN FD kit.", + "Requires a red panda for this CAN FD car. " + + "All the hardware needed is sold in the CAN FD kit.", Column.MODEL, shop_footnote=True) From 8aac07bf86897ff9dee8f82ddd361fe39aed5063 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 12 Jan 2023 15:20:37 -0800 Subject: [PATCH 0619/1179] model replay: disable nav for now --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f49ccf4315..3b16b3f112 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -190,7 +190,7 @@ pipeline { steps { phone_steps("tici-common", [ ["build", "cd selfdrive/manager && ./build.py"], - ["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], + ["model replay", "cd selfdrive/test/process_replay && NO_NAV=1 ./model_replay.py"], ]) } } From 1d91913aae95fceade6afd7c808e2188ce6e2985 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 13 Jan 2023 14:21:51 -0500 Subject: [PATCH 0620/1179] Hyundai: Add FW Version for 2021 Sonata N Line (#26945) * Hyundai: Add FW Version for 2021 Sonata N Line * missing engine Co-authored-by: Shane Smiskol --- 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 eace661266..c4fda42b63 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -516,6 +516,7 @@ FW_VERSIONS = { b'HM6M2_0a0_BD0', b'\xf1\x8739110-2S278\xf1\x82DNDVD5GMCCXXXL5B', b'\xf1\x8739110-2S041\xf1\x81HM6M1_0a0_M00', + b'\xf1\x81HM6M1_0a0_G20', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00DN8 MDPS C 1,00 1,01 56310L0010\x00 4DNAC101', # modified firmware @@ -606,6 +607,7 @@ FW_VERSIONS = { b'\xf1\x87SALFBA7460044GJ2gx\x87\x88Vf\x86hx\x88\x87\x88wwwwgw\x86wd?\xfa\xff\x86U_\xff\xaf\x1f\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', b'\xf1\x87SAMFBA8105254GJ2wx\x87\x88Vf\x86hx\x88\x87\x88wwwwwwww\x86O\xfa\xff\x99\x88\x7f\xffZG\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', b'\xf1\x87SANFB45889451GC7wx\x87\x88gw\x87x\x88\x88x\x88\x87wxw\x87wxw\x87\x8f\xfc\xffeU\x8f\xff+Q\xf1\x81U913\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00SDN8T16NB2\n\xdd^\xbc', + b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSA\xb9\x13\xf9p', ], }, CAR.SONATA_LF: { From aaed3537780b5082d427667d6ab4070db2e7e21f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 14 Jan 2023 03:33:03 +0800 Subject: [PATCH 0621/1179] cabana: use Qt::Window flag for FindSimilarBitsDlg (#26938) use Qt::Window flag for FindSimilarBitsDlg --- tools/cabana/mainwin.cc | 6 +++--- tools/cabana/tools/findsimilarbits.cc | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 46ef8f10f9..9df5894b90 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -280,7 +280,7 @@ void MainWindow::setOption() { } void MainWindow::findSimilarBits() { - FindSimilarBitsDlg dlg(this); - QObject::connect(&dlg, &FindSimilarBitsDlg::openMessage, messages_widget, &MessagesWidget::selectMessage); - dlg.exec(); + FindSimilarBitsDlg *dlg = new FindSimilarBitsDlg(this); + QObject::connect(dlg, &FindSimilarBitsDlg::openMessage, messages_widget, &MessagesWidget::selectMessage); + dlg->show(); } diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 5c9623c7e4..8a05e3e236 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -10,8 +10,10 @@ #include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" -FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent) { +FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) { setWindowTitle(tr("Find similar bits")); + setAttribute(Qt::WA_DeleteOnClose); + QVBoxLayout *main_layout = new QVBoxLayout(this); QHBoxLayout *form_layout = new QHBoxLayout(); From 88423e25df8bfbd8e6a3275eb086f468cf9a59f1 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 13 Jan 2023 12:37:38 -0700 Subject: [PATCH 0622/1179] Laikad: set active (#26850) * laikad update, renaming * update locationd * fix naming * address PR comments * upsi * . * draft to fix replay * fix process relay to allow no response for messages * final fix for process replay * . * bump cereal * update process replay ref commit * reduce wait time * . * last ref change * move laikad helpers to laika * . * fix ublox test * update refs * add proper qcom replay support * fix gnss support if both is available * update refs * remove left over * revert laikad msg * move laika back to master * init * fix gps valid flag * change time * add gnss to ignore * remove gps_valid flag * . * adopt orientation reset threshold * . * update laikad * . * fix stanstill KF resets * test orienation reset count * update laika * bump cereal * fix process replay * update laika repo * remove handle gps * add extra logging for cache * . * add more log * . * . * update laika * dont remove gps code * inc min satellite count * update magic vals and add acc drop * update laika * upsi * rem * bump laika * use nav and correct * more fixes * use sftp * No more glonass * Revert "No more glonass" This reverts commit a76124da50a1e25f423ad1137c7a046e1d57811d. * nump laika * back support old ephemeris cache * add health to ephemeris message * bump laika * remove print * fix laikad tests * clean * remove extra log * bump laika * inc timeout for plotjuggler build * rem cache clear * . * enable gps after checks Co-authored-by: Kurt Nistelberger Co-authored-by: Bruce Wayne Co-authored-by: Shane Smiskol --- .github/workflows/tools_tests.yaml | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 85 +++++++------- selfdrive/locationd/liblocationd.cc | 4 +- selfdrive/locationd/locationd.cc | 71 ++++++------ selfdrive/locationd/locationd.h | 6 +- .../locationd/test/_test_locationd_lib.py | 4 +- selfdrive/locationd/test/test_laikad.py | 104 +++++++++--------- selfdrive/locationd/test/test_locationd.py | 36 +++--- selfdrive/locationd/ublox_msg.cc | 1 + .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 12 files changed, 169 insertions(+), 150 deletions(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 94cc3c2580..7ad0ce35b1 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -38,7 +38,7 @@ jobs: - name: Build Docker image run: eval "$BUILD" - name: Unit test - timeout-minutes: 2 + timeout-minutes: 6 run: | ${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \ apt-get update && \ diff --git a/laika_repo b/laika_repo index 5eb0c3c259..73bf110ae0 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 5eb0c3c2596dd12a232b83bdb057a716810e89cf +Subproject commit 73bf110ae0093ad86755bf5eb6a03e46ff5c239d diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 1f13c2b69a..b8d86c63fd 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -3,6 +3,7 @@ import json import math import os import time +import shutil from collections import defaultdict from concurrent.futures import Future, ProcessPoolExecutor from datetime import datetime @@ -29,17 +30,17 @@ from system.swaglog import cloudlog MAX_TIME_GAP = 10 EPHEMERIS_CACHE = 'LaikadEphemeris' DOWNLOADS_CACHE_FOLDER = "/tmp/comma_download_cache/" -CACHE_VERSION = 0.1 +CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 class Laikad: - def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_orbits=True, auto_update=False, - valid_ephem_types=(EphemerisType.ULTRA_RAPID_ORBIT, EphemerisType.NAV), + def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, + valid_ephem_types=(EphemerisType.NAV,), save_ephemeris=False, use_qcom=False): """ valid_const: GNSS constellation which can be used - auto_fetch_orbits: If true fetch orbits from internet when needed + auto_fetch_navs: If true fetch navs from internet when needed auto_update: If true download AstroDog will download all files needed. This can be ephemeris or correction data like ionosphere. valid_ephem_types: Valid ephemeris types to be used by AstroDog save_ephemeris: If true saves and loads nav and orbit ephemeris to cache. @@ -47,11 +48,11 @@ class Laikad: self.astro_dog = AstroDog(valid_const=valid_const, auto_update=auto_update, valid_ephem_types=valid_ephem_types, clear_old_ephemeris=True, cache_dir=DOWNLOADS_CACHE_FOLDER) self.gnss_kf = GNSSKalman(GENERATED_DIR, cython=True, erratic_clock=use_qcom) - self.auto_fetch_orbits = auto_fetch_orbits + self.auto_fetch_navs = auto_fetch_navs self.orbit_fetch_executor: Optional[ProcessPoolExecutor] = None self.orbit_fetch_future: Optional[Future] = None - self.last_fetch_orbits_t = None + self.last_fetch_navs_t = None self.got_first_gnss_msg = False self.last_cached_t = None self.save_ephemeris = save_ephemeris @@ -74,29 +75,30 @@ class Laikad: try: cache = json.loads(cache, object_hook=deserialize_hook) - self.astro_dog.add_orbits(cache['orbits']) - self.astro_dog.add_navs(cache['nav']) - self.last_fetch_orbits_t = cache['last_fetch_orbits_t'] + if cache['version'] == CACHE_VERSION: + self.astro_dog.add_navs(cache['navs']) + self.last_fetch_navs_t = cache['last_fetch_navs_t'] + else: + cache['navs'] = {} except json.decoder.JSONDecodeError: cloudlog.exception("Error parsing cache") - timestamp = self.last_fetch_orbits_t.as_datetime() if self.last_fetch_orbits_t is not None else 'Nan' + timestamp = self.last_fetch_navs_t.as_datetime() if self.last_fetch_navs_t is not None else 'Nan' cloudlog.debug( - f"Loaded nav ({sum([len(v) for v in cache['nav']])}) and orbits ({sum([len(v) for v in cache['orbits']])}) cache with timestamp: {timestamp}. Unique orbit and nav sats: {list(cache['orbits'].keys())} {list(cache['nav'].keys())} " + - f"With time range: {[f'{start.as_datetime()}, {end.as_datetime()}' for (start,end) in self.astro_dog.orbit_fetched_times._ranges]}") + f"Loaded navs ({sum([len(v) for v in cache['navs']])}) cache with timestamp: {timestamp}. Unique orbit and nav sats: {list(cache['navs'].keys())} " + + f"With time range: {[f'{start.as_datetime()}, {end.as_datetime()}' for (start,end) in self.astro_dog.navs_fetched_times._ranges]}") def cache_ephemeris(self, t: GPSTime): if self.save_ephemeris and (self.last_cached_t is None or t - self.last_cached_t > SECS_IN_MIN): put_nonblocking(EPHEMERIS_CACHE, json.dumps( - {'version': CACHE_VERSION, 'last_fetch_orbits_t': self.last_fetch_orbits_t, 'orbits': self.astro_dog.orbits, 'nav': self.astro_dog.nav}, + {'version': CACHE_VERSION, 'last_fetch_navs_t': self.last_fetch_navs_t, 'navs': self.astro_dog.navs}, cls=CacheSerializer)) cloudlog.debug("Cache saved") self.last_cached_t = t def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: - min_measurements = 6 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 5 + min_measurements = 7 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 6 position_solution, pr_residuals = calc_pos_fix(measurements, self.posfix_functions, min_measurements=min_measurements) - if len(position_solution) < 3: return None position_estimate = position_solution[:3] @@ -155,8 +157,13 @@ class Laikad: # Filter measurements with unexpected pseudoranges for GPS and GLONASS satellites new_meas = [m for m in new_meas if 1e7 < m.observables['C1C'] < 3e7] processed_measurements = process_measurements(new_meas, self.astro_dog) - - instant_fix = self.get_lsq_fix(t, processed_measurements) + if self.last_fix_pos is not None: + corrected_measurements = correct_measurements(processed_measurements, self.last_fix_pos, self.astro_dog) + instant_fix = self.get_lsq_fix(t, corrected_measurements) + #instant_fix = self.get_lsq_fix(t, processed_measurements) + else: + corrected_measurements = [] + instant_fix = self.get_lsq_fix(t, processed_measurements) if instant_fix is None: return None else: @@ -164,8 +171,6 @@ class Laikad: self.last_fix_t = t self.last_fix_pos = position_estimate self.lat_fix_pos_std = position_std - - corrected_measurements = correct_measurements(processed_measurements, position_estimate, self.astro_dog) if (t*1e9) % 10 == 0: cloudlog.debug(f"Measurements Incoming/Processed/Corrected: {len(new_meas), len(processed_measurements), len(corrected_measurements)}") return position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, processed_measurements @@ -185,8 +190,8 @@ class Laikad: if week > 0: self.got_first_gnss_msg = True latest_msg_t = GPSTime(week, tow) - if self.auto_fetch_orbits: - self.fetch_orbits(latest_msg_t, block) + if self.auto_fetch_navs: + self.fetch_navs(latest_msg_t, block) output = self.process_report(new_meas, t) if output is None: @@ -254,9 +259,9 @@ class Laikad: p_initial_diag[GStates.ECEF_POS] = 1000 ** 2 self.gnss_kf.init_state(x_initial, covs_diag=p_initial_diag) - def fetch_orbits(self, t: GPSTime, block): - # Download new orbits if 1 hour of orbits data left - if t + SECS_IN_HR not in self.astro_dog.orbit_fetched_times and (self.last_fetch_orbits_t is None or abs(t - self.last_fetch_orbits_t) > SECS_IN_MIN): + def fetch_navs(self, t: GPSTime, block): + # Download new navs if 1 hour of navs data left + if t + SECS_IN_HR not in self.astro_dog.navs_fetched_times and (self.last_fetch_navs_t is None or abs(t - self.last_fetch_navs_t) > SECS_IN_MIN): astro_dog_vars = self.astro_dog.valid_const, self.astro_dog.auto_update, self.astro_dog.valid_ephem_types, self.astro_dog.cache_dir ret = None @@ -271,22 +276,22 @@ class Laikad: if ret is not None: if ret[0] is None: - self.last_fetch_orbits_t = ret[2] + self.last_fetch_navs_t = ret[2] else: - self.astro_dog.orbits, self.astro_dog.orbit_fetched_times, self.last_fetch_orbits_t = ret + self.astro_dog.navs, self.astro_dog.navs_fetched_times, self.last_fetch_navs_t = ret self.cache_ephemeris(t=t) def get_orbit_data(t: GPSTime, valid_const, auto_update, valid_ephem_types, cache_dir): astro_dog = AstroDog(valid_const=valid_const, auto_update=auto_update, valid_ephem_types=valid_ephem_types, cache_dir=cache_dir) - cloudlog.info(f"Start to download/parse orbits for time {t.as_datetime()}") + cloudlog.info(f"Start to download/parse navs for time {t.as_datetime()}") start_time = time.monotonic() try: - astro_dog.get_orbit_data(t, only_predictions=True) - cloudlog.info(f"Done parsing orbits. Took {time.monotonic() - start_time:.1f}s") - cloudlog.debug(f"Downloaded orbits ({sum([len(v) for v in astro_dog.orbits])}): {list(astro_dog.orbits.keys())}" + + astro_dog.get_navs(t) + cloudlog.info(f"Done parsing navs. Took {time.monotonic() - start_time:.1f}s") + cloudlog.debug(f"Downloaded navs ({sum([len(v) for v in astro_dog.navs])}): {list(astro_dog.navs.keys())}" + f"With time range: {[f'{start.as_datetime()}, {end.as_datetime()}' for (start,end) in astro_dog.orbit_fetched_times._ranges]}") - return astro_dog.orbits, astro_dog.orbit_fetched_times, t + return astro_dog.navs, astro_dog.navs_fetched_times, t except (DownloadFailed, RuntimeError, ValueError, IOError) as e: cloudlog.warning(f"No orbit data found or parsing failure: {e}") return None, None, t @@ -385,7 +390,15 @@ def process_msg(laikad, gnss_msg, mono_time, block=False): return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) +def clear_tmp_cache(): + if os.path.exists(DOWNLOADS_CACHE_FOLDER): + shutil.rmtree(DOWNLOADS_CACHE_FOLDER) + os.mkdir(DOWNLOADS_CACHE_FOLDER) + + def main(sm=None, pm=None, qc=None): + #clear_tmp_cache() + use_qcom = not Params().get_bool("UbloxAvailable", block=True) if use_qcom or (qc is not None and qc): raw_gnss_socket = "qcomGnss" @@ -399,7 +412,7 @@ def main(sm=None, pm=None, qc=None): replay = "REPLAY" in os.environ use_internet = "LAIKAD_NO_INTERNET" not in os.environ - laikad = Laikad(save_ephemeris=not replay, auto_fetch_orbits=use_internet, use_qcom=use_qcom) + laikad = Laikad(save_ephemeris=not replay, auto_fetch_navs=use_internet, use_qcom=use_qcom) while True: sm.update() @@ -409,17 +422,15 @@ def main(sm=None, pm=None, qc=None): msg = process_msg(laikad, gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) if msg is None: + # TODO: beautify this, locationd needs a valid message msg = messaging.new_message("gnssMeasurements") - msg.valid = False - pm.send('gnssMeasurements', msg) if not laikad.got_first_gnss_msg and sm.updated['clocks']: clocks_msg = sm['clocks'] t = GPSTime.from_datetime(datetime.utcfromtimestamp(clocks_msg.wallTimeNanos * 1E-9)) - if laikad.auto_fetch_orbits: - laikad.fetch_orbits(t, block=replay) - + if laikad.auto_fetch_navs: + laikad.fetch_navs(t, block=replay) if __name__ == "__main__": main() diff --git a/selfdrive/locationd/liblocationd.cc b/selfdrive/locationd/liblocationd.cc index da57fb7ff4..32fec7724a 100755 --- a/selfdrive/locationd/liblocationd.cc +++ b/selfdrive/locationd/liblocationd.cc @@ -3,8 +3,8 @@ extern "C" { typedef Localizer* Localizer_t; - Localizer *localizer_init() { - return new Localizer(); + Localizer *localizer_init(bool has_ublox) { + return new Localizer(has_ublox); } void localizer_get_message_bytes(Localizer *localizer, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid, diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 442adcd347..928e19081e 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -30,10 +30,11 @@ const double GPS_UBLOX_SENSOR_TIME_OFFSET = 0.095; // s const float GPS_MUL_FACTOR = 10.0; const float GPS_POS_STD_THRESHOLD = 50.0; const float GPS_VEL_STD_THRESHOLD = 5.0; -const float GPS_POS_ERROR_RESET_THRESHOLD = 200.0; -const float GPS_POS_STD_RESET_THRESHOLD = 5.0; +const float GPS_POS_ERROR_RESET_THRESHOLD = 300.0; +const float GPS_POS_STD_RESET_THRESHOLD = 2.0; const float GPS_VEL_STD_RESET_THRESHOLD = 0.5; -const float GPS_ORIENTATION_ERROR_RESET_THRESHOLD = 5.0; +const float GPS_ORIENTATION_ERROR_RESET_THRESHOLD = 1.0; +const int GPS_ORIENTATION_ERROR_RESET_CNT = 3; static VectorXd floatlist2vector(const capnp::List::Reader& floatlist) { VectorXd res(floatlist.size()); @@ -84,6 +85,8 @@ Localizer::Localizer() { this->converter = std::make_unique((ECEF) { .x = ecef_pos[0], .y = ecef_pos[1], .z = ecef_pos[2] }); } +Localizer::Localizer(bool has_ublox) : Localizer() { ublox_available = has_ublox; } + void Localizer::build_live_location(cereal::LiveLocationKalman::Builder& fix) { VectorXd predicted_state = this->kf->get_x(); MatrixXdr predicted_cov = this->kf->get_P(); @@ -227,7 +230,7 @@ void Localizer::handle_sensor(double current_time, const cereal::SensorEventData } double sensor_time = 1e-9 * log.getTimestamp(); - + // sensor time and log time should be close if (std::abs(current_time - sensor_time) > 0.1) { LOGE("Sensor reading ignored, sensor timestamp more than 100ms off from log time"); @@ -308,7 +311,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R } if (gps_invalid_flag || gps_unreasonable || gps_accuracy_insane || gps_lat_lng_alt_insane || gps_vel_insane || gps_accuracy_insane_quectel) { - this->gps_valid = false; + //this->gps_valid = false; this->determine_gps_mode(current_time); return; } @@ -316,7 +319,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R double sensor_time = current_time - sensor_time_offset; // Process message - this->gps_valid = true; + //this->gps_valid = true; this->gps_mode = true; Geodetic geodetic = { log.getLatitude(), log.getLongitude(), log.getAltitude() }; this->converter = std::make_unique(geodetic); @@ -357,12 +360,10 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R void Localizer::handle_gnss(double current_time, const cereal::GnssMeasurements::Reader& log) { - this->gps_valid = log.getPositionECEF().getValid() && log.getVelocityECEF().getValid(); - if (!this->gps_valid) { + if(!log.getPositionECEF().getValid() || !log.getVelocityECEF().getValid()) { this->determine_gps_mode(current_time); return; } - this->gps_mode = true; double sensor_time = log.getMeasTime() * 1e-9; if (ublox_available) @@ -406,29 +407,42 @@ void Localizer::handle_gnss(double current_time, const cereal::GnssMeasurements: VectorXd initial_pose_ecef_quat = quat2vector(euler2quat(ecef_euler_from_ned({ ecef_pos(0), ecef_pos(1), ecef_pos(2) }, orientation_ned_gps))); if (ecef_pos_std > GPS_POS_STD_THRESHOLD || ecef_vel_std > GPS_VEL_STD_THRESHOLD) { - this->gps_valid = false; this->determine_gps_mode(current_time); return; } + // prevent jumping gnss measurements (covered lots, standstill...) + bool orientation_reset = ecef_vel_std < GPS_VEL_STD_RESET_THRESHOLD; + orientation_reset &= orientation_error.norm() > GPS_ORIENTATION_ERROR_RESET_THRESHOLD; + orientation_reset &= !this->standstill; + if (orientation_reset) { + this->orientation_reset_count++; + } + else { + this->orientation_reset_count = 0; + } + if ((gps_est_error > GPS_POS_ERROR_RESET_THRESHOLD && ecef_pos_std < GPS_POS_STD_RESET_THRESHOLD) || this->last_gps_msg == 0) { // always reset on first gps message and if the location is off but the accuracy is high LOGE("Locationd vs gnssMeasurement position difference too large, kalman reset"); this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); - } else if (ecef_vel_std < GPS_VEL_STD_RESET_THRESHOLD && orientation_error.norm() > GPS_ORIENTATION_ERROR_RESET_THRESHOLD) { + } else if (orientation_reset_count > GPS_ORIENTATION_ERROR_RESET_CNT) { LOGE("Locationd vs gnssMeasurement orientation difference too large, kalman reset"); this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_ORIENTATION_FROM_GPS, { initial_pose_ecef_quat }); + this->orientation_reset_count = 0; } - this->last_gps_msg = current_time; + this->gps_mode = true; + this->last_gps_msg = sensor_time; this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_POS, { ecef_pos }, { ecef_pos_R }); this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); } void Localizer::handle_car_state(double current_time, const cereal::CarState::Reader& log) { this->car_speed = std::abs(log.getVEgo()); - if (log.getStandstill()) { + this->standstill = log.getStandstill(); + if (this->standstill) { this->kf->predict_and_observe(current_time, OBSERVATION_NO_ROT, { Vector3d(0.0, 0.0, 0.0) }); this->kf->predict_and_observe(current_time, OBSERVATION_NO_ACCEL, { Vector3d(0.0, 0.0, 0.0) }); } @@ -437,7 +451,7 @@ void Localizer::handle_car_state(double current_time, const cereal::CarState::Re void Localizer::handle_cam_odo(double current_time, const cereal::CameraOdometry::Reader& log) { VectorXd rot_device = this->device_from_calib * floatlist2vector(log.getRot()); VectorXd trans_device = this->device_from_calib * floatlist2vector(log.getTrans()); - + if (!this->is_timestamp_valid(current_time)) { this->observation_timings_invalid = true; return; @@ -574,12 +588,12 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->handle_sensor(t, log.getAccelerometer()); } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); - } else if (log.isGpsLocation()) { - this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); - } else if (log.isGpsLocationExternal()) { - this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); - //} else if (log.isGnssMeasurements()) { - // this->handle_gnss(t, log.getGnssMeasurements()); + //} else if (log.isGpsLocation()) { + // this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); + //} else if (log.isGpsLocationExternal()) { + // this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + } else if (log.isGnssMeasurements()) { + this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { @@ -604,7 +618,7 @@ kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_build } bool Localizer::is_gps_ok() { - return this->gps_valid; + return (this->kf->get_filter_time() - this->last_gps_msg) < 1.0; } bool Localizer::critical_services_valid(std::map critical_services) { @@ -616,7 +630,7 @@ bool Localizer::critical_services_valid(std::map critical_s return true; } -bool Localizer::is_timestamp_valid(double current_time) { +bool Localizer::is_timestamp_valid(double current_time) { double filter_time = this->kf->get_filter_time(); if (!std::isnan(filter_time) && ((filter_time - current_time) > MAX_FILTER_REWIND_TIME)) { LOGE("Observation timestamp is older than the max rewind threshold of the filter"); @@ -643,19 +657,12 @@ void Localizer::determine_gps_mode(double current_time) { int Localizer::locationd_thread() { ublox_available = Params().getBool("UbloxAvailable", true); - - const char* gps_location_socket; - if (ublox_available) { - gps_location_socket = "gpsLocationExternal"; - } else { - gps_location_socket = "gpsLocation"; - } - const std::initializer_list service_list = {gps_location_socket, "cameraOdometry", "liveCalibration", + const std::initializer_list service_list = {"gnssMeasurements", "cameraOdometry", "liveCalibration", "carState", "carParams", "accelerometer", "gyroscope"}; - PubMaster pm({"liveLocationKalman"}); // TODO: remove carParams once we're always sending at 100Hz - SubMaster sm(service_list, {}, nullptr, {gps_location_socket, "carParams"}); + SubMaster sm(service_list, {}, nullptr, {"gnssMeasurements", "carParams"}); + PubMaster pm({"liveLocationKalman"}); uint64_t cnt = 0; bool filterInitialized = false; diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index 7a282be9d7..a292a3c936 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -24,6 +24,7 @@ class Localizer { public: Localizer(); + Localizer(bool has_ublox); int locationd_thread(); @@ -77,9 +78,10 @@ private: double reset_tracker = 0.0; bool device_fell = false; bool gps_mode = false; - bool gps_valid = false; double last_gps_msg = 0; bool ublox_available = true; bool observation_timings_invalid = false; - std::map observation_values_invalid; + std::map observation_values_invalid; + bool standstill = true; + int32_t orientation_reset_count = 0; }; diff --git a/selfdrive/locationd/test/_test_locationd_lib.py b/selfdrive/locationd/test/_test_locationd_lib.py index c4a053bbc6..819bb1570e 100755 --- a/selfdrive/locationd/test/_test_locationd_lib.py +++ b/selfdrive/locationd/test/_test_locationd_lib.py @@ -19,7 +19,7 @@ LIBLOCATIOND_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../ class TestLocationdLib(unittest.TestCase): def setUp(self): header = '''typedef ...* Localizer_t; -Localizer_t localizer_init(); +Localizer_t localizer_init(bool has_ublox); void localizer_get_message_bytes(Localizer_t localizer, bool inputsOK, bool sensorsOK, bool gpsOK, bool msgValid, char *buff, size_t buff_size); void localizer_handle_msg_bytes(Localizer_t localizer, const char *data, size_t size);''' @@ -27,7 +27,7 @@ void localizer_handle_msg_bytes(Localizer_t localizer, const char *data, size_t self.ffi.cdef(header) self.lib = self.ffi.dlopen(LIBLOCATIOND_PATH) - self.localizer = self.lib.localizer_init() + self.localizer = self.lib.localizer_init(True) # default to ublox self.buff_size = 2048 self.msg_buff = self.ffi.new(f'char[{self.buff_size}]') diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 198ecfe935..6059eab68f 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -4,7 +4,7 @@ import unittest from collections import defaultdict from datetime import datetime from unittest import mock -from unittest.mock import Mock, patch +from unittest.mock import patch from common.params import Params from laika.constants import SECS_IN_DAY @@ -67,47 +67,47 @@ class TestLaikad(unittest.TestCase): def setUp(self): Params().remove(EPHEMERIS_CACHE) - def test_fetch_orbits_non_blocking(self): + def test_fetch_navs_non_blocking(self): gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) laikad = Laikad() - laikad.fetch_orbits(gpstime, block=False) + laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) # Get results and save orbits to laikad: - laikad.fetch_orbits(gpstime, block=False) + laikad.fetch_navs(gpstime, block=False) - ephem = laikad.astro_dog.orbits['G01'][0] + ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) - laikad.fetch_orbits(gpstime+2*SECS_IN_DAY, block=False) + laikad.fetch_navs(gpstime+2*SECS_IN_DAY, block=False) laikad.orbit_fetch_future.result(30) # Get results and save orbits to laikad: - laikad.fetch_orbits(gpstime + 2 * SECS_IN_DAY, block=False) + laikad.fetch_navs(gpstime + 2 * SECS_IN_DAY, block=False) - ephem2 = laikad.astro_dog.orbits['G01'][0] + ephem2 = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) - def test_fetch_orbits_with_wrong_clocks(self): + def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() - def check_has_orbits(): - self.assertGreater(len(laikad.astro_dog.orbits), 0) - ephem = laikad.astro_dog.orbits['G01'][0] + def check_has_navs(): + self.assertGreater(len(laikad.astro_dog.navs), 0) + ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) real_current_time = GPSTime.from_datetime(datetime(2021, month=3, day=1)) wrong_future_clock_time = real_current_time + SECS_IN_DAY - laikad.fetch_orbits(wrong_future_clock_time, block=True) - check_has_orbits() - self.assertEqual(laikad.last_fetch_orbits_t, wrong_future_clock_time) + laikad.fetch_navs(wrong_future_clock_time, block=True) + check_has_navs() + self.assertEqual(laikad.last_fetch_navs_t, wrong_future_clock_time) # Test fetching orbits with earlier time - assert real_current_time < laikad.last_fetch_orbits_t + assert real_current_time < laikad.last_fetch_navs_t laikad.astro_dog.orbits = {} - laikad.fetch_orbits(real_current_time, block=True) - check_has_orbits() - self.assertEqual(laikad.last_fetch_orbits_t, real_current_time) + laikad.fetch_navs(real_current_time, block=True) + check_has_navs() + self.assertEqual(laikad.last_fetch_navs_t, real_current_time) def test_ephemeris_source_in_msg(self): data_mock = defaultdict(str) @@ -115,22 +115,22 @@ class TestLaikad(unittest.TestCase): gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC laikad = Laikad() - laikad.fetch_orbits(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.orbits['R01'][0]) + laikad.fetch_navs(gpstime, block=True) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.glonassIacUltraRapid) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) # Verify gps satellite returns same source - meas = get_measurement_mock(gpstime, laikad.astro_dog.orbits['R01'][0]) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.glonassIacUltraRapid) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) # Test nasa source by using older date gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) laikad = Laikad() - laikad.fetch_orbits(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.orbits['G01'][0]) + laikad.fetch_navs(gpstime, block=True) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nasaUltraRapid) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) # Test nav source type ephem = GPSEphemeris(data_mock, gpstime) @@ -142,7 +142,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 555 + correct_msgs_expected = 554 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -161,9 +161,8 @@ class TestLaikad(unittest.TestCase): def test_laika_online_nav_only(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV) # Disable fetch_orbits to test NAV only - laikad.fetch_orbits = Mock() correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 559 + correct_msgs_expected = 554 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -171,45 +170,45 @@ class TestLaikad(unittest.TestCase): def test_laika_offline(self, downloader_mock): downloader_mock.side_effect = DownloadFailed("Mock download failed") laikad = Laikad(auto_update=False) - laikad.fetch_orbits(GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC, block=True) + laikad.fetch_navs(GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC, block=True) @mock.patch('laika.downloader.download_and_cache_file') def test_download_failed_russian_source(self, downloader_mock): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(16, len(correct_msgs)) - self.assertEqual(16, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(0, len(correct_msgs)) + self.assertEqual(0, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) # Pretend process has loaded the orbits on startup by using the time of the first gps message. - laikad.fetch_orbits(self.first_gps_time, block=True) - self.dict_has_values(laikad.astro_dog.orbits) + laikad.fetch_navs(self.first_gps_time, block=True) + self.dict_has_values(laikad.astro_dog.navs) @unittest.skip("Use to debug live data") - def test_laika_get_orbits_now(self): + def test_laika_get_navs_now(self): laikad = Laikad(auto_update=False) - laikad.fetch_orbits(GPSTime.from_datetime(datetime.utcnow()), block=True) + laikad.fetch_navs(GPSTime.from_datetime(datetime.utcnow()), block=True) prn = "G01" - self.assertGreater(len(laikad.astro_dog.orbits[prn]), 0) + self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) prn = "R01" - self.assertGreater(len(laikad.astro_dog.orbits[prn]), 0) - print(min(laikad.astro_dog.orbits[prn], key=lambda e: e.epoch).epoch.as_datetime()) + self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) + print(min(laikad.astro_dog.navs[prn], key=lambda e: e.epoch).epoch.as_datetime()) - def test_get_orbits_in_process(self): + def test_get_navs_in_process(self): laikad = Laikad(auto_update=False) - has_orbits = False + has_navs = False for m in self.logs: laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=False) if laikad.orbit_fetch_future is not None: laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.orbits.values() - has_orbits = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if has_orbits: + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + if has_navs: break - self.assertTrue(has_orbits) - self.assertGreater(len(laikad.astro_dog.orbit_fetched_times._ranges), 0) + self.assertTrue(has_navs) + self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): @@ -228,17 +227,16 @@ class TestLaikad(unittest.TestCase): wait_for_cache() Params().remove(EPHEMERIS_CACHE) - laikad.astro_dog.get_navs(self.first_gps_time) - laikad.fetch_orbits(self.first_gps_time, block=True) + #laikad.astro_dog.get_navs(self.first_gps_time) + laikad.fetch_navs(self.first_gps_time, block=True) # Wait for cache to save wait_for_cache() # Check both nav and orbits separate laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True) - # Verify orbits and nav are loaded from cache - self.dict_has_values(laikad.astro_dog.orbits) - self.dict_has_values(laikad.astro_dog.nav) + # Verify navs are loaded from cache + self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(self.logs, laikad, return_one_success=True) self.assertIsNotNone(msg) @@ -246,7 +244,7 @@ class TestLaikad(unittest.TestCase): with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() - laikad.fetch_orbits(self.first_gps_time, block=False) + laikad.fetch_navs(self.first_gps_time, block=False) mock_method.assert_not_called() # Verify cache is working for only orbits by running a segment diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py index 7569530211..6e65acaaf9 100755 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -8,13 +8,14 @@ import capnp import cereal.messaging as messaging from cereal.services import service_list from common.params import Params +from common.transformations.coordinates import ecef2geodetic from selfdrive.manager.process_config import managed_processes class TestLocationdProc(unittest.TestCase): MAX_WAITS = 1000 - LLD_MSGS = ['gpsLocationExternal', 'cameraOdometry', 'carState', 'liveCalibration', + LLD_MSGS = ['gnssMeasurements', 'cameraOdometry', 'carState', 'liveCalibration', 'accelerometer', 'gyroscope', 'magnetometer'] def setUp(self): @@ -45,16 +46,14 @@ class TestLocationdProc(unittest.TestCase): except capnp.lib.capnp.KjException: msg = messaging.new_message(name, 0) - if name == "gpsLocationExternal": - msg.gpsLocationExternal.flags = 1 - msg.gpsLocationExternal.verticalAccuracy = 1.0 - msg.gpsLocationExternal.speedAccuracy = 1.0 - msg.gpsLocationExternal.bearingAccuracyDeg = 1.0 - msg.gpsLocationExternal.vNED = [0.0, 0.0, 0.0] - msg.gpsLocationExternal.latitude = self.lat - msg.gpsLocationExternal.longitude = self.lon - msg.gpsLocationExternal.unixTimestampMillis = t * 1e6 - msg.gpsLocationExternal.altitude = self.alt + if name == "gnssMeasurements": + msg.gnssMeasurements.measTime = t + msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] + msg.gnssMeasurements.positionECEF.std = [0,0,0] + msg.gnssMeasurements.positionECEF.valid = True + msg.gnssMeasurements.velocityECEF.value = [] + msg.gnssMeasurements.velocityECEF.std = [0,0,0] + msg.gnssMeasurements.velocityECEF.valid = True elif name == 'cameraOdometry': msg.cameraOdometry.rot = [0.0, 0.0, 0.0] msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0] @@ -67,9 +66,11 @@ class TestLocationdProc(unittest.TestCase): # first reset params Params().remove('LastGPSPosition') - self.lat = 30 + (random.random() * 10.0) - self.lon = -70 + (random.random() * 10.0) - self.alt = 5 + (random.random() * 10.0) + self.x = -2710700 + (random.random() * 1e5) + self.y = -4280600 + (random.random() * 1e5) + self.z = 3850300 + (random.random() * 1e5) + self.lat, self.lon, self.alt = ecef2geodetic([self.x, self.y, self.z]) + self.fake_duration = 90 # secs # get fake messages at the correct frequency, listed in services.py fake_msgs = [] @@ -83,10 +84,9 @@ class TestLocationdProc(unittest.TestCase): time.sleep(1) # wait for async params write lastGPS = json.loads(Params().get('LastGPSPosition')) - - self.assertAlmostEqual(lastGPS['latitude'], self.lat, places=3) - self.assertAlmostEqual(lastGPS['longitude'], self.lon, places=3) - self.assertAlmostEqual(lastGPS['altitude'], self.alt, places=3) + self.assertAlmostEqual(lastGPS['latitude'], self.lat, places=4) + self.assertAlmostEqual(lastGPS['longitude'], self.lon, places=4) + self.assertAlmostEqual(lastGPS['altitude'], self.alt, places=4) if __name__ == "__main__": diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index b45dffae33..6431e9d48b 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -192,6 +192,7 @@ kj::Array UbloxMsgParser::gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg) { eph.setAf2(subframe_1->af_2() * pow(2, -55)); eph.setAf1(subframe_1->af_1() * pow(2, -43)); eph.setAf0(subframe_1->af_0() * pow(2, -31)); + eph.setSvHealth(subframe_1->sv_health()); } // Subframe 2 diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 22ec099285..24ee87e471 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -331,7 +331,7 @@ CONFIGS = [ pub_sub={ "cameraOdometry": ["liveLocationKalman"], "accelerometer": [], "gyroscope": [], - "gpsLocationExternal": [], "liveCalibration": [], "carState": [], + "gnssMeasurements": [], "liveCalibration": [], "carState": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 157d146ade..58b6139d3e 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -ff0348b1957c8f992125df77a36b3c0553a26e6a +e41c3dd90cf61d0a630ba53c7e866cb2be3fc1a8 \ No newline at end of file From c1b9c3d3d1c928df929bce0cd1959d06e1091ccf Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 14 Jan 2023 03:40:34 +0800 Subject: [PATCH 0623/1179] Cabana: save signal on editingFinished (#26940) save signal on editingFinished --- tools/cabana/signaledit.cc | 32 ++++++++++++++++---------------- tools/cabana/signaledit.h | 7 +++---- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index b2491d5b1f..3845e72be1 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -54,12 +54,20 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { val_desc = new QLineEdit(); form_layout->addRow(tr("Value descriptions"), val_desc); - QObject::connect(name, &QLineEdit::textEdited, this, &SignalForm::changed); - QObject::connect(factor, &QLineEdit::textEdited, this, &SignalForm::changed); - QObject::connect(offset, &QLineEdit::textEdited, this, &SignalForm::changed); + QObject::connect(name, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); + QObject::connect(factor, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); + QObject::connect(offset, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); + QObject::connect(size, &QSpinBox::editingFinished, this, &SignalForm::changed); QObject::connect(sign, SIGNAL(activated(int)), SIGNAL(changed())); QObject::connect(endianness, SIGNAL(activated(int)), SIGNAL(changed())); - QObject::connect(size, SIGNAL(valueChanged(int)), SIGNAL(changed())); +} + +void SignalForm::textBoxEditingFinished() { + QLineEdit *edit = qobject_cast(QObject::sender()); + if (edit && edit->isModified()) { + edit->setModified(false); + emit changed(); + } } // SignalEdit @@ -108,17 +116,12 @@ 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]() { emit showFormClicked(sig); }); QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) { emit showChart(msg_id, sig, checked, QGuiApplication::keyboardModifiers() & Qt::ShiftModifier); }); - QObject::connect(remove_btn, &QToolButton::clicked, [this]() { emit remove(sig); }); - QObject::connect(form, &SignalForm::changed, [this]() { save_timer->start(); }); + QObject::connect(remove_btn, &QToolButton::clicked, [this]() { emit remove(sig); }); + QObject::connect(form, &SignalForm::changed, this, &SignalEdit::saveSignal); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } @@ -133,8 +136,6 @@ void SignalEdit::setSignal(const QString &message_id, const Signal *signal) { } void SignalEdit::saveSignal() { - if (!sig || !form->changed_by_user) return; - Signal s = *sig; s.name = form->name->text().toStdString(); s.size = form->size->text().toInt(); @@ -160,8 +161,9 @@ void SignalEdit::saveSignal() { s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); s.msb = s.start_bit; } - if (s != *sig) + if (s != *sig) { emit save(this->sig, s); + } } void SignalEdit::setChartOpened(bool opened) { @@ -171,7 +173,6 @@ void SignalEdit::setChartOpened(bool opened) { void SignalEdit::updateForm(bool visible) { if (visible && sig) { - form->changed_by_user = false; if (form->name->text() != sig->name.c_str()) { form->name->setText(sig->name.c_str()); } @@ -182,7 +183,6 @@ void SignalEdit::updateForm(bool visible) { form->msb->setText(QString::number(sig->msb)); form->lsb->setText(QString::number(sig->lsb)); form->size->setValue(sig->size); - form->changed_by_user = true; } form->setVisible(visible); icon->setText(visible ? "▼ " : "> "); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index eec943226e..d7b9084e7f 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "selfdrive/ui/qt/widgets/controls.h" @@ -15,13 +14,14 @@ class SignalForm : public QWidget { Q_OBJECT public: SignalForm(QWidget *parent); + void textBoxEditingFinished(); + QLineEdit *name, *unit, *comment, *val_desc, *offset, *factor, *min_val, *max_val; QLabel *lsb, *msb; QSpinBox *size; QComboBox *sign, *endianness; - bool changed_by_user = false; - signals: +signals: void changed(); }; @@ -55,5 +55,4 @@ protected: QLabel *icon; int form_idx = 0; QToolButton *plot_btn; - QTimer *save_timer; }; From 83d619e457a27f7ac2f1a7fc7c297dc257aa4430 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Fri, 13 Jan 2023 13:49:33 -0600 Subject: [PATCH 0624/1179] Add missing COROLLA_TSS2 engine f/w (#26936) add missing engine Co-authored-by: Shane Smiskol --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 586b1a835e..c413028a25 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -765,6 +765,7 @@ FW_VERSIONS = { b'\x03312N6100\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', b'\x03312N6200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203202\x00\x00\x00\x00', b'\x03312N6200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203302\x00\x00\x00\x00', + b'\x03312N6200\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', b'\x02312K4000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', b'\x02312U5000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00', ], From 2e36d07106c7e4e8e12afe0c33762abbf217a416 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Fri, 13 Jan 2023 13:23:06 -0800 Subject: [PATCH 0625/1179] paramsd: Remove one active condition (#26922) * remove one active condition * update refs * remove unused vars * update refs * update refs --- selfdrive/locationd/paramsd.py | 4 +--- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index 9bd4ed0837..7e7c2b091f 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -36,7 +36,6 @@ class ParamsLearner: self.yaw_rate = 0.0 self.yaw_rate_std = 0.0 self.roll = 0.0 - self.steering_pressed = False self.steering_angle = 0.0 self.valid = True @@ -88,10 +87,9 @@ class ParamsLearner: elif which == 'carState': self.steering_angle = msg.steeringAngleDeg - self.steering_pressed = msg.steeringPressed self.speed = msg.vEgo - in_linear_region = abs(self.steering_angle) < 45 or not self.steering_pressed + in_linear_region = abs(self.steering_angle) < 45 self.active = self.speed > 1 and in_linear_region if self.active: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 58b6139d3e..ea45fb4957 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -e41c3dd90cf61d0a630ba53c7e866cb2be3fc1a8 \ No newline at end of file +c714ab010923f2bce732bd22e903ccc4454136fd \ No newline at end of file From 50f62a7adc011c753aa846807a8eabfdbdf93996 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 13 Jan 2023 13:46:01 -0800 Subject: [PATCH 0626/1179] revert timeout increase from #26850 --- .github/workflows/tools_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 7ad0ce35b1..94cc3c2580 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -38,7 +38,7 @@ jobs: - name: Build Docker image run: eval "$BUILD" - name: Unit test - timeout-minutes: 6 + timeout-minutes: 2 run: | ${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \ apt-get update && \ From 23bd5d6f5d554b4117671605f2a99f6e37903789 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 13 Jan 2023 14:49:01 -0800 Subject: [PATCH 0627/1179] clutil: use logging functions (#26950) Co-authored-by: Comma Device --- common/clutil.cc | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/common/clutil.cc b/common/clutil.cc index 9d3447d807..3cfc8a8c8c 100644 --- a/common/clutil.cc +++ b/common/clutil.cc @@ -5,6 +5,7 @@ #include #include "common/util.h" +#include "common/swaglog.h" namespace { // helper functions @@ -31,14 +32,14 @@ void cl_print_info(cl_platform_id platform, cl_device_id device) { case CL_DEVICE_TYPE_ACCELERATOR: type_str = "CL_DEVICE_TYPE_ACCELERATOR"; break; } - std::cout << "vendor: " << get_platform_info(platform, CL_PLATFORM_VENDOR) << std::endl - << "platform version: " << get_platform_info(platform, CL_PLATFORM_VERSION) << std::endl - << "profile: " << get_platform_info(platform, CL_PLATFORM_PROFILE) << std::endl - << "extensions: " << get_platform_info(platform, CL_PLATFORM_EXTENSIONS) << std::endl - << "name :" << get_device_info(device, CL_DEVICE_NAME) << std::endl - << "device version :" << get_device_info(device, CL_DEVICE_VERSION) << std::endl - << "max work group size :" << work_group_size << std::endl - << "type = " << device_type << " = " << type_str << std::endl; + LOGD("vendor: %s", get_platform_info(platform, CL_PLATFORM_VENDOR).c_str()); + LOGD("platform version: %s", get_platform_info(platform, CL_PLATFORM_VERSION).c_str()); + LOGD("profile: %s", get_platform_info(platform, CL_PLATFORM_PROFILE).c_str()); + LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str()); + LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str()); + LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str()); + LOGD("max work group size: %d", work_group_size); + LOGD("type = %d = ", device_type, type_str); } void cl_print_build_errors(cl_program program, cl_device_id device) { @@ -49,7 +50,7 @@ void cl_print_build_errors(cl_program program, cl_device_id device) { std::string log(log_size, '\0'); clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, &log[0], NULL); - std::cout << "build failed; status=" << status << ", log:" << std::endl << log << std::endl; + LOGE("build failed; status=%d, log: %s", status, log.c_str()); } } // namespace @@ -61,14 +62,15 @@ cl_device_id cl_get_device_id(cl_device_type device_type) { CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL)); for (size_t i = 0; i < num_platforms; ++i) { - std::cout << "platform[" << i << "] CL_PLATFORM_NAME: " << get_platform_info(platform_ids[i], CL_PLATFORM_NAME) << std::endl; + LOGD("platform[%d] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str()); + // Get first device if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) { cl_print_info(platform_ids[i], device_id); return device_id; } } - std::cout << "No valid openCL platform found" << std::endl; + LOGE("No valid openCL platform found"); assert(0); return nullptr; } From 3136985b950e79cf2943dafa2cea4db5ad0f528b Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Fri, 13 Jan 2023 15:01:55 -0800 Subject: [PATCH 0628/1179] No more magic for the can chunks (#26861) * remove magic and add checksum * add comms reset * bump submodule --- panda | 2 +- selfdrive/boardd/panda.cc | 71 ++++++++++++------- selfdrive/boardd/panda.h | 8 ++- .../boardd/tests/test_boardd_usbprotocol.cc | 37 +++++++--- 4 files changed, 80 insertions(+), 38 deletions(-) diff --git a/panda b/panda index 0b3b906036..11d90f9e78 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 0b3b9060365739eeeddb1528cfe4018fec4efe7a +Subproject commit 11d90f9e78b1c070e44e02d5d8c2b18790617324 diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 3e447c830e..d4d53aa230 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -26,6 +26,8 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { (hw_type == cereal::PandaState::PandaType::DOS) || (hw_type == cereal::PandaState::PandaType::TRES); + can_reset_communications(); + return; } @@ -174,10 +176,6 @@ void Panda::pack_can_buffer(const capnp::List::Reader &can_data int32_t pos = 0; uint8_t send_buf[2 * USB_TX_SOFT_LIMIT]; - uint32_t magic = CAN_TRANSACTION_MAGIC; - memcpy(&send_buf[0], &magic, sizeof(uint32_t)); - pos += sizeof(uint32_t); - for (auto cmsg : can_data_list) { // check if the message is intended for this panda uint8_t bus = cmsg.getSrc(); @@ -194,20 +192,25 @@ void Panda::pack_can_buffer(const capnp::List::Reader &can_data header.extended = (cmsg.getAddress() >= 0x800) ? 1 : 0; header.data_len_code = data_len_code; header.bus = bus - bus_offset; + header.checksum = 0; memcpy(&send_buf[pos], (uint8_t *)&header, sizeof(can_header)); - pos += sizeof(can_header); - memcpy(&send_buf[pos], (uint8_t *)can_data.begin(), can_data.size()); - pos += can_data.size(); + memcpy(&send_buf[pos + sizeof(can_header)], (uint8_t *)can_data.begin(), can_data.size()); + uint32_t msg_size = sizeof(can_header) + can_data.size(); + + // set checksum + ((can_header *) &send_buf[pos])->checksum = calculate_checksum(&send_buf[pos], msg_size); + + pos += msg_size; if (pos >= USB_TX_SOFT_LIMIT) { write_func(send_buf, pos); - pos = sizeof(uint32_t); + pos = 0; } } // send remaining packets - if (pos > sizeof(uint32_t)) write_func(send_buf, pos); + if (pos > 0) write_func(send_buf, pos); } void Panda::can_send(capnp::List::Reader can_data_list) { @@ -217,36 +220,35 @@ void Panda::can_send(capnp::List::Reader can_data_list) { } bool Panda::can_receive(std::vector& out_vec) { - uint8_t data[RECV_SIZE]; - int recv = handle->bulk_read(0x81, (uint8_t*)data, RECV_SIZE); + int recv = handle->bulk_read(0x81, &receive_buffer[receive_buffer_size], RECV_SIZE); if (!comms_healthy()) { return false; } if (recv == RECV_SIZE) { LOGW("Panda receive buffer full"); } + receive_buffer_size += recv; - return (recv <= 0) ? true : unpack_can_buffer(data, recv, out_vec); + return (recv <= 0) ? true : unpack_can_buffer(receive_buffer, receive_buffer_size, out_vec); } -bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &out_vec) { - if (size < sizeof(uint32_t)) { - return true; - } +void Panda::can_reset_communications() { + handle->control_write(0xc0, 0, 0); +} - uint32_t magic; - memcpy(&magic, &data[0], sizeof(uint32_t)); - if (magic != CAN_TRANSACTION_MAGIC) { - LOGE("CAN recv: buffer didn't start with magic"); - handle->comms_healthy = false; - return false; - } +bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector &out_vec) { + int pos = 0; - int pos = sizeof(uint32_t); - while (pos < size) { + while (pos <= size - sizeof(can_header)) { can_header header; memcpy(&header, &data[pos], sizeof(can_header)); + const uint8_t data_len = dlc_to_len[header.data_len_code]; + if (pos + sizeof(can_header) + data_len > size) { + // we don't have all the data for this message yet + break; + } + can_frame &canData = out_vec.emplace_back(); canData.busTime = 0; canData.address = header.addr; @@ -258,10 +260,27 @@ bool Panda::unpack_can_buffer(uint8_t *data, int size, std::vector &o canData.src += CAN_RETURNED_BUS_OFFSET; } - const uint8_t data_len = dlc_to_len[header.data_len_code]; + if (calculate_checksum(&data[pos], sizeof(can_header) + data_len) != 0) { + LOGE("Panda CAN checksum failed"); + return false; + } + canData.dat.assign((char *)&data[pos + sizeof(can_header)], data_len); pos += sizeof(can_header) + data_len; } + + // move the overflowing data to the beginning of the buffer for the next round + memmove(data, &data[pos], size - pos); + size -= pos; + return true; } + +uint8_t Panda::calculate_checksum(uint8_t *data, uint32_t len) { + uint8_t checksum = 0U; + for (uint32_t i = 0U; i < len; i++) { + checksum ^= data[i]; + } + return checksum; +} diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index 75fec57a3e..156efe7ef3 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -30,6 +30,7 @@ struct __attribute__((packed)) can_header { uint8_t returned : 1; uint8_t extended : 1; uint32_t addr : 29; + uint8_t checksum : 8; }; struct can_frame { @@ -80,11 +81,16 @@ public: void set_canfd_non_iso(uint16_t bus, bool non_iso); void can_send(capnp::List::Reader can_data_list); bool can_receive(std::vector& out_vec); + void can_reset_communications(); protected: // for unit tests + uint8_t receive_buffer[RECV_SIZE + sizeof(can_header) + 64]; + uint32_t receive_buffer_size = 0; + Panda(uint32_t bus_offset) : bus_offset(bus_offset) {} void pack_can_buffer(const capnp::List::Reader &can_data_list, std::function write_func); - bool unpack_can_buffer(uint8_t *data, int size, std::vector &out_vec); + bool unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector &out_vec); + uint8_t calculate_checksum(uint8_t *data, uint32_t len); }; diff --git a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc b/selfdrive/boardd/tests/test_boardd_usbprotocol.cc index cc3b4bce9a..3b78eb7bd2 100644 --- a/selfdrive/boardd/tests/test_boardd_usbprotocol.cc +++ b/selfdrive/boardd/tests/test_boardd_usbprotocol.cc @@ -16,7 +16,8 @@ int random_int(int min, int max) { struct PandaTest : public Panda { PandaTest(uint32_t bus_offset, int can_list_size, cereal::PandaState::PandaType hw_type); void test_can_send(); - void test_can_recv(); + void test_can_recv(uint32_t chunk_size = 0); + void test_chunked_can_recv(); std::map test_data; int can_list_size = 0; @@ -58,11 +59,7 @@ PandaTest::PandaTest(uint32_t bus_offset_, int can_list_size, cereal::PandaState void PandaTest::test_can_send() { std::vector unpacked_data; this->pack_can_buffer(can_data_list, [&](uint8_t *chunk, size_t size) { - uint32_t magic; - memcpy(&magic, &chunk[0], sizeof(uint32_t)); - - REQUIRE(magic == CAN_TRANSACTION_MAGIC); - unpacked_data.insert(unpacked_data.end(), &chunk[sizeof(uint32_t)], &chunk[size]); + unpacked_data.insert(unpacked_data.end(), chunk, &chunk[size]); }); REQUIRE(unpacked_data.size() == total_pakets_size); @@ -77,16 +74,30 @@ void PandaTest::test_can_send() { REQUIRE(header.addr == cnt); REQUIRE(test_data.find(data_len) != test_data.end()); const std::string &dat = test_data[data_len]; - REQUIRE(memcmp(dat.data(), &unpacked_data[pos + 5], dat.size()) == 0); + REQUIRE(memcmp(dat.data(), &unpacked_data[pos + sizeof(can_header)], dat.size()) == 0); ++cnt; } REQUIRE(cnt == can_list_size); } -void PandaTest::test_can_recv() { +void PandaTest::test_can_recv(uint32_t rx_chunk_size) { std::vector frames; - this->pack_can_buffer(can_data_list, [&](uint8_t *data, size_t size) { - this->unpack_can_buffer(data, size, frames); + this->pack_can_buffer(can_data_list, [&](uint8_t *data, uint32_t size) { + if (rx_chunk_size == 0) { + REQUIRE(this->unpack_can_buffer(data, size, frames)); + } else { + this->receive_buffer_size = 0; + uint32_t pos = 0; + + while(pos < size) { + uint32_t chunk_size = std::min(rx_chunk_size, size - pos); + memcpy(&this->receive_buffer[this->receive_buffer_size], &data[pos], chunk_size); + this->receive_buffer_size += chunk_size; + pos += chunk_size; + + REQUIRE(this->unpack_can_buffer(this->receive_buffer, this->receive_buffer_size, frames)); + } + } }); REQUIRE(frames.size() == can_list_size); @@ -109,6 +120,9 @@ TEST_CASE("send/recv CAN 2.0 packets") { SECTION("can_receive") { test.test_can_recv(); } + SECTION("chunked_can_receive") { + test.test_can_recv(0x40); + } } TEST_CASE("send/recv CAN FD packets") { @@ -122,4 +136,7 @@ TEST_CASE("send/recv CAN FD packets") { SECTION("can_receive") { test.test_can_recv(); } + SECTION("chunked_can_receive") { + test.test_can_recv(0x40); + } } From c91679c2d433e69b3a5cfc1a2bd275b757d2eff3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 13 Jan 2023 15:23:58 -0800 Subject: [PATCH 0629/1179] remove dead libdiag.h (#26951) --- release/files_common | 1 - selfdrive/sensord/libdiag.h | 37 ------------------------------------- 2 files changed, 38 deletions(-) delete mode 100644 selfdrive/sensord/libdiag.h diff --git a/release/files_common b/release/files_common index d0afa30dea..3d07924a91 100644 --- a/release/files_common +++ b/release/files_common @@ -280,7 +280,6 @@ selfdrive/loggerd/deleter.py selfdrive/loggerd/xattr_cache.py selfdrive/sensord/SConscript -selfdrive/sensord/libdiag.h selfdrive/sensord/sensors_qcom2.cc selfdrive/sensord/sensors/*.cc selfdrive/sensord/sensors/*.h diff --git a/selfdrive/sensord/libdiag.h b/selfdrive/sensord/libdiag.h deleted file mode 100644 index 03a59464ed..0000000000 --- a/selfdrive/sensord/libdiag.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define DIAG_MAX_RX_PKT_SIZ 4096 - -bool Diag_LSM_Init(uint8_t* pIEnv); -bool Diag_LSM_DeInit(void); - -// DCI - -#define DIAG_CON_APSS 0x001 -#define DIAG_CON_MPSS 0x002 -#define DIAG_CON_LPASS 0x004 -#define DIAG_CON_WCNSS 0x008 - -enum { - DIAG_DCI_NO_ERROR = 1001, -} diag_dci_error_type; - -int diag_register_dci_client(int*, uint16_t*, int, void*); -int diag_log_stream_config(int client_id, int set_mask, uint16_t log_codes_array[], int num_codes); -int diag_register_dci_stream(void (*func_ptr_logs)(unsigned char *ptr, int len), void (*func_ptr_events)(unsigned char *ptr, int len)); -int diag_release_dci_client(int*); - -int diag_send_dci_async_req(int client_id, unsigned char buf[], int bytes, unsigned char *rsp_ptr, int rsp_len, - void (*func_ptr)(unsigned char *ptr, int len, void *data_ptr), void *data_ptr); - - -#ifdef __cplusplus -} -#endif From 406d12b7c17ff0d3d4fb713a90b178978c36d042 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 13 Jan 2023 17:20:45 -0800 Subject: [PATCH 0630/1179] Fix car docs diff bot (#26955) fix --- selfdrive/debug/print_docs_diff.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/selfdrive/debug/print_docs_diff.py b/selfdrive/debug/print_docs_diff.py index b804286458..103dd52dd8 100755 --- a/selfdrive/debug/print_docs_diff.py +++ b/selfdrive/debug/print_docs_diff.py @@ -9,6 +9,7 @@ from selfdrive.car.docs_definitions import Column FOOTNOTE_TAG = "{}" STAR_ICON = '' +VIDEO_ICON = '' COLUMNS = "|" + "|".join([column.value for column in Column]) + "|" COLUMN_HEADER = "|---|---|---|{}|".format("|".join([":---:"] * (len(Column) - 3))) ARROW_SYMBOL = "➡️" @@ -39,8 +40,8 @@ def match_cars(base_cars, new_cars): def build_column_diff(base_car, new_car): row_builder = [] for column in Column: - base_column = base_car.get_column(column, STAR_ICON, FOOTNOTE_TAG) - new_column = new_car.get_column(column, STAR_ICON, FOOTNOTE_TAG) + base_column = base_car.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) + new_column = new_car.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) if base_column != new_column: row_builder.append(f"{base_column} {ARROW_SYMBOL} {new_column}") @@ -74,11 +75,11 @@ def print_car_info_diff(path): # Removals for car_info in car_removals: - changes["removals"].append(format_row([car_info.get_column(column, STAR_ICON, FOOTNOTE_TAG) for column in Column])) + changes["removals"].append(format_row([car_info.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column])) # Additions for car_info in car_additions: - changes["additions"].append(format_row([car_info.get_column(column, STAR_ICON, FOOTNOTE_TAG) for column in Column])) + changes["additions"].append(format_row([car_info.get_column(column, STAR_ICON, VIDEO_ICON, FOOTNOTE_TAG) for column in Column])) for new_car, base_car in car_changes: # Column changes From 6527f2c825191860317317f2810fe320b277b69c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 13 Jan 2023 17:52:24 -0800 Subject: [PATCH 0631/1179] Car docs: link to car harness on shop (#26957) * harness links * test * fix for no years cars * match order of docs --- docs/CARS.md | 444 +++++++++++++++--------------- selfdrive/car/docs_definitions.py | 30 +- 2 files changed, 241 insertions(+), 233 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 48145d78a9..0d4c53ac01 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -8,229 +8,229 @@ A supported vehicle is one that just works when you install a comma three. All s |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| -|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| -|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| -|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| -|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| -|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| -|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| -|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| -|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| -|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Genesis|GV60 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| -|Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| -|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| -|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| -|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| -|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| -|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| -|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|| -|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|| -|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|| -|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| -|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| -|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| -|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O|| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|| -|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Hyundai|Santa Cruz 2021-22[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| -|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| -|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|Hyundai|Tucson Hybrid 2022[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| -|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| -|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|| -|Kia|EV6 (with HDA II) 2022[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|| -|Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| -|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| -|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| -|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| -|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| -|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| -|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Kia|Sorento 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| -|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| -|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| -|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| -|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| -|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B|| -|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| -|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| -|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| -|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|| -|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| -|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| -|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| -|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| -|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| -|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| -|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| -|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| -|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Genesis|GV60 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[4](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|| +|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| +|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| +|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|| +|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|| +|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| +|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| +|Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O|| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Hyundai|Santa Cruz 2021-22[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| +|Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Tucson 2022[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Tucson 2023[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Hyundai|Tucson Hybrid 2022[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| +|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Kia|EV6 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|| +|Kia|EV6 (with HDA II) 2022[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|| +|Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| +|Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| +|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| +|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| +|Kia|Sorento 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| +|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B|| +|Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| +|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| +|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| +|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|| +|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| +|Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| +|Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| +|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| 1Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`.
diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index c3063bc47c..e047b33e76 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -126,20 +126,11 @@ class CarInfo: harness: Enum = Harness.none def init(self, CP: car.CarParams, all_footnotes: Dict[Enum, int]): - # TODO: set all the min steer speeds in carParams and remove this - if self.min_steer_speed is not None: - assert CP.minSteerSpeed == 0, f"{CP.carFingerprint}: Minimum steer speed set in both CarInfo and CarParams" - else: - self.min_steer_speed = CP.minSteerSpeed - - # TODO: set all the min enable speeds in carParams correctly and remove this - if self.min_enable_speed is None: - self.min_enable_speed = CP.minEnableSpeed - self.car_name = CP.carName self.car_fingerprint = CP.carFingerprint self.make, self.model, self.years = split_name(self.name) + # longitudinal column op_long = "Stock" if CP.openpilotLongitudinalControl and not CP.enableDsu: op_long = "openpilot" @@ -150,6 +141,23 @@ class CarInfo: else: self.footnotes.append(CommonFootnote.EXP_LONG_AVAIL) + # min steer & enable speed columns + # TODO: set all the min steer speeds in carParams and remove this + if self.min_steer_speed is not None: + assert CP.minSteerSpeed == 0, f"{CP.carFingerprint}: Minimum steer speed set in both CarInfo and CarParams" + else: + self.min_steer_speed = CP.minSteerSpeed + + # TODO: set all the min enable speeds in carParams correctly and remove this + if self.min_enable_speed is None: + self.min_enable_speed = CP.minEnableSpeed + + # harness column + harness_col = self.harness.value + if self.harness is not Harness.none: + model_years = self.model + (' ' + self.years if self.years else '') + harness_col = f'{harness_col}' + self.row = { Column.MAKE: self.make, Column.MODEL: self.model, @@ -159,7 +167,7 @@ class CarInfo: Column.FSR_STEERING: f"{max(self.min_steer_speed * CV.MS_TO_MPH, 0):.0f} mph", Column.STEERING_TORQUE: Star.EMPTY, Column.AUTO_RESUME: Star.FULL if CP.autoResumeSng else Star.EMPTY, - Column.HARNESS: self.harness.value, + Column.HARNESS: harness_col, Column.VIDEO: self.video_link if self.video_link is not None else "", # replaced with an image and link from template in get_column } From 028527423c86800e5f260377533c1f8024658f67 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Fri, 13 Jan 2023 21:32:15 -0800 Subject: [PATCH 0632/1179] camerad: rework ox exposure score (#26948) * wip * make separate score func * n4ot g * clean up * remove * simplify * b2b * balance costs * clean up * no if tici * box view * new baselines * Revert "new baselines" This reverts commit f7a5d059eda70fa4d49e3024923da30e8821f42b. * Revert "box view" This reverts commit a57924be36e7d6abc2585aca9575c74cd583ef86. Co-authored-by: Comma Device --- system/camerad/cameras/camera_qcom2.cc | 66 +++++++++++++++----------- system/camerad/cameras/camera_qcom2.h | 4 ++ system/camerad/test/test_exposure.py | 11 ++--- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 091b0d91d9..8e2ad7bd91 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -104,8 +104,8 @@ const int ANALOG_GAIN_MIN_IDX_OX03C10 = 0x0; const int ANALOG_GAIN_REC_IDX_OX03C10 = 0x11; // 2.5x const int ANALOG_GAIN_MAX_IDX_OX03C10 = 0x36; const int ANALOG_GAIN_COST_DELTA_OX03C10 = -1; -const float ANALOG_GAIN_COST_LOW_OX03C10 = 0.05; -const float ANALOG_GAIN_COST_HIGH_OX03C10 = 0.8; +const float ANALOG_GAIN_COST_LOW_OX03C10 = 0.4; +const float ANALOG_GAIN_COST_HIGH_OX03C10 = 6.4; const int EXPOSURE_TIME_MIN_AR0231 = 2; // with HDR, fastest ss const int EXPOSURE_TIME_MAX_AR0231 = 0x0855; // with HDR, slowest ss, 40ms @@ -1041,6 +1041,30 @@ void CameraState::handle_camera_event(void *evdat) { } } +void CameraState::update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain) { + float score = 1e6; + if (camera_id == CAMERA_ID_AR0231) { + // Cost of ev diff + score = std::abs(desired_ev - (exp_t * exp_gain)) * 10; + // Cost of absolute gain + float m = exp_g_idx > analog_gain_rec_idx ? analog_gain_cost_high : analog_gain_cost_low; + score += std::abs(exp_g_idx - (int)analog_gain_rec_idx) * m; + // Cost of changing gain + score += std::abs(exp_g_idx - gain_idx) * (score + 1.0) / 10.0; + } else if (camera_id == CAMERA_ID_OX03C10) { + score = std::abs(desired_ev - (exp_t * exp_gain)); + float m = exp_g_idx > analog_gain_rec_idx ? analog_gain_cost_high : analog_gain_cost_low; + score += std::abs(exp_g_idx - (int)analog_gain_rec_idx) * m; + score += ((1 - analog_gain_cost_delta) + analog_gain_cost_delta * (exp_g_idx - analog_gain_min_idx) / (analog_gain_max_idx - analog_gain_min_idx)) * std::abs(exp_g_idx - gain_idx) * 5.0; + } + + if (score < best_ev_score) { + new_exp_t = exp_t; + new_exp_g = exp_g_idx; + best_ev_score = score; + } +} + void CameraState::set_camera_exposure(float grey_frac) { if (!enabled) return; const float dt = 0.05; @@ -1066,9 +1090,9 @@ void CameraState::set_camera_exposure(float grey_frac) { float k = (1.0 - k_ev) / 3.0; desired_ev = (k * cur_ev[0]) + (k * cur_ev[1]) + (k * cur_ev[2]) + (k_ev * desired_ev); - float best_ev_score = 1e6; - int new_g = 0; - int new_t = 0; + best_ev_score = 1e6; + new_exp_g = 0; + new_exp_t = 0; // Hysteresis around high conversion gain // We usually want this on since it results in lower noise, but turn off in very bright day scenes @@ -1095,8 +1119,8 @@ void CameraState::set_camera_exposure(float grey_frac) { gain_idx = std::stoi(gain_bytes); exposure_time = std::stoi(time_bytes); - new_g = gain_idx; - new_t = exposure_time; + new_exp_g = gain_idx; + new_exp_t = exposure_time; enable_dc_gain = false; } else { // Simple brute force optimizer to choose sensor parameters @@ -1112,23 +1136,7 @@ void CameraState::set_camera_exposure(float grey_frac) { continue; } - // Compute error to desired ev - float score = std::abs(desired_ev - (t * gain)) * 10; - - // Going below recommended gain needs lower penalty to not overexpose - float m = g > analog_gain_rec_idx ? analog_gain_cost_high : analog_gain_cost_low; - score += std::abs(g - (int)analog_gain_rec_idx) * m; - - // LOGE("cam: %d - gain: %d, t: %d (%.2f), score %.2f, score + gain %.2f, %.3f, %.3f", camera_num, g, t, desired_ev / gain, score, score + std::abs(g - gain_idx) * (score + 1.0) / 10.0, desired_ev, min_ev); - - // Small penalty on changing gain - score += ((1 - analog_gain_cost_delta) + analog_gain_cost_delta * (g - analog_gain_min_idx) / (analog_gain_max_idx - analog_gain_min_idx)) * std::abs(g - gain_idx) * (score + 1.0) / 10.0; - - if (score < best_ev_score) { - new_t = t; - new_g = g; - best_ev_score = score; - } + update_exposure_score(desired_ev, t, g, gain); } } @@ -1137,9 +1145,9 @@ void CameraState::set_camera_exposure(float grey_frac) { measured_grey_fraction = grey_frac; target_grey_fraction = target_grey; - analog_gain_frac = sensor_analog_gains[new_g]; - gain_idx = new_g; - exposure_time = new_t; + analog_gain_frac = sensor_analog_gains[new_exp_g]; + gain_idx = new_exp_g; + exposure_time = new_exp_t; dc_gain_enabled = enable_dc_gain; float gain = analog_gain_frac * (1 + dc_gain_weight * (dc_gain_factor-1) / dc_gain_max_weight); @@ -1156,7 +1164,7 @@ void CameraState::set_camera_exposure(float grey_frac) { // LOGE("ae - camera %d, cur_t %.5f, sof %.5f, dt %.5f", camera_num, 1e-9 * nanos_since_boot(), 1e-9 * buf.cur_frame_data.timestamp_sof, 1e-9 * (nanos_since_boot() - buf.cur_frame_data.timestamp_sof)); if (camera_id == CAMERA_ID_AR0231) { - uint16_t analog_gain_reg = 0xFF00 | (new_g << 4) | new_g; + uint16_t analog_gain_reg = 0xFF00 | (new_exp_g << 4) | new_exp_g; struct i2c_random_wr_payload exp_reg_array[] = { {0x3366, analog_gain_reg}, {0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)}, @@ -1171,7 +1179,7 @@ void CameraState::set_camera_exposure(float grey_frac) { uint32_t vs_time = std::min(std::max((uint32_t)exposure_time / 128, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10); uint32_t spd_time = vs_time; - uint32_t real_gain = ox03c10_analog_gains_reg[new_g]; + uint32_t real_gain = ox03c10_analog_gains_reg[new_exp_g]; uint32_t min_gain = ox03c10_analog_gains_reg[0]; struct i2c_random_wr_payload exp_reg_array[] = { {0x3501, hcg_time>>8}, {0x3502, hcg_time&0xFF}, diff --git a/system/camerad/cameras/camera_qcom2.h b/system/camerad/cameras/camera_qcom2.h index 9f0c3743f1..9e0109ab20 100644 --- a/system/camerad/cameras/camera_qcom2.h +++ b/system/camerad/cameras/camera_qcom2.h @@ -47,6 +47,9 @@ public: float cur_ev[3]; float min_ev, max_ev; + float best_ev_score; + int new_exp_g; + int new_exp_t; float measured_grey_fraction; float target_grey_fraction; @@ -58,6 +61,7 @@ public: int camera_num; void handle_camera_event(void *evdat); + void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain); void set_camera_exposure(float grey_frac); void sensors_start(); diff --git a/system/camerad/test/test_exposure.py b/system/camerad/test/test_exposure.py index 8cce7e7ffa..201b205c4f 100755 --- a/system/camerad/test/test_exposure.py +++ b/system/camerad/test/test_exposure.py @@ -6,16 +6,13 @@ import numpy as np from selfdrive.test.helpers import with_processes from system.camerad.snapshot.snapshot import get_snapshots -from system.hardware import TICI - TEST_TIME = 45 REPEAT = 5 class TestCamerad(unittest.TestCase): @classmethod def setUpClass(cls): - if not TICI: - raise unittest.SkipTest + pass def _numpy_rgb2gray(self, im): ret = np.clip(im[:,:,2] * 0.114 + im[:,:,1] * 0.587 + im[:,:,0] * 0.299, 0, 255).astype(np.uint8) @@ -37,13 +34,11 @@ class TestCamerad(unittest.TestCase): start = time.time() while time.time() - start < TEST_TIME and passed < REPEAT: rpic, dpic = get_snapshots(frame="roadCameraState", front_frame="driverCameraState") + wpic, _ = get_snapshots(frame="wideRoadCameraState") res = self._is_exposure_okay(rpic) res = res and self._is_exposure_okay(dpic) - - if TICI: - wpic, _ = get_snapshots(frame="wideRoadCameraState") - res = res and self._is_exposure_okay(wpic) + res = res and self._is_exposure_okay(wpic) if passed > 0 and not res: passed = -passed # fails test if any failure after first sus From 1e8e4f7ede35d9a95c97ccfbb0bf8d7c5df46e39 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 13 Jan 2023 22:24:16 -0800 Subject: [PATCH 0633/1179] temporary revert laikad as main gps --- selfdrive/locationd/locationd.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 928e19081e..70ccf3bb4e 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -354,6 +354,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); } + this->last_gps_msg = sensor_time; this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_POS, { ecef_pos }, { ecef_pos_R }); this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); } @@ -588,12 +589,12 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->handle_sensor(t, log.getAccelerometer()); } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); - //} else if (log.isGpsLocation()) { - // this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); - //} else if (log.isGpsLocationExternal()) { - // this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); - } else if (log.isGnssMeasurements()) { - this->handle_gnss(t, log.getGnssMeasurements()); + } else if (log.isGpsLocation()) { + this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); + } else if (log.isGpsLocationExternal()) { + this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + //} else if (log.isGnssMeasurements()) { + // this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { From c44b6225592c070d87d2b3e77018a623d344f054 Mon Sep 17 00:00:00 2001 From: Bruce Wayne Date: Sat, 14 Jan 2023 10:34:59 -0800 Subject: [PATCH 0634/1179] Revert "temporary revert laikad as main gps" This reverts commit 1e8e4f7ede35d9a95c97ccfbb0bf8d7c5df46e39. --- selfdrive/locationd/locationd.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 70ccf3bb4e..928e19081e 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -354,7 +354,6 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); } - this->last_gps_msg = sensor_time; this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_POS, { ecef_pos }, { ecef_pos_R }); this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); } @@ -589,12 +588,12 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->handle_sensor(t, log.getAccelerometer()); } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); - } else if (log.isGpsLocation()) { - this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); - } else if (log.isGpsLocationExternal()) { - this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); - //} else if (log.isGnssMeasurements()) { - // this->handle_gnss(t, log.getGnssMeasurements()); + //} else if (log.isGpsLocation()) { + // this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); + //} else if (log.isGpsLocationExternal()) { + // this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + } else if (log.isGnssMeasurements()) { + this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { From d064a32b00c375f21afbbe32171231122281c1ea Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 14 Jan 2023 16:28:17 -0800 Subject: [PATCH 0635/1179] docs: add experimental mode to compatibility description (#26954) * docs: add experimental mode to compatibility description * lower case --- selfdrive/car/docs_definitions.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/selfdrive/car/docs_definitions.py b/selfdrive/car/docs_definitions.py index e047b33e76..c0fb4420df 100644 --- a/selfdrive/car/docs_definitions.py +++ b/selfdrive/car/docs_definitions.py @@ -204,6 +204,13 @@ class CarInfo: if self.row[Column.STEERING_TORQUE] != Star.FULL: sentence_builder += " This car may not be able to take tight turns on its own." + # experimental mode + exp_link = "Experimental mode" + if CP.openpilotLongitudinalControl or CP.experimentalLongitudinalAvailable: + sentence_builder += f" Traffic light and stop sign handling is also available in {exp_link}." + else: + sentence_builder += f" {exp_link}, with traffic light and stop sign handling, is not currently available for this car, but may be added in a future software update." + return sentence_builder.format(car_model=f"{self.make} {self.model}", alc=alc, acc=acc) else: From 4c33d94d3f088c6f1fc88a0f40f3a828968c1c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Sat, 14 Jan 2023 16:56:14 -0800 Subject: [PATCH 0636/1179] Revert locationd to gpsLocation (#26963) * revert locationd laika change * switch msg * change proc replay * back to gpslocation * update ref * no np floats in msg * Ignore empty laikad messages in mapos * more tolerance * c++ doesnt work like that --- selfdrive/locationd/locationd.cc | 23 +++++++----- selfdrive/locationd/test/test_locationd.py | 35 ++++++++++++------- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/ui/qt/maps/map.cc | 3 +- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 928e19081e..8941b50248 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -354,6 +354,7 @@ void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::R this->reset_kalman(NAN, initial_pose_ecef_quat, ecef_pos, ecef_vel, ecef_pos_R, ecef_vel_R); } + this->last_gps_msg = sensor_time; this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_POS, { ecef_pos }, { ecef_pos_R }); this->kf->predict_and_observe(sensor_time, OBSERVATION_ECEF_VEL, { ecef_vel }, { ecef_vel_R }); } @@ -588,12 +589,12 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->handle_sensor(t, log.getAccelerometer()); } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); - //} else if (log.isGpsLocation()) { - // this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); - //} else if (log.isGpsLocationExternal()) { - // this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); - } else if (log.isGnssMeasurements()) { - this->handle_gnss(t, log.getGnssMeasurements()); + } else if (log.isGpsLocation()) { + this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); + } else if (log.isGpsLocationExternal()) { + this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + //} else if (log.isGnssMeasurements()) { + // this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { @@ -657,11 +658,17 @@ void Localizer::determine_gps_mode(double current_time) { int Localizer::locationd_thread() { ublox_available = Params().getBool("UbloxAvailable", true); - const std::initializer_list service_list = {"gnssMeasurements", "cameraOdometry", "liveCalibration", + const char* gps_location_socket; + if (ublox_available) { + gps_location_socket = "gpsLocationExternal"; + } else { + gps_location_socket = "gpsLocation"; + } + const std::initializer_list service_list = {gps_location_socket, "cameraOdometry", "liveCalibration", "carState", "carParams", "accelerometer", "gyroscope"}; // TODO: remove carParams once we're always sending at 100Hz - SubMaster sm(service_list, {}, nullptr, {"gnssMeasurements", "carParams"}); + SubMaster sm(service_list, {}, nullptr, {gps_location_socket, "carParams"}); PubMaster pm({"liveLocationKalman"}); uint64_t cnt = 0; diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py index 6e65acaaf9..9f643e2b8f 100755 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -15,7 +15,7 @@ from selfdrive.manager.process_config import managed_processes class TestLocationdProc(unittest.TestCase): MAX_WAITS = 1000 - LLD_MSGS = ['gnssMeasurements', 'cameraOdometry', 'carState', 'liveCalibration', + LLD_MSGS = ['gpsLocationExternal', 'cameraOdometry', 'carState', 'liveCalibration', 'accelerometer', 'gyroscope', 'magnetometer'] def setUp(self): @@ -46,14 +46,25 @@ class TestLocationdProc(unittest.TestCase): except capnp.lib.capnp.KjException: msg = messaging.new_message(name, 0) - if name == "gnssMeasurements": - msg.gnssMeasurements.measTime = t - msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] - msg.gnssMeasurements.positionECEF.std = [0,0,0] - msg.gnssMeasurements.positionECEF.valid = True - msg.gnssMeasurements.velocityECEF.value = [] - msg.gnssMeasurements.velocityECEF.std = [0,0,0] - msg.gnssMeasurements.velocityECEF.valid = True + + if name == "gpsLocationExternal": + msg.gpsLocationExternal.flags = 1 + msg.gpsLocationExternal.verticalAccuracy = 1.0 + msg.gpsLocationExternal.speedAccuracy = 1.0 + msg.gpsLocationExternal.bearingAccuracyDeg = 1.0 + msg.gpsLocationExternal.vNED = [0.0, 0.0, 0.0] + msg.gpsLocationExternal.latitude = float(self.lat) + msg.gpsLocationExternal.longitude = float(self.lon) + msg.gpsLocationExternal.unixTimestampMillis = t * 1e6 + msg.gpsLocationExternal.altitude = float(self.alt) + #if name == "gnssMeasurements": + # msg.gnssMeasurements.measTime = t + # msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] + # msg.gnssMeasurements.positionECEF.std = [0,0,0] + # msg.gnssMeasurements.positionECEF.valid = True + # msg.gnssMeasurements.velocityECEF.value = [] + # msg.gnssMeasurements.velocityECEF.std = [0,0,0] + # msg.gnssMeasurements.velocityECEF.valid = True elif name == 'cameraOdometry': msg.cameraOdometry.rot = [0.0, 0.0, 0.0] msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0] @@ -84,9 +95,9 @@ class TestLocationdProc(unittest.TestCase): time.sleep(1) # wait for async params write lastGPS = json.loads(Params().get('LastGPSPosition')) - self.assertAlmostEqual(lastGPS['latitude'], self.lat, places=4) - self.assertAlmostEqual(lastGPS['longitude'], self.lon, places=4) - self.assertAlmostEqual(lastGPS['altitude'], self.alt, places=4) + self.assertAlmostEqual(lastGPS['latitude'], self.lat, places=3) + self.assertAlmostEqual(lastGPS['longitude'], self.lon, places=3) + self.assertAlmostEqual(lastGPS['altitude'], self.alt, places=3) if __name__ == "__main__": diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 24ee87e471..22ec099285 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -331,7 +331,7 @@ CONFIGS = [ pub_sub={ "cameraOdometry": ["liveLocationKalman"], "accelerometer": [], "gyroscope": [], - "gnssMeasurements": [], "liveCalibration": [], "carState": [], + "gpsLocationExternal": [], "liveCalibration": [], "carState": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index ea45fb4957..a173cf5205 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c714ab010923f2bce732bd22e903ccc4454136fd \ No newline at end of file +18a70665bdb6b6aee4a224e826417049415e8290 diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index c625564f1d..dd30b5feff 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -125,7 +125,8 @@ void MapWindow::updateState(const UIState &s) { } } - if (sm.updated("gnssMeasurements")) { + // TODO should check a valid/status flag + if (sm.updated("gnssMeasurements") && sm["gnssMeasurements"].getGnssMeasurements().getGpsWeek() > 0){ auto laikad_location = sm["gnssMeasurements"].getGnssMeasurements(); auto laikad_pos = laikad_location.getPositionECEF(); auto laikad_pos_ecef = laikad_pos.getValue(); From 6861c9999195a9791bdb31675a4ed07dbd562b9c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 14 Jan 2023 23:06:09 -0800 Subject: [PATCH 0637/1179] don't run ublox procs without ublox (#26965) * pigeond: don't run if ublox missing * same for ubloxd Co-authored-by: Comma Device --- selfdrive/manager/process_config.py | 9 +++++++-- selfdrive/sensord/pigeond.py | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index c03e995497..8fc4d94e55 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -17,6 +17,11 @@ def logging(started, params, CP: car.CarParams) -> bool: run = (not CP.notCar) or not params.get_bool("DisableLogging") return started and run +def ublox(started, params, CP: car.CarParams) -> bool: + use_ublox = os.path.exists('/dev/ttyHS0') and not os.path.exists('/persist/comma/use-quectel-gps') + params.put_bool("UbloxAvailable", use_ublox) + return started and use_ublox + procs = [ # due to qualcomm kernel bugs SIGKILLing camerad sometimes causes page table corruption NativeProcess("camerad", "system/camerad", ["./camerad"], unkillable=True, callback=driverview), @@ -35,7 +40,6 @@ procs = [ NativeProcess("mapsd", "selfdrive/navd", ["./map_renderer"], enabled=False), NativeProcess("navmodeld", "selfdrive/modeld", ["./navmodeld"], enabled=False), NativeProcess("sensord", "selfdrive/sensord", ["./sensord"], enabled=not PC), - NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=(not PC or WEBCAM)), NativeProcess("ui", "selfdrive/ui", ["./ui"], offroad=True, watchdog_max_dt=(5 if not PC else None)), NativeProcess("soundd", "selfdrive/ui/soundd", ["./soundd"], offroad=True), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"]), @@ -50,7 +54,8 @@ procs = [ PythonProcess("navd", "selfdrive.navd.navd"), PythonProcess("pandad", "selfdrive.boardd.pandad", offroad=True), PythonProcess("paramsd", "selfdrive.locationd.paramsd"), - PythonProcess("pigeond", "selfdrive.sensord.pigeond", enabled=TICI), + NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=TICI, onroad=False, callback=ublox), + PythonProcess("pigeond", "selfdrive.sensord.pigeond", enabled=TICI, onroad=False, callback=ublox), PythonProcess("plannerd", "selfdrive.controls.plannerd"), PythonProcess("radard", "selfdrive.controls.radard"), PythonProcess("thermald", "selfdrive.thermald.thermald", offroad=True), diff --git a/selfdrive/sensord/pigeond.py b/selfdrive/sensord/pigeond.py index f56af1c705..bb53dd1bd4 100755 --- a/selfdrive/sensord/pigeond.py +++ b/selfdrive/sensord/pigeond.py @@ -303,8 +303,7 @@ def main(): pigeon, pm = create_pigeon() init_baudrate(pigeon) - r = initialize_pigeon(pigeon) - Params().put_bool("UbloxAvailable", r) + initialize_pigeon(pigeon) # start receiving data run_receiving(pigeon, pm) From ae6ad15df5e9047f841e990812d26f0409545dc2 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sun, 15 Jan 2023 21:50:29 +0100 Subject: [PATCH 0638/1179] MacOS: bump body to fix build (#26972) --- body | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/body b/body index dc780f858c..e1805f65ee 160000 --- a/body +++ b/body @@ -1 +1 @@ -Subproject commit dc780f858c1ef641471d09b72569e199e3e10acb +Subproject commit e1805f65ee75fab4454c21eda8b42b49d4bdc48f From 58bd02408979f19999acd8c755ed30785b9ef6d7 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 16 Jan 2023 04:52:11 +0800 Subject: [PATCH 0639/1179] cabana: support drag and drop to merge charts (#26968) --- tools/cabana/chartswidget.cc | 67 +++++++++++++++++++++++++++++++----- tools/cabana/chartswidget.h | 6 ++++ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 952ed2d83f..c8208b2f14 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -331,6 +332,17 @@ void ChartView::msgRemoved(uint32_t address) { } } +void ChartView::addSeries(const QList &series_list) { + for (auto &s : series_list) { + if (auto m = dbc()->msg(s[0])) { + auto it = m->sigs.find(s[2]); + if (it != m->sigs.end() && !hasSeries(s[0], &(it->second))) { + addSeries(s[0], &(it->second)); + } + } + } +} + void ChartView::manageSeries() { SeriesSelector dlg(this); for (auto &s : sigs) { @@ -343,14 +355,7 @@ void ChartView::manageSeries() { if (series_list.isEmpty()) { emit remove(); } else { - for (auto &s : series_list) { - if (auto m = dbc()->msg(s[0])) { - auto it = m->sigs.find(s[2]); - if (it != m->sigs.end() && !hasSeries(s[0], &(it->second))) { - addSeries(s[0], &(it->second)); - } - } - } + addSeries(series_list); for (auto it = sigs.begin(); it != sigs.end(); /**/) { bool exists = std::any_of(series_list.cbegin(), series_list.cend(), [&](auto &s) { return s[0] == it->msg_id && s[2] == it->sig->name.c_str(); @@ -495,6 +500,23 @@ void ChartView::leaveEvent(QEvent *event) { QChartView::leaveEvent(event); } +void ChartView::mousePressEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton && !chart()->plotArea().contains(event->pos()) && + !manage_btn_proxy->widget()->underMouse() && !close_btn_proxy->widget()->underMouse()) { + QMimeData *mimeData = new QMimeData; + mimeData->setData(mime_type, QByteArray::number((qulonglong)this)); + QDrag *drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->setPixmap(grab()); + drag->setHotSpot(event->pos()); + Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction); + if (dropAction == Qt::MoveAction) { + return; + } + } + QChartView::mousePressEvent(event); +} + void ChartView::mouseReleaseEvent(QMouseEvent *event) { auto rubber = findChild(); if (event->button() == Qt::LeftButton && rubber && rubber->isVisible()) { @@ -550,6 +572,35 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { QChartView::mouseMoveEvent(ev); } +void ChartView::dragMoveEvent(QDragMoveEvent *event) { + if (event->mimeData()->hasFormat(mime_type)) { + event->setDropAction(event->source() == this ? Qt::MoveAction : Qt::CopyAction); + event->accept(); + } else { + event->ignore(); + } +} + +void ChartView::dropEvent(QDropEvent *event) { + if (event->mimeData()->hasFormat(mime_type)) { + if (event->source() == this) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + ChartView *source_chart = (ChartView *)event->source(); + QList series; + for (auto &s : source_chart->sigs) { + series.push_back({s.msg_id, msgName(s.msg_id), QString::fromStdString(s.sig->name)}); + } + addSeries(series); + emit source_chart->remove(); + event->acceptProposedAction(); + } + } else { + event->ignore(); + } +} + void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { qreal x = chart()->mapToPosition(QPointF{can->currentSec(), 0}).x(); qreal y1 = chart()->plotArea().top() - 2; diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 819432920b..ebce8ceda6 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -58,8 +59,11 @@ private slots: private: QList::iterator removeSeries(const QList::iterator &it); + void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dropEvent(QDropEvent *event) override; void leaveEvent(QEvent *event) override; void resizeEvent(QResizeEvent *event) override; void updateAxisY(); @@ -68,6 +72,7 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; void applyNiceNumbers(qreal min, qreal max); qreal niceNumber(qreal x, bool ceiling); + void addSeries(const QList &series_list); QValueAxis *axis_x; QValueAxis *axis_y; @@ -76,6 +81,7 @@ private: QGraphicsProxyWidget *manage_btn_proxy; std::pair events_range = {0, 0}; QList sigs; + const QString mime_type = "application/x-cabanachartview"; }; class ChartsWidget : public QWidget { From f6dc12a735b4856d2ac6225ec9a2f2aa36d2c2de Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 15 Jan 2023 16:13:50 -0500 Subject: [PATCH 0640/1179] VW MQB: Add diagnostic firewall note to config tool (#26975) --- selfdrive/debug/vw_mqb_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/debug/vw_mqb_config.py b/selfdrive/debug/vw_mqb_config.py index 8c4dbc55ee..8952405b8e 100755 --- a/selfdrive/debug/vw_mqb_config.py +++ b/selfdrive/debug/vw_mqb_config.py @@ -126,6 +126,7 @@ if __name__ == "__main__": uds_client.security_access(ACCESS_TYPE_LEVEL_1.SEND_KEY, struct.pack("!I", key)) # type: ignore except (NegativeResponseError, MessageTimeoutError): print("Security access failed!") + print("Open the hood and retry (disables the \"diagnostic firewall\" on newer vehicles)") quit() try: From 11da83d2b58d26e876fe65e6bb2ec1013b7a5316 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 15 Jan 2023 13:52:16 -0800 Subject: [PATCH 0641/1179] boardd: lock spi device (#26937) * lock spi * bump panda Co-authored-by: Comma Device --- panda | 2 +- selfdrive/boardd/spi.cc | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/panda b/panda index 11d90f9e78..e83b2189c1 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 11d90f9e78b1c070e44e02d5d8c2b18790617324 +Subproject commit e83b2189c148499b8ba430433886791217f3389a diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 717b6ce820..8a6bf8be7f 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -1,3 +1,4 @@ +#include #include #include @@ -28,6 +29,23 @@ struct __attribute__((packed)) spi_header { const int SPI_MAX_RETRIES = 5; const int SPI_ACK_TIMEOUT = 50; // milliseconds +class LockEx { +public: + LockEx(int fd, std::recursive_mutex &m) : fd(fd), m(m) { + m.lock(); + flock(fd, LOCK_EX); + }; + + ~LockEx() { + m.unlock(); + flock(fd, LOCK_UN); + } + +private: + int fd; + std::recursive_mutex &m; +}; + PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { LOGD("opening SPI panda: %s", serial.c_str()); @@ -84,6 +102,7 @@ void PandaSpiHandle::cleanup() { int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t param2, unsigned int timeout) { + LockEx lock(spi_fd, hw_lock); ControlPacket_t packet = { .request = request, .param1 = param1, @@ -94,6 +113,7 @@ int PandaSpiHandle::control_write(uint8_t request, uint16_t param1, uint16_t par } int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout) { + LockEx lock(spi_fd, hw_lock); ControlPacket_t packet = { .request = request, .param1 = param1, @@ -104,15 +124,15 @@ int PandaSpiHandle::control_read(uint8_t request, uint16_t param1, uint16_t para } int PandaSpiHandle::bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + LockEx lock(spi_fd, hw_lock); return bulk_transfer(endpoint, data, length, NULL, 0); } int PandaSpiHandle::bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout) { + LockEx lock(spi_fd, hw_lock); return bulk_transfer(endpoint, NULL, 0, data, length); } int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len) { - std::lock_guard lk(hw_lock); - const int xfer_size = 0x40 * 15; int ret = 0; @@ -167,7 +187,6 @@ int PandaSpiHandle::spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint1 int ret; int count = SPI_MAX_RETRIES; - std::lock_guard lk(hw_lock); do { // TODO: handle error ret = spi_transfer(endpoint, tx_data, tx_len, rx_data, max_rx_len); From 9c58e5fedd7cee154eec44857c6df83dcc1a8ed0 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sun, 15 Jan 2023 20:16:45 -0500 Subject: [PATCH 0642/1179] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202020=20?= =?UTF-8?q?=C5=A0koda=20Scala=20(#26976)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- selfdrive/car/volkswagen/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index f627e517be..6ae4969cc0 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1079,6 +1079,7 @@ FW_VERSIONS = { b'\xf1\x870CW300050 \xf1\x891709', ], (Ecu.srs, 0x715, None): [ + b'\xf1\x872Q0959655AJ\xf1\x890250\xf1\x82\x1211110411110411--04040404131111112H14', b'\xf1\x872Q0959655AM\xf1\x890351\xf1\x82\022111104111104112104040404111111112H14', ], (Ecu.eps, 0x712, None): [ From 5cc192be4d994d26e385f03a1945d810d465eb00 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Mon, 16 Jan 2023 07:13:16 +0100 Subject: [PATCH 0643/1179] cabana: MacOS fixes (#26973) * make qtcharts a framework * cabana: dfisable openpilot prefix on macos * cabana: disable opengl on charts * fix linux build * no newline * add comments --- tools/cabana/SConscript | 5 ++++- tools/cabana/cabana.cc | 4 ++++ tools/cabana/chartswidget.cc | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 718e2e50af..507b98ae88 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -8,10 +8,13 @@ base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq', if arch == "Darwin": base_frameworks.append('OpenCL') + base_frameworks.append('QtCharts') else: base_libs.append('OpenCL') + base_libs.append('Qt5Charts') + +qt_libs = ['qt_util'] + base_libs -qt_libs = ['qt_util', 'Qt5Charts'] + base_libs cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, opendbc,'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv'] + qt_libs cabana_env = qt_env.Clone() diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 4f037ba595..6a9db120e9 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -33,7 +33,11 @@ int main(int argc, char *argv[]) { replay_flags |= REPLAY_FLAG_QCAMERA; } + // TODO: Remove when OpenpilotPrefix supports ZMQ +#ifndef __APPLE__ OpenpilotPrefix op_prefix; +#endif + CANMessages p(&app); int ret = 0; if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index c8208b2f14..b8ec0af346 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -268,7 +268,12 @@ void ChartView::setPlotAreaLeftPosition(int pos) { void ChartView::addSeries(const QString &msg_id, const Signal *sig) { QLineSeries *series = new QLineSeries(this); + + // TODO: Due to a bug in CameraWidget the camera frames + // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed +#ifndef __APPLE__ series->setUseOpenGL(true); +#endif chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); From f25239f7c516b19782926423754db7c31a29bd75 Mon Sep 17 00:00:00 2001 From: apache2046 Date: Tue, 17 Jan 2023 02:22:09 +0800 Subject: [PATCH 0644/1179] Radard: pdf not cdf (#26978) Update radard.py according the the equation, it is the probability density function (pdf) , not the cumulative distribution function (cdf) --- selfdrive/controls/radard.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index db87604e98..6a0902e510 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -35,7 +35,7 @@ class KalmanParams(): self.K = [[interp(dt, dts, K0)], [interp(dt, dts, K1)]] -def laplacian_cdf(x, mu, b): +def laplacian_pdf(x, mu, b): b = max(b, 1e-4) return math.exp(-abs(x-mu)/b) @@ -45,9 +45,9 @@ def match_vision_to_cluster(v_ego, lead, clusters): offset_vision_dist = lead.x[0] - RADAR_TO_CAMERA def prob(c): - prob_d = laplacian_cdf(c.dRel, offset_vision_dist, lead.xStd[0]) - prob_y = laplacian_cdf(c.yRel, -lead.y[0], lead.yStd[0]) - prob_v = laplacian_cdf(c.vRel + v_ego, lead.v[0], lead.vStd[0]) + prob_d = laplacian_pdf(c.dRel, offset_vision_dist, lead.xStd[0]) + prob_y = laplacian_pdf(c.yRel, -lead.y[0], lead.yStd[0]) + prob_v = laplacian_pdf(c.vRel + v_ego, lead.v[0], lead.vStd[0]) # This is isn't exactly right, but good heuristic return prob_d * prob_y * prob_v From 5cf1dd7f1377c65172a5dfaaade1396c17eb9e5a Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Mon, 16 Jan 2023 19:36:06 +0100 Subject: [PATCH 0645/1179] MacOS: mock gpio functions (#26971) --- common/gpio.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/common/gpio.cc b/common/gpio.cc index 9f5c211a4b..aa65c0bd9d 100644 --- a/common/gpio.cc +++ b/common/gpio.cc @@ -1,5 +1,20 @@ #include "common/gpio.h" +#ifdef __APPLE__ +int gpio_init(int pin_nr, bool output) { + return 0; +} + +int gpio_set(int pin_nr, bool high) { + return 0; +} + +int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) { + return 0; +} + +#else + #include #include @@ -63,3 +78,5 @@ int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int p close(fd); return rq.fd; } + +#endif From 657f1c13379f9b7f5b820ab17772fd6a37cd14d2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 16 Jan 2023 11:20:20 -0800 Subject: [PATCH 0646/1179] add bootstrap icons (#26980) * add bootstrap icons * pin --- third_party/bootstrap/.gitignore | 1 + third_party/bootstrap/bootstrap-icons.svg | 1 + third_party/bootstrap/pull.sh | 14 ++++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 third_party/bootstrap/.gitignore create mode 100644 third_party/bootstrap/bootstrap-icons.svg create mode 100755 third_party/bootstrap/pull.sh diff --git a/third_party/bootstrap/.gitignore b/third_party/bootstrap/.gitignore new file mode 100644 index 0000000000..ac06c0cf85 --- /dev/null +++ b/third_party/bootstrap/.gitignore @@ -0,0 +1 @@ +/icons/ diff --git a/third_party/bootstrap/bootstrap-icons.svg b/third_party/bootstrap/bootstrap-icons.svg new file mode 100644 index 0000000000..61f2720db4 --- /dev/null +++ b/third_party/bootstrap/bootstrap-icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/third_party/bootstrap/pull.sh b/third_party/bootstrap/pull.sh new file mode 100755 index 0000000000..0b03b4db9e --- /dev/null +++ b/third_party/bootstrap/pull.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +cd $DIR + +if [ ! -d icons/ ]; then + git clone https://github.com/twbs/icons/ +fi + +cd icons +git fetch --all +git checkout d5aa187483a1b0b186f87adcfa8576350d970d98 +cp bootstrap-icons.svg ../ From 164880524a705fee3ba0507e70c7c0069b1f7ef0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 17 Jan 2023 03:21:15 +0800 Subject: [PATCH 0647/1179] cabana: add a combobox to switch between signal and raw hex value (#26974) * switch between hex&signal value * sync display mode between view & model --- tools/cabana/historylog.cc | 36 +++++++++++++++++++++++++++++------- tools/cabana/historylog.h | 14 ++++++++++++-- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 485a21cc1b..c6ee7d9086 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -7,16 +7,24 @@ // HistoryLogModel +void HistoryLogModel::setDisplayType(HistoryLogModel::DisplayType type) { + if (display_type != type) { + display_type = type; + refresh(); + } +} + QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { + const bool display_signals = display_type == HistoryLogModel::Signals; if (role == Qt::DisplayRole) { const auto &m = messages[index.row()]; if (index.column() == 0) { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } - return !sigs.empty() ? QString::number(m.sig_values[index.column() - 1]) : m.data; - } else if (role == Qt::FontRole && index.column() == 1 && sigs.empty()) { + return display_signals ? QString::number(m.sig_values[index.column() - 1]) : m.data; + } else if (role == Qt::FontRole && index.column() == 1 && !display_signals) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); - } else if (role == Qt::ToolTipRole && index.column() > 0 && !sigs.empty()) { + } else if (role == Qt::ToolTipRole && index.column() > 0 && display_signals) { return tr("double click to open the chart"); } return {}; @@ -28,6 +36,7 @@ void HistoryLogModel::setMessage(const QString &message_id) { if (auto dbc_msg = dbc()->msg(msg_id)) { sigs = dbc_msg->getSignals(); } + display_type = !sigs.empty() ? HistoryLogModel::Signals : HistoryLogModel::Hex; filter_cmp = nullptr; refresh(); } @@ -41,15 +50,16 @@ void HistoryLogModel::refresh() { } QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, int role) const { + const bool display_signals = display_type == HistoryLogModel::Signals && !sigs.empty(); if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { if (section == 0) { return "Time"; } - return !sigs.empty() ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; - } else if (role == Qt::BackgroundRole && section > 0 && !sigs.empty()) { + return display_signals ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; + } else if (role == Qt::BackgroundRole && section > 0 && display_signals) { return QBrush(QColor(getColor(section - 1))); - } else if (role == Qt::ForegroundRole && section > 0 && !sigs.empty()) { + } else if (role == Qt::ForegroundRole && section > 0 && display_signals) { return QBrush(Qt::black); } } @@ -182,6 +192,11 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); QHBoxLayout *h = new QHBoxLayout(); + + display_type_cb = new QComboBox(); + display_type_cb->addItems({"Signal value", "Hex value"}); + h->addWidget(display_type_cb); + signals_cb = new QComboBox(this); signals_cb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); h->addWidget(signals_cb); @@ -202,6 +217,7 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(logs); QObject::connect(logs, &QTableView::doubleClicked, this, &LogsWidget::doubleClicked); + QObject::connect(display_type_cb, SIGNAL(activated(int)), this, SLOT(displayTypeChanged())); QObject::connect(signals_cb, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(comp_box, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); @@ -222,6 +238,8 @@ void LogsWidget::setMessage(const QString &message_id) { signals_cb->addItem(s->name.c_str()); } } + display_type_cb->setCurrentIndex(has_signals ? 0 : 1); + display_type_cb->setVisible(has_signals); comp_box->setVisible(has_signals); value_edit->setVisible(has_signals); signals_cb->setVisible(has_signals); @@ -245,6 +263,10 @@ void LogsWidget::setFilter() { cur_filter_text = value_edit->text(); } +void LogsWidget::displayTypeChanged() { + model->setDisplayType(display_type_cb->currentIndex() == 0 ? HistoryLogModel::Signals : HistoryLogModel::Hex); +} + void LogsWidget::showEvent(QShowEvent *event) { if (dynamic_mode->isChecked()) { model->refresh(); @@ -259,7 +281,7 @@ void LogsWidget::updateState() { void LogsWidget::doubleClicked(const QModelIndex &index) { if (index.isValid()) { - if (model->sigs.size() > 0 && index.column() > 0) { + if (model->display_type == HistoryLogModel::Signals && model->sigs.size() > 0 && index.column() > 0) { emit openChart(model->msg_id, model->sigs[index.column()-1]); } can->seekTo(model->messages[index.row()].mono_time / (double)1e9 - can->routeStartTime()); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index f20f51637a..1eea7e5eba 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -21,16 +21,24 @@ class HistoryLogModel : public QAbstractTableModel { Q_OBJECT public: + enum DisplayType { + Signals, + Hex + }; + HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} void setMessage(const QString &message_id); void updateState(); void setFilter(int sig_idx, const QString &value, std::function cmp); + void setDisplayType(DisplayType type); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void fetchMore(const QModelIndex &parent) override; inline bool canFetchMore(const QModelIndex &parent) const override { return has_more_data; } int rowCount(const QModelIndex &parent = QModelIndex()) const override { return messages.size(); } - int columnCount(const QModelIndex &parent = QModelIndex()) const override { return std::max(1ul, sigs.size()) + 1; } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { + return display_type == HistoryLogModel::Hex ? 2 : std::max(1ul, sigs.size()) + 1; + } void setDynamicMode(int state); void segmentsMerged(); void refresh(); @@ -55,6 +63,7 @@ public: std::deque messages; std::vector sigs; bool dynamic_mode = false; + DisplayType display_type = HistoryLogModel::Signals; }; class HistoryLog : public QTableView { @@ -76,6 +85,7 @@ signals: private slots: void setFilter(); + void displayTypeChanged(); private: void doubleClicked(const QModelIndex &index); @@ -84,7 +94,7 @@ private: HistoryLog *logs; HistoryLogModel *model; QCheckBox *dynamic_mode; - QComboBox *signals_cb, *comp_box; + QComboBox *signals_cb, *comp_box, *display_type_cb; QLineEdit *value_edit; QString cur_filter_text; }; From af97a96080428976abf2f65aa7deec109a015032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Mon, 16 Jan 2023 19:43:34 -0800 Subject: [PATCH 0648/1179] Add lane ekf (#26986) * change lane_kf pos * add lane back here --- SConstruct | 2 +- selfdrive/locationd/models/lane_kf.py | 105 ++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100755 selfdrive/locationd/models/lane_kf.py diff --git a/SConstruct b/SConstruct index b148a9116a..3051f4298d 100644 --- a/SConstruct +++ b/SConstruct @@ -387,10 +387,10 @@ rednose_config = { if arch != "larch64": rednose_config['to_build'].update({ 'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, [], rednose_deps), + 'lane': ('#selfdrive/locationd/models/lane_kf.py', True, [], rednose_deps), 'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, [], []), 'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, [], []), 'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, [], []), - 'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', True, [], rednose_deps), }) Export('rednose_config') diff --git a/selfdrive/locationd/models/lane_kf.py b/selfdrive/locationd/models/lane_kf.py new file mode 100755 index 0000000000..4d38fa8e09 --- /dev/null +++ b/selfdrive/locationd/models/lane_kf.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +import sys +import numpy as np +import sympy as sp + +from selfdrive.locationd.models.constants import ObservationKind +from rednose.helpers.ekf_sym import gen_code, EKF_sym + + +class LaneKalman(): + name = 'lane' + + @staticmethod + def generate_code(generated_dir): + # make functions and jacobians with sympy + # state variables + dim = 6 + state = sp.MatrixSymbol('state', dim, 1) + + dd = sp.Symbol('dd') # WARNING: NOT TIME + + # Time derivative of the state as a function of state + state_dot = sp.Matrix(np.zeros((dim, 1))) + state_dot[:3,0] = sp.Matrix(state[3:6,0]) + + # Basic descretization, 1st order intergrator + # Can be pretty bad if dt is big + f_sym = sp.Matrix(state) + dd*state_dot + + # + # Observation functions + # + h_lane_sym = sp.Matrix(state[:3,0]) + obs_eqs = [[h_lane_sym, ObservationKind.LANE_PT, None]] + gen_code(generated_dir, LaneKalman.name, f_sym, dd, state, obs_eqs, dim, dim) + + def __init__(self, generated_dir, pt_std=5): + # state + # left and right lane centers in ecef + # WARNING: this is not a temporal model + # the 'time' in this kalman filter is + # the distance traveled by the vehicle, + # which should approximately be the + # distance along the lane path + # a more logical parametrization + # states 0-2 are ecef coordinates distance d + # states 3-5 is the 3d "velocity" of the + # lane in ecef (m/m). + x_initial = np.array([0,0,0, + 0,0,0]) + + # state covariance + P_initial = np.diag([1e16, 1e16, 1e16, + 1**2, 1**2, 1**2]) + + # process noise + Q = np.diag([0.1**2, 0.1**2, 0.1**2, + 0.1**2, 0.1**2, 0.1*2]) + + self.dim_state = len(x_initial) + + # init filter + self.filter = EKF_sym(generated_dir, self.name, Q, x_initial, P_initial, x_initial.shape[0], P_initial.shape[0]) + self.obs_noise = {ObservationKind.LANE_PT: np.diag([pt_std**2]*3)} + + @property + def x(self): + return self.filter.state() + + @property + def P(self): + return self.filter.covs() + + def predict(self, t): + return self.filter.predict(t) + + def rts_smooth(self, estimates): + return self.filter.rts_smooth(estimates, norm_quats=False) + + + def init_state(self, state, covs_diag=None, covs=None, filter_time=None): + if covs_diag is not None: + P = np.diag(covs_diag) + elif covs is not None: + P = covs + else: + P = self.filter.covs() + self.filter.init_state(state, P, filter_time) + + def predict_and_observe(self, t, kind, data): + data = np.atleast_2d(data) + return self.filter.predict_and_update_batch(t, kind, data, self.get_R(kind, len(data))) + + def get_R(self, kind, n): + obs_noise = self.obs_noise[kind] + dim = obs_noise.shape[0] + R = np.zeros((n, dim, dim)) + for i in range(n): + R[i,:,:] = obs_noise + return R + + +if __name__ == "__main__": + generated_dir = sys.argv[2] + LaneKalman.generate_code(generated_dir) From a43a243b6e3852798390e0adc85f8f688f43b4d3 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Mon, 16 Jan 2023 21:02:30 -0700 Subject: [PATCH 0649/1179] Improve GPSbox tests (#26983) * add altitude testing * fix proc check Co-authored-by: Kurt Nistelberger --- tools/gpstest/README.md | 7 +- tools/gpstest/fuzzy_testing.py | 206 +++++++++++---------------- tools/gpstest/helper.py | 53 +++++++ tools/gpstest/remote_checker.py | 54 ------- tools/gpstest/rpc_server.py | 185 ++++++++++++++++++++++++ tools/gpstest/simulate_gps_signal.py | 25 ++-- 6 files changed, 342 insertions(+), 188 deletions(-) create mode 100644 tools/gpstest/helper.py delete mode 100644 tools/gpstest/remote_checker.py create mode 100644 tools/gpstest/rpc_server.py diff --git a/tools/gpstest/README.md b/tools/gpstest/README.md index 5aff0ee3d7..01f44df0ce 100644 --- a/tools/gpstest/README.md +++ b/tools/gpstest/README.md @@ -3,12 +3,9 @@ Testing the GPS receiver using GPS spoofing. At the moment only static location relpay is supported. # Usage -``` -# on host, start gps signal simulation -./run_static_lime.py -``` +on C3 run `rpc_server.py`, on host PC run `fuzzy_testing.py` -`run_static_lime.py` downloads the latest ephemeris file from +`simulate_gps_signal.py` downloads the latest ephemeris file from https://cddis.nasa.gov/archive/gnss/data/daily/20xx/brdc/. diff --git a/tools/gpstest/fuzzy_testing.py b/tools/gpstest/fuzzy_testing.py index bd204e7ae7..a2e130342c 100755 --- a/tools/gpstest/fuzzy_testing.py +++ b/tools/gpstest/fuzzy_testing.py @@ -1,147 +1,115 @@ #!/usr/bin/env python3 -import sys -import time -import random -import datetime as dt -import subprocess as sp +import argparse import multiprocessing -import threading -from typing import Tuple, Any +import rpyc # pylint: disable=import-error +from collections import defaultdict -from laika.downloader import download_nav -from laika.gps_time import GPSTime -from laika.helpers import ConstellationId +from helper import download_rinex, exec_LimeGPS_bin +from helper import get_random_coords, get_continuous_coords -cache_dir = '/tmp/gpstest/' +#------------------------------------------------------------------------------ +# this script is supposed to run on HOST PC +# limeSDR is unreliable via c3 USB +#------------------------------------------------------------------------------ -def download_rinex(): - # TODO: check if there is a better way to get the full brdc file for LimeGPS - gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) - utc_time = dt.datetime.utcnow() - dt.timedelta(1) - gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) - return download_nav(gps_time, cache_dir, ConstellationId.GPS) - - -def exec_LimeGPS_bin(rinex_file: str, location: str, duration: int): - # this functions should never return, cause return means, timeout is - # reached or it crashed - try: - cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", location] - sp.check_output(cmd, timeout=duration) - except sp.TimeoutExpired: - print("LimeGPS timeout reached!") - except Exception as e: - print(f"LimeGPS crashed: {str(e)}") - - -def run_lime_gps(rinex_file: str, location: str, duration: int): - print(f"LimeGPS {location} {duration}") - +def run_lime_gps(rinex_file: str, location: str, timeout: int): + # needs to run longer than the checker + timeout += 10 + print(f"LimeGPS {location} {timeout}") p = multiprocessing.Process(target=exec_LimeGPS_bin, - args=(rinex_file, location, duration)) + args=(rinex_file, location, timeout)) p.start() return p +con = None +def run_remote_checker(lat, lon, alt, duration, ip_addr): + global con + try: + con = rpyc.connect(ip_addr, 18861) + con._config['sync_request_timeout'] = duration+20 + except ConnectionRefusedError: + print("could not run remote checker is 'rpc_server.py' running???") + return False, None, None -def get_random_coords(lat, lon) -> Tuple[int, int]: - # jump around the world - # max values, lat: -90 to 90, lon: -180 to 180 + matched, log, info = con.root.exposed_run_checker(lat, lon, alt, + timeout=duration, + use_laikad=True) + con.close() # TODO: might wanna fetch more logs here + con = None - lat_add = random.random()*20 + 10 - lon_add = random.random()*20 + 20 - - lat = ((lat + lat_add + 90) % 180) - 90 - lon = ((lon + lon_add + 180) % 360) - 180 - return round(lat, 5), round(lon, 5) - -def get_continuous_coords(lat, lon) -> Tuple[int, int]: - # continuously move around the world - - lat_add = random.random()*0.01 - lon_add = random.random()*0.01 - - lat = ((lat + lat_add + 90) % 180) - 90 - lon = ((lon + lon_add + 180) % 360) - 180 - return round(lat, 5), round(lon, 5) - -rc_p: Any = None -def exec_remote_checker(lat, lon, duration, ip_addr): - global rc_p - # TODO: good enough for testing - remote_cmd = "export PYTHONPATH=/data/pythonpath && " - remote_cmd += "cd /data/openpilot && " - remote_cmd += f"timeout {duration} /usr/local/pyenv/shims/python tools/gpstest/remote_checker.py " - remote_cmd += f"{lat} {lon}" - - ssh_cmd = ["ssh", "-i", "/home/batman/openpilot/xx/phone/key/id_rsa", - f"comma@{ip_addr}"] - ssh_cmd += [remote_cmd] - - rc_p = sp.Popen(ssh_cmd, stdout=sp.PIPE) - rc_p.wait() - rc_output = rc_p.stdout.read() - print(f"Checker Result: {rc_output.strip().decode('utf-8')}") + print(f"Remote Checker: {log} {info}") + return matched, log, info -def run_remote_checker(spoof_proc, lat, lon, duration, ip_addr) -> bool: - checker_thread = threading.Thread(target=exec_remote_checker, - args=(lat, lon, duration, ip_addr)) - checker_thread.start() +stats = defaultdict(int) # type: ignore +keys = ['success', 'failed', 'ublox_fail', 'laikad_fail', 'proc_crash', 'checker_crash'] - tcnt = 0 - while True: - if not checker_thread.is_alive(): - # assume this only happens when the signal got matched - return True - - # the spoofing process has a timeout, kill checker if reached - if not spoof_proc.is_alive(): - rc_p.kill() - # spoofing process died, assume timeout - print("Spoofing process timeout") - return False - - print(f"Time elapsed: {tcnt}[s]", end = "\r") - time.sleep(1) - tcnt += 1 +def print_report(): + print("\nFuzzy testing report summary:") + for k in keys: + print(f" {k}: {stats[k]}") -def main(): - if len(sys.argv) < 2: - print(f"usage: {sys.argv[0]} [-c]") - ip_addr = sys.argv[1] +def update_stats(matched, log, info): + if matched: + stats['success'] += 1 + return - continuous_mode = False - if len(sys.argv) == 3 and sys.argv[2] == '-c': - print("Continuous Mode!") - continuous_mode = True + stats['failed'] += 1 + if log == "PROC CRASH": + stats['proc_crash'] += 1 + if log == "CHECKER CRASHED": + stats['checker_crash'] += 1 + if log == "TIMEOUT": + if "LAIKAD" in info: + stats['laikad_fail'] += 1 + else: # "UBLOX" in info + stats['ublox_fail'] += 1 + +def main(ip_addr, continuous_mode, timeout, pos): rinex_file = download_rinex() - duration = 60*3 # max runtime in seconds - lat, lon = get_random_coords(47.2020, 15.7403) + lat, lon, alt = pos + if lat == 0 and lon == 0 and alt == 0: + lat, lon, alt = get_random_coords(47.2020, 15.7403) - while True: - # spoof random location - spoof_proc = run_lime_gps(rinex_file, f"{lat},{lon},100", duration) - start_time = time.monotonic() + try: + while True: + # spoof random location + spoof_proc = run_lime_gps(rinex_file, f"{lat},{lon},{alt}", timeout) - # remote checker runs blocking - if not run_remote_checker(spoof_proc, lat, lon, duration, ip_addr): - # location could not be matched by ublox module - pass + # remote checker execs blocking + matched, log, info = run_remote_checker(lat, lon, alt, timeout, ip_addr) + update_stats(matched, log, info) + spoof_proc.terminate() + spoof_proc = None - end_time = time.monotonic() - spoof_proc.terminate() + if continuous_mode: + lat, lon, alt = get_continuous_coords(lat, lon, alt) + else: + lat, lon, alt = get_random_coords(lat, lon) + except KeyboardInterrupt: + if spoof_proc is not None: + spoof_proc.terminate() - # -1 to count process startup - print(f"Time to get Signal: {round(end_time - start_time - 1, 4)}") + if con is not None and not con.closed: + con.root.exposed_kill_procs() + con.close() + + print_report() - if continuous_mode: - lat, lon = get_continuous_coords(lat, lon) - else: - lat, lon = get_random_coords(lat, lon) if __name__ == "__main__": - main() + parser = argparse.ArgumentParser(description="Fuzzy test GPS stack with random locations.") + parser.add_argument("ip_addr", type=str) + parser.add_argument("-c", "--contin", type=bool, nargs='?', default=False, help='Continous location change') + parser.add_argument("-t", "--timeout", type=int, nargs='?', default=180, help='Timeout to get location') + + # for replaying a location + parser.add_argument("lat", type=float, nargs='?', default=0) + parser.add_argument("lon", type=float, nargs='?', default=0) + parser.add_argument("alt", type=float, nargs='?', default=0) + args = parser.parse_args() + main(args.ip_addr, args.contin, args.timeout, (args.lat, args.lon, args.alt)) diff --git a/tools/gpstest/helper.py b/tools/gpstest/helper.py new file mode 100644 index 0000000000..4f62e60db0 --- /dev/null +++ b/tools/gpstest/helper.py @@ -0,0 +1,53 @@ +import random +import datetime as dt +import subprocess as sp +from typing import Tuple + +from laika.downloader import download_nav +from laika.gps_time import GPSTime +from laika.helpers import ConstellationId + + +def download_rinex(): + # TODO: check if there is a better way to get the full brdc file for LimeGPS + gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) + utc_time = dt.datetime.utcnow() - dt.timedelta(1) + gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) + return download_nav(gps_time, '/tmp/gpstest/', ConstellationId.GPS) + + +def exec_LimeGPS_bin(rinex_file: str, location: str, duration: int): + # this functions should never return, cause return means, timeout is + # reached or it crashed + try: + cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", location] + sp.check_output(cmd, timeout=duration) + except sp.TimeoutExpired: + print("LimeGPS timeout reached!") + except Exception as e: + print(f"LimeGPS crashed: {str(e)}") + + +def get_random_coords(lat, lon) -> Tuple[float, float, int]: + # jump around the world + # max values, lat: -90 to 90, lon: -180 to 180 + + lat_add = random.random()*20 + 10 + lon_add = random.random()*20 + 20 + alt = random.randint(-10**3, 4*10**3) + + lat = ((lat + lat_add + 90) % 180) - 90 + lon = ((lon + lon_add + 180) % 360) - 180 + return round(lat, 5), round(lon, 5), alt + + +def get_continuous_coords(lat, lon, alt) -> Tuple[float, float, int]: + # continuously move around the world + lat_add = random.random()*0.01 + lon_add = random.random()*0.01 + alt_add = random.randint(-100, 100) + + lat = ((lat + lat_add + 90) % 180) - 90 + lon = ((lon + lon_add + 180) % 360) - 180 + alt += alt_add + return round(lat, 5), round(lon, 5), alt diff --git a/tools/gpstest/remote_checker.py b/tools/gpstest/remote_checker.py deleted file mode 100644 index a649a105c3..0000000000 --- a/tools/gpstest/remote_checker.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -import sys -import time -from typing import List - -from common.params import Params -import cereal.messaging as messaging -from selfdrive.manager.process_config import managed_processes - -DELTA = 0.001 -# assume running openpilot for now -procs: List[str] = []#"ubloxd", "pigeond"] - - -def main(): - if len(sys.argv) != 4: - print("args: ") - return - - quectel_mod = Params().get_bool("UbloxAvailable") - sol_lat = float(sys.argv[2]) - sol_lon = float(sys.argv[3]) - - for p in procs: - managed_processes[p].start() - time.sleep(0.5) # give time to startup - - socket = 'gpsLocation' if quectel_mod else 'gpsLocationExternal' - gps_sock = messaging.sub_sock(socket, timeout=0.1) - - # analyze until the location changed - while True: - events = messaging.drain_sock(gps_sock) - for e in events: - loc = e.gpsLocation if quectel_mod else e.gpsLocationExternal - lat = loc.latitude - lon = loc.longitude - - if abs(lat - sol_lat) < DELTA and abs(lon - sol_lon) < DELTA: - print("MATCH") - return - - time.sleep(0.1) - - for p in procs: - if not managed_processes[p].proc.is_alive(): - print(f"ERROR: '{p}' died") - return - - -if __name__ == "__main__": - main() - for p in procs: - managed_processes[p].stop() diff --git a/tools/gpstest/rpc_server.py b/tools/gpstest/rpc_server.py new file mode 100644 index 0000000000..b35c66d02d --- /dev/null +++ b/tools/gpstest/rpc_server.py @@ -0,0 +1,185 @@ +import os +import time +import shutil +from datetime import datetime +from collections import defaultdict + +import rpyc # pylint: disable=import-error +from rpyc.utils.server import ThreadedServer # pylint: disable=import-error + +#from common.params import Params +import cereal.messaging as messaging +from selfdrive.manager.process_config import managed_processes +from laika.lib.coordinates import ecef2geodetic + +DELTA = 0.001 +ALT_DELTA = 30 +MATCH_NUM = 10 +REPORT_STATS = 10 + +EPHEM_CACHE = "/data/params/d/LaikadEphemeris" +DOWNLOAD_CACHE = "/tmp/comma_download_cache" + +SERVER_LOG_FILE = "/tmp/fuzzy_server.log" +server_log = open(SERVER_LOG_FILE, "w+") + +def slog(msg): + server_log.write(f"{datetime.now().strftime('%H:%M:%S.%f')} | {msg}\n") + server_log.flush() + +def handle_laikad(msg): + if not hasattr(msg, 'correctedMeasurements'): + return None + + num_corr = len(msg.correctedMeasurements) + pos_ecef = msg.positionECEF.value + pos_geo = [] + if len(pos_ecef) > 0: + pos_geo = ecef2geodetic(pos_ecef) + + pos_std = msg.positionECEF.std + pos_valid = msg.positionECEF.valid + + slog(f"{num_corr} {pos_geo} {pos_ecef} {pos_std} {pos_valid}") + return pos_geo, (num_corr, pos_geo, list(pos_ecef), list(msg.positionECEF.std)) + +hw_msgs = 0 +ephem_msgs: dict = defaultdict(int) +def handle_ublox(msg): + global hw_msgs + + d = msg.to_dict() + + if 'hwStatus2' in d: + hw_msgs += 1 + + if 'ephemeris' in d: + ephem_msgs[msg.ephemeris.svId] += 1 + + num_meas = None + if 'measurementReport' in d: + num_meas = msg.measurementReport.numMeas + + return [hw_msgs, ephem_msgs, num_meas] + + +def start_procs(procs): + for p in procs: + managed_processes[p].start() + time.sleep(1) + +def kill_procs(procs, no_retry=False): + for p in procs: + managed_processes[p].stop() + time.sleep(1) + + if not no_retry: + for p in procs: + mp = managed_processes[p].proc + if mp is not None and mp.is_alive(): + managed_processes[p].stop() + time.sleep(3) + +def check_alive_procs(procs): + for p in procs: + mp = managed_processes[p].proc + if mp is None or not mp.is_alive(): + return False, p + return True, None + + +class RemoteCheckerService(rpyc.Service): + def on_connect(self, conn): + pass + + def on_disconnect(self, conn): + #kill_procs(self.procs, no_retry=False) + # this execution is delayed, it will kill the next run of laikad + # TODO: add polling to wait for everything is killed + pass + + def run_checker(self, slat, slon, salt, sockets, procs, timeout): + global hw_msgs, ephem_msgs + hw_msgs = 0 + ephem_msgs = defaultdict(int) + + slog(f"Run test: {slat} {slon} {salt}") + + # quectel_mod = Params().get_bool("UbloxAvailable") + + match_cnt = 0 + msg_cnt = 0 + stats_laikad = [] + stats_ublox = [] + + self.procs = procs + start_procs(procs) + sm = messaging.SubMaster(sockets) + + start_time = time.monotonic() + while True: + sm.update() + + if sm.updated['ubloxGnss']: + stats_ublox.append(handle_ublox(sm['ubloxGnss'])) + + if sm.updated['gnssMeasurements']: + pos_geo, stats = handle_laikad(sm['gnssMeasurements']) + if pos_geo is None or len(pos_geo) == 0: + continue + + match = all(abs(g-s) < DELTA for g,s in zip(pos_geo[:2], [slat, slon])) + match &= abs(pos_geo[2] - salt) < ALT_DELTA + if match: + match_cnt += 1 + if match_cnt >= MATCH_NUM: + return True, "MATCH", f"After: {round(time.monotonic() - start_time, 4)}" + + # keep some stats for error reporting + stats_laikad.append(stats) + + if (msg_cnt % 10) == 0: + a, p = check_alive_procs(procs) + if not a: + return False, "PROC CRASH", f"{p}" + msg_cnt += 1 + + if (time.monotonic() - start_time) > timeout: + h = f"LAIKAD: {stats_laikad[-REPORT_STATS:]}" + if len(h) == 0: + h = f"UBLOX: {stats_ublox[-REPORT_STATS:]}" + return False, "TIMEOUT", h + + + def exposed_run_checker(self, slat, slon, salt, timeout=180, use_laikad=True): + try: + procs = [] + sockets = [] + + if use_laikad: + procs.append("laikad") # pigeond, ubloxd # might wanna keep them running + sockets += ['ubloxGnss', 'gnssMeasurements'] + + if os.path.exists(EPHEM_CACHE): + os.remove(EPHEM_CACHE) + shutil.rmtree(DOWNLOAD_CACHE, ignore_errors=True) + + ret = self.run_checker(slat, slon, salt, sockets, procs, timeout) + kill_procs(procs) + return ret + + except Exception as e: + # always make sure processes get killed + kill_procs(procs) + return False, "CHECKER CRASHED", f"{str(e)}" + + + def exposed_kill_procs(self): + kill_procs(self.procs, no_retry=True) + + +if __name__ == "__main__": + print(f"Sever Log written to: {SERVER_LOG_FILE}") + t = ThreadedServer(RemoteCheckerService, port=18861) + t.start() + diff --git a/tools/gpstest/simulate_gps_signal.py b/tools/gpstest/simulate_gps_signal.py index a6aca1c404..da0f64eaca 100755 --- a/tools/gpstest/simulate_gps_signal.py +++ b/tools/gpstest/simulate_gps_signal.py @@ -16,7 +16,7 @@ cache_dir = '/tmp/gpstest/' def download_rinex(): # TODO: check if there is a better way to get the full brdc file for LimeGPS gps_time = GPSTime.from_datetime(dt.datetime.utcnow()) - utc_time = dt.datetime.utcnow() - dt.timedelta(1) + utc_time = dt.datetime.utcnow()# - dt.timedelta(1) gps_time = GPSTime.from_datetime(dt.datetime(utc_time.year, utc_time.month, utc_time.day)) return download_nav(gps_time, cache_dir, ConstellationId.GPS) @@ -36,11 +36,15 @@ def get_random_coords(lat, lon) -> Tuple[int, int]: # jump around the world return get_coords(lat, lon, 20, 20, 10, 20) -def run_limeSDR_loop(lat, lon, contin_sim, rinex_file, timeout): +def run_limeSDR_loop(lat, lon, alt, contin_sim, rinex_file, timeout): while True: try: - print(f"starting LimeGPS, Location: {lat},{lon}") - cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},100"] + # TODO: add starttime setting and altitude + # -t 2023/01/15,00:00:00 -T 2023/01/15,00:00:00 + # this needs to match the date of the navigation file + print(f"starting LimeGPS, Location: {lat} {lon} {alt}") + cmd = ["LimeGPS/LimeGPS", "-e", rinex_file, "-l", f"{lat},{lon},{alt}"] + print(f"CMD: {cmd}") sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) except KeyboardInterrupt: print("stopping LimeGPS") @@ -71,7 +75,7 @@ def run_hackRF_loop(lat, lon, rinex_file, timeout): try: print(f"starting gps-sdr-sim, Location: {lat},{lon}") # create 30second file and replay with hackrf endless - cmd = ["gps-sdr-sim/gps-sdr-sim", "-e", rinex_file, "-l", f"{lat},{lon},100", "-d", "30"] + cmd = ["gps-sdr-sim/gps-sdr-sim", "-e", rinex_file, "-l", f"{lat},{lon},-200", "-d", "30"] sp.check_output(cmd, stderr=sp.PIPE, timeout=timeout) # created in current working directory except Exception: @@ -90,7 +94,7 @@ def run_hackRF_loop(lat, lon, rinex_file, timeout): print(f"hackrf_transfer crashed:{str(e)}") -def main(lat, lon, jump_sim, contin_sim, hackrf_mode): +def main(lat, lon, alt, jump_sim, contin_sim, hackrf_mode): if hackrf_mode: if not os.path.exists('hackrf'): @@ -130,17 +134,18 @@ def main(lat, lon, jump_sim, contin_sim, hackrf_mode): if jump_sim: timeout = 30 - if not hackrf_mode: - run_limeSDR_loop(lat, lon, contin_sim, rinex_file, timeout) - else: + if hackrf_mode: run_hackRF_loop(lat, lon, rinex_file, timeout) + else: + run_limeSDR_loop(lat, lon, alt, contin_sim, rinex_file, timeout) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Simulate static [or random jumping] GPS signal.") parser.add_argument("lat", type=float, nargs='?', default=0) parser.add_argument("lon", type=float, nargs='?', default=0) + parser.add_argument("alt", type=float, nargs='?', default=0) parser.add_argument("--jump", action="store_true", help="signal that jumps around the world") parser.add_argument("--contin", action="store_true", help="continuously/slowly moving around the world") parser.add_argument("--hackrf", action="store_true", help="hackrf mode (DEFAULT: LimeSDR)") args = parser.parse_args() - main(args.lat, args.lon, args.jump, args.contin, args.hackrf) + main(args.lat, args.lon, args.alt, args.jump, args.contin, args.hackrf) From 2ef127ebc05c609dffff506a64fa3c600d7b194b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 18 Jan 2023 05:09:18 +0800 Subject: [PATCH 0650/1179] cabana: more compact form (#26985) --- tools/cabana/signaledit.cc | 54 ++++++++++++++++++++++---------------- tools/cabana/signaledit.h | 2 +- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 3845e72be1..2a92e03461 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -9,50 +9,56 @@ // SignalForm SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { - QFormLayout *form_layout = new QFormLayout(this); + auto double_validator = new QDoubleValidator(this); + QVBoxLayout *main_layout = new QVBoxLayout(this); + QFormLayout *form_layout = new QFormLayout(); + main_layout->addLayout(form_layout); name = new QLineEdit(); name->setValidator(new QRegExpValidator(QRegExp("^(\\w+)"), name)); form_layout->addRow(tr("Name"), name); + QHBoxLayout *hl = new QHBoxLayout(this); size = new QSpinBox(); size->setMinimum(1); - form_layout->addRow(tr("Size"), size); - + hl->addWidget(size); endianness = new QComboBox(); - endianness->addItems({"Little", "Big"}); - form_layout->addRow(tr("Endianness"), endianness); - - form_layout->addRow(tr("lsb"), lsb = new QLabel()); - form_layout->addRow(tr("msb"), msb = new QLabel()); - + endianness->addItems({"Little Endianness", "Big Endianness"}); + hl->addWidget(endianness); sign = new QComboBox(); sign->addItems({"Signed", "Unsigned"}); - form_layout->addRow(tr("sign"), sign); - - auto double_validator = new QDoubleValidator(this); - - factor = new QLineEdit(); - factor->setValidator(double_validator); - form_layout->addRow(tr("Factor"), factor); + hl->addWidget(sign); + form_layout->addRow(tr("Size"), hl); offset = new QLineEdit(); offset->setValidator(double_validator); form_layout->addRow(tr("Offset"), offset); + factor = new QLineEdit(); + factor->setValidator(double_validator); + form_layout->addRow(tr("Factor"), factor); + + expand_btn = new QToolButton(this); + expand_btn->setText(tr("more...")); + main_layout->addWidget(expand_btn, 0, Qt::AlignRight); // TODO: parse the following parameters in opendbc + QWidget *extra_container = new QWidget(this); + QFormLayout *extra_layout = new QFormLayout(extra_container); unit = new QLineEdit(); - form_layout->addRow(tr("Unit"), unit); + extra_layout->addRow(tr("Unit"), unit); comment = new QLineEdit(); - form_layout->addRow(tr("Comment"), comment); + extra_layout->addRow(tr("Comment"), comment); min_val = new QLineEdit(); min_val->setValidator(double_validator); - form_layout->addRow(tr("Minimum value"), min_val); + extra_layout->addRow(tr("Minimum value"), min_val); max_val = new QLineEdit(); max_val->setValidator(double_validator); - form_layout->addRow(tr("Maximum value"), max_val); + extra_layout->addRow(tr("Maximum value"), max_val); val_desc = new QLineEdit(); - form_layout->addRow(tr("Value descriptions"), val_desc); + extra_layout->addRow(tr("Value descriptions"), val_desc); + + main_layout->addWidget(extra_container); + extra_container->setVisible(false); QObject::connect(name, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); QObject::connect(factor, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); @@ -60,6 +66,10 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { QObject::connect(size, &QSpinBox::editingFinished, this, &SignalForm::changed); QObject::connect(sign, SIGNAL(activated(int)), SIGNAL(changed())); QObject::connect(endianness, SIGNAL(activated(int)), SIGNAL(changed())); + QObject::connect(expand_btn, &QToolButton::clicked, [=]() { + extra_container->setVisible(!extra_container->isVisible()); + expand_btn->setText(extra_container->isVisible() ? tr("less...") : tr("more...")); + }); } void SignalForm::textBoxEditingFinished() { @@ -180,8 +190,6 @@ void SignalEdit::updateForm(bool visible) { form->sign->setCurrentIndex(sig->is_signed ? 0 : 1); form->factor->setText(QString::number(sig->factor)); form->offset->setText(QString::number(sig->offset)); - form->msb->setText(QString::number(sig->msb)); - form->lsb->setText(QString::number(sig->lsb)); form->size->setValue(sig->size); } form->setVisible(visible); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index d7b9084e7f..a18f1d34f0 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -17,9 +17,9 @@ public: void textBoxEditingFinished(); QLineEdit *name, *unit, *comment, *val_desc, *offset, *factor, *min_val, *max_val; - QLabel *lsb, *msb; QSpinBox *size; QComboBox *sign, *endianness; + QToolButton *expand_btn; signals: void changed(); From bc8e2032f7aaafb172e4b2505e7cdc5da1970eb9 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Tue, 17 Jan 2023 14:16:28 -0800 Subject: [PATCH 0651/1179] camerad: reduce ox LFM noise (#26949) * wip * make separate score func * n4ot g * clean up * remove * simplify * b2b * more than 0 * this is fine * led * balance costs * clean up * no if tici * box view * new baselines * Revert "new baselines" This reverts commit f7a5d059eda70fa4d49e3024923da30e8821f42b. * Revert "box view" This reverts commit a57924be36e7d6abc2585aca9575c74cd583ef86. * maximize dcg Co-authored-by: Comma Dev1ce --- system/camerad/cameras/camera_qcom2.cc | 25 +++++++++++++------------ system/camerad/cameras/sensor2_i2c.h | 8 ++++---- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 8e2ad7bd91..92b3bde413 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -60,15 +60,15 @@ CameraInfo cameras_supported[CAMERA_ID_MAX] = { const float DC_GAIN_AR0231 = 2.5; const float DC_GAIN_OX03C10 = 7.32; -const float DC_GAIN_ON_GREY_AR0231= 0.2; +const float DC_GAIN_ON_GREY_AR0231 = 0.2; const float DC_GAIN_OFF_GREY_AR0231 = 0.3; -const float DC_GAIN_ON_GREY_OX03C10= 0.25; -const float DC_GAIN_OFF_GREY_OX03C10 = 0.35; +const float DC_GAIN_ON_GREY_OX03C10 = 0.9; +const float DC_GAIN_OFF_GREY_OX03C10 = 1.0; const int DC_GAIN_MIN_WEIGHT_AR0231 = 0; const int DC_GAIN_MAX_WEIGHT_AR0231 = 1; -const int DC_GAIN_MIN_WEIGHT_OX03C10 = 16; -const int DC_GAIN_MAX_WEIGHT_OX03C10 = 32; +const int DC_GAIN_MIN_WEIGHT_OX03C10 = 1; // always on is fine +const int DC_GAIN_MAX_WEIGHT_OX03C10 = 1; const float TARGET_GREY_FACTOR_AR0231 = 1.0; const float TARGET_GREY_FACTOR_OX03C10 = 0.02; @@ -1172,15 +1172,16 @@ void CameraState::set_camera_exposure(float grey_frac) { }; sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, true); } else if (camera_id == CAMERA_ID_OX03C10) { - // t_HCG + t_LCG + t_VS on LPD, t_SPD on SPD - uint32_t hcg_time = std::max((dc_gain_weight * exposure_time / dc_gain_max_weight), 0); - uint32_t lcg_time = std::max(((dc_gain_max_weight - dc_gain_weight) * exposure_time / dc_gain_max_weight), 0); - // uint32_t spd_time = std::max(hcg_time / 16, (uint32_t)exposure_time_min); - uint32_t vs_time = std::min(std::max((uint32_t)exposure_time / 128, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10); - uint32_t spd_time = vs_time; + // t_HCG&t_LCG + t_VS on LPD, t_SPD on SPD + uint32_t hcg_time = exposure_time; + uint32_t lcg_time = hcg_time; + uint32_t spd_time = exposure_time_max + VS_TIME_MAX_OX03C10; + uint32_t vs_time = std::min(std::max((uint32_t)exposure_time / 40, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10); uint32_t real_gain = ox03c10_analog_gains_reg[new_exp_g]; uint32_t min_gain = ox03c10_analog_gains_reg[0]; + uint32_t spd_gain = 0xF00; + struct i2c_random_wr_payload exp_reg_array[] = { {0x3501, hcg_time>>8}, {0x3502, hcg_time&0xFF}, {0x3581, lcg_time>>8}, {0x3582, lcg_time&0xFF}, @@ -1189,7 +1190,7 @@ void CameraState::set_camera_exposure(float grey_frac) { {0x3508, real_gain>>8}, {0x3509, real_gain&0xFF}, {0x3588, min_gain>>8}, {0x3589, min_gain&0xFF}, - {0x3548, min_gain>>8}, {0x3549, min_gain&0xFF}, + {0x3548, spd_gain>>8}, {0x3549, spd_gain&0xFF}, {0x35c8, min_gain>>8}, {0x35c9, min_gain&0xFF}, }; sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, false); diff --git a/system/camerad/cameras/sensor2_i2c.h b/system/camerad/cameras/sensor2_i2c.h index ab51059d9a..83fcb8f7a9 100644 --- a/system/camerad/cameras/sensor2_i2c.h +++ b/system/camerad/cameras/sensor2_i2c.h @@ -126,7 +126,7 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { {0x3219, 0x08}, {0x3506, 0x20}, {0x3507, 0x00}, // hcg fine exposure - {0x350a, 0x04}, {0x350b, 0x00}, {0x350c, 0x00}, // hcg digital gain + {0x350a, 0x01}, {0x350b, 0x00}, {0x350c, 0x00}, // hcg digital gain {0x3586, 0x40}, {0x3587, 0x00}, // lcg fine exposure {0x358a, 0x01}, {0x358b, 0x00}, {0x358c, 0x00}, // lcg digital gain @@ -711,11 +711,11 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { {0x4221, 0x03}, // this is changed from 1 -> 3 // DCG exposure coarse - {0x3501, 0x01}, {0x3502, 0xc8}, + // {0x3501, 0x01}, {0x3502, 0xc8}, // SPD exposure coarse - {0x3541, 0x01}, {0x3542, 0xc8}, + // {0x3541, 0x01}, {0x3542, 0xc8}, // VS exposure coarse - {0x35c1, 0x00}, {0x35c2, 0x01}, + // {0x35c1, 0x00}, {0x35c2, 0x01}, // crc reference {0x420e, 0x66}, {0x420f, 0x5d}, {0x4210, 0xa8}, {0x4211, 0x55}, From fe9fadaa55760d3940d7ccabd1e7edbf3bed1b1a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 17 Jan 2023 14:22:47 -0800 Subject: [PATCH 0652/1179] Ioniq 2019 EV: add FW versions (#26988) * add FW from 26e73a0e32642dc4|2023-01-16--13-05-28 * duplicate --- 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 c4fda42b63..ec7605657b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -448,11 +448,13 @@ FW_VERSIONS = { b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7501 4AEEC104', b'\xf1\x00AE MDPS C 1.00 1.03 56310/G7300 4AEEC103', b'\xf1\x00AE MDPS C 1.00 1.03 56310G7300\x00 4AEEC103', + b'\xf1\x00AE MDPS C 1.00 1.04 56310/G7301 4AEEC104', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G7200 160418', b'\xf1\x00AEE MFC AT USA LHD 1.00 1.00 95740-G2400 180222', b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2300 170703', + b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.00 95740-G2400 180222', ], }, CAR.IONIQ_HEV_2022: { From e5931ed7624208e1413cb06e1522eb704948e1c0 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Tue, 17 Jan 2023 17:17:10 -0800 Subject: [PATCH 0653/1179] boardd: retune LED curve for new autoexposure (#26991) * use il only * works on both Co-authored-by: Comma Dev1ce --- selfdrive/boardd/boardd.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 1f1249194d..e626882191 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -48,8 +48,8 @@ #define MAX_IR_POWER 0.5f #define MIN_IR_POWER 0.0f -#define CUTOFF_IL 200 -#define SATURATE_IL 1600 +#define CUTOFF_IL 400 +#define SATURATE_IL 1000 #define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a') using namespace std::chrono_literals; @@ -540,9 +540,8 @@ void peripheral_control_thread(Panda *panda, bool no_fan_control) { if (sm.updated("driverCameraState")) { auto event = sm["driverCameraState"]; int cur_integ_lines = event.getDriverCameraState().getIntegLines(); - float cur_gain = event.getDriverCameraState().getGain(); - cur_integ_lines = integ_lines_filter.update(cur_integ_lines * cur_gain); + cur_integ_lines = integ_lines_filter.update(cur_integ_lines); last_front_frame_t = event.getLogMonoTime(); if (cur_integ_lines <= CUTOFF_IL) { From ef42652368bb56a93e75f172062ac9f6aca29563 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 17 Jan 2023 19:52:06 -0800 Subject: [PATCH 0654/1179] fix typo AR0321 -> AR0231 (#26993) --- Jenkinsfile | 2 +- cereal | 2 +- selfdrive/ui/ui.cc | 2 +- system/camerad/cameras/camera_common.cc | 2 +- system/camerad/test/test_camerad.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3b16b3f112..bd138bed76 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -152,7 +152,7 @@ pipeline { stage('camerad-ar') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } steps { - phone_steps("tici-ar0321", [ + phone_steps("tici-ar0231", [ ["build", "cd selfdrive/manager && ./build.py"], ["test camerad", "python system/camerad/test/test_camerad.py"], ["test exposure", "python system/camerad/test/test_exposure.py"], diff --git a/cereal b/cereal index c0d9abf6f7..6b91a52d3d 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit c0d9abf6f7c7de140c41af10e322e226d900ef99 +Subproject commit 6b91a52d3d7bd62507f26ac1321338d4cfd2dc03 diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index c62d737481..4df963167a 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -163,7 +163,7 @@ static void update_state(UIState *s) { scene.longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); } if (sm.updated("wideRoadCameraState")) { - float scale = (sm["wideRoadCameraState"].getWideRoadCameraState().getSensor() == cereal::FrameData::ImageSensor::AR0321) ? 6.0f : 1.0f; + float scale = (sm["wideRoadCameraState"].getWideRoadCameraState().getSensor() == cereal::FrameData::ImageSensor::AR0231) ? 6.0f : 1.0f; scene.light_sensor = std::max(100.0f - scale * sm["wideRoadCameraState"].getWideRoadCameraState().getExposureValPercent(), 0.0f); } scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 30e2810ec4..7ee3738057 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -167,7 +167,7 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr framed.setExposureValPercent(perc); if (c->camera_id == CAMERA_ID_AR0231) { - framed.setSensor(cereal::FrameData::ImageSensor::AR0321); + framed.setSensor(cereal::FrameData::ImageSensor::AR0231); } else if (c->camera_id == CAMERA_ID_OX03C10) { framed.setSensor(cereal::FrameData::ImageSensor::OX03C10); } diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index 6c2ef1c7bc..34411e4ef1 100755 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -10,7 +10,7 @@ from selfdrive.manager.process_config import managed_processes from system.hardware import TICI TEST_TIMESPAN = 30 -LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0321: 0.5, # ARs use synced pulses for frame starts +LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 0.5, # ARs use synced pulses for frame starts log.FrameData.ImageSensor.ox03c10: 1.0} # OXs react to out-of-sync at next frame CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState') From 2fd48e26a3580a52d76b43dada7fc04eb2cbe669 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 17 Jan 2023 22:00:01 -0800 Subject: [PATCH 0655/1179] Deprecate canMonoTimes (#26992) * not used anywhere * bump cereal * also here --- cereal | 2 +- selfdrive/controls/controlsd.py | 1 - selfdrive/controls/radard.py | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cereal b/cereal index 6b91a52d3d..b27131e72f 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 6b91a52d3d7bd62507f26ac1321338d4cfd2dc03 +Subproject commit b27131e72f987f3bd0fcd28a42f686b583709e1f diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 1d92cd4fb2..ac36df7aa2 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -757,7 +757,6 @@ class Controls: controlsState.alertType = current_alert.alert_type controlsState.alertSound = current_alert.audible_alert - controlsState.canMonoTimes = list(CS.canMonoTimes) controlsState.longitudinalPlanMonoTime = self.sm.logMonoTime['longitudinalPlan'] controlsState.lateralPlanMonoTime = self.sm.logMonoTime['lateralPlan'] controlsState.enabled = self.enabled diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py index 6a0902e510..34f0f274fe 100755 --- a/selfdrive/controls/radard.py +++ b/selfdrive/controls/radard.py @@ -165,7 +165,6 @@ class RadarD(): dat.valid = sm.all_checks() and len(rr.errors) == 0 radarState = dat.radarState radarState.mdMonoTime = sm.logMonoTime['modelV2'] - radarState.canMonoTimes = list(rr.canMonoTimes) radarState.radarErrors = list(rr.errors) radarState.carStateMonoTime = sm.logMonoTime['carState'] From ef89ec3eb095df8604d8c66009413444b634b1e6 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 18 Jan 2023 19:31:40 +0100 Subject: [PATCH 0656/1179] cabana: fix segfault on descending sort (#26995) --- tools/cabana/messageswidget.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index fd0bc68514..ffbca1b1df 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -96,8 +96,9 @@ void MessageListModel::sortMessages() { beginResetModel(); if (sort_column == 0) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - bool ret = std::pair{msgName(l), l} < std::pair{msgName(r), r}; - return sort_order == Qt::AscendingOrder ? ret : !ret; + auto ll = std::pair{msgName(l), l}; + auto rr = std::pair{msgName(r), r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { @@ -105,13 +106,15 @@ void MessageListModel::sortMessages() { }); } else if (sort_column == 2) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - bool ret = std::pair{can->lastMessage(l).freq, l} < std::pair{can->lastMessage(r).freq, r}; - return sort_order == Qt::AscendingOrder ? ret : !ret; + auto ll = std::pair{can->lastMessage(l).freq, l}; + auto rr = std::pair{can->lastMessage(r).freq, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } else if (sort_column == 3) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - bool ret = std::pair{can->lastMessage(l).count, l} < std::pair{can->lastMessage(r).count, r}; - return sort_order == Qt::AscendingOrder ? ret : !ret; + auto ll = std::pair{can->lastMessage(l).count, l}; + auto rr = std::pair{can->lastMessage(r).count, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } endResetModel(); From e69e4f4052927b1053145d06cc8144f209f84f11 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 18 Jan 2023 19:32:04 +0100 Subject: [PATCH 0657/1179] cabana: sort bus:id numerically instead of alphabetically (#26996) * cabana: sort bus:id numerically instead of alphabetically * Update tools/cabana/canmessages.h --- tools/cabana/canmessages.cc | 2 ++ tools/cabana/canmessages.h | 2 ++ tools/cabana/messageswidget.cc | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index 6e19eb440f..a473313f90 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -64,6 +64,8 @@ bool CANMessages::eventFilter(const Event *event) { QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); CanData &data = (*new_msgs)[id]; data.ts = current_sec; + data.src = c.getSrc(); + data.address = c.getAddress(); data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); data.count = ++counters[id]; if (double delta = (current_sec - counters_begin_sec); delta > 0) { diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index ea43933565..2451793742 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -11,6 +11,8 @@ struct CanData { double ts = 0.; + uint8_t src = 0; + uint32_t address = 0; uint32_t count = 0; uint32_t freq = 0; QByteArray dat; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index ffbca1b1df..3477abe37b 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -102,7 +102,9 @@ void MessageListModel::sortMessages() { }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - return sort_order == Qt::AscendingOrder ? l < r : l > r; + auto ll = std::tuple{can->lastMessage(l).src, can->lastMessage(l).address, l}; + auto rr = std::tuple{can->lastMessage(r).src, can->lastMessage(r).address, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } else if (sort_column == 2) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { From 351d97ab5a72f3dfb22de2e7e321c4cc447a44c9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 19 Jan 2023 03:40:44 +0800 Subject: [PATCH 0658/1179] cabana: make video resizable (#26998) --- tools/cabana/chartswidget.cc | 1 - tools/cabana/mainwin.cc | 19 ++++++++++++------- tools/cabana/mainwin.h | 4 +++- tools/cabana/settings.cc | 2 ++ tools/cabana/settings.h | 4 +++- tools/cabana/videowidget.cc | 30 +++++++++++++++--------------- tools/cabana/videowidget.h | 2 +- 7 files changed, 36 insertions(+), 26 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index b8ec0af346..33e133d140 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -16,7 +16,6 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 9df5894b90..af89d26f4f 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -116,19 +116,23 @@ void MainWindow::createDockWindows() { addDockWidget(Qt::LeftDockWidgetArea, dock); // right panel - QWidget *right_container = new QWidget(this); - r_layout = new QVBoxLayout(right_container); charts_widget = new ChartsWidget(this); + QWidget *charts_container = new QWidget(this); + charts_layout = new QVBoxLayout(charts_container); + charts_layout->setContentsMargins(0, 0, 0, 0); + charts_layout->addWidget(charts_widget); + video_widget = new VideoWidget(this); - r_layout->addWidget(video_widget, 0, Qt::AlignTop); - r_layout->addWidget(charts_widget, 1); - r_layout->addStretch(0); + video_splitter = new QSplitter(Qt::Vertical,this); + video_splitter->addWidget(video_widget); + video_splitter->addWidget(charts_container); + video_splitter->restoreState(settings.video_splitter_state); video_dock = new QDockWidget(can->routeName(), this); video_dock->setObjectName(tr("VideoPanel")); video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); - video_dock->setWidget(right_container); + video_dock->setWidget(video_splitter); addDockWidget(Qt::RightDockWidgetArea, video_dock); } @@ -239,7 +243,7 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); - r_layout->insertWidget(2, charts_widget, 1); + charts_layout->insertWidget(0, charts_widget, 1); floating_window->deleteLater(); floating_window = nullptr; } else if (!dock && !floating_window) { @@ -270,6 +274,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { settings.geometry = saveGeometry(); settings.window_state = saveState(); + settings.video_splitter_state = video_splitter->saveState(); settings.save(); QWidget::closeEvent(event); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index f8b5f92349..3e80ffa1aa 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "tools/cabana/chartswidget.h" @@ -51,8 +52,9 @@ protected: DetailWidget *detail_widget; ChartsWidget *charts_widget; QWidget *floating_window = nullptr; - QVBoxLayout *r_layout; + QVBoxLayout *charts_layout; QProgressBar *progress_bar; QJsonDocument fingerprint_to_dbc; QComboBox *dbc_combo; + QSplitter *video_splitter;; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 5e7f833317..a5b490e9fb 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -21,6 +21,7 @@ void Settings::save() { s.setValue("last_dir", last_dir); s.setValue("window_state", window_state); s.setValue("geometry", geometry); + s.setValue("video_splitter_state", video_splitter_state); } void Settings::load() { @@ -32,6 +33,7 @@ void Settings::load() { last_dir = s.value("last_dir", QDir::homePath()).toString(); window_state = s.value("window_state").toByteArray(); geometry = s.value("geometry").toByteArray(); + video_splitter_state = s.value("video_splitter_state").toByteArray(); } // SettingsDlg diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index d231a3a53a..76be2f1487 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -18,7 +18,9 @@ public: int chart_height = 200; int max_chart_x_range = 3 * 60; // 3 minutes QString last_dir; - QByteArray window_state, geometry; + QByteArray geometry; + QByteArray video_splitter_state; + QByteArray window_state; signals: void changed(); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index ed4354ce65..99d82daccf 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -17,20 +17,16 @@ inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } -VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { - setFrameShape(QFrame::StyledPanel); - setFrameShadow(QFrame::Sunken); - QHBoxLayout *containter_layout = new QHBoxLayout(this); - QVBoxLayout *main_layout = new QVBoxLayout(); - main_layout->setContentsMargins(0, 0, 0, 0); +VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + QFrame *frame = new QFrame(this); + frame->setFrameShape(QFrame::StyledPanel); + frame->setFrameShadow(QFrame::Sunken); + main_layout->addWidget(frame); - containter_layout->addStretch(1); - containter_layout->addLayout(main_layout); - containter_layout->addStretch(1); - - cam_widget = new CameraWidget("camerad", can->visionStreamType(), false, this); - cam_widget->setFixedSize(parent->width(), parent->width() / 1.596); - main_layout->addWidget(cam_widget); + QVBoxLayout *frame_layout = new QVBoxLayout(frame); + cam_widget = new CameraWidget("camerad", can->visionStreamType(), false); + frame_layout->addWidget(cam_widget); // slider controls QHBoxLayout *slider_layout = new QHBoxLayout(); @@ -43,7 +39,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { end_time_label = new QLabel(this); slider_layout->addWidget(end_time_label); - main_layout->addLayout(slider_layout); + frame_layout->addLayout(slider_layout); // btn controls QHBoxLayout *control_layout = new QHBoxLayout(); @@ -61,7 +57,11 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) { group->addButton(btn); if (speed == 1.0) btn->setChecked(true); } - main_layout->addLayout(control_layout); + frame_layout->addLayout(control_layout); + + cam_widget->setMinimumHeight(100); + cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); 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)); }); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index ec8bc4bec4..515dab6c87 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -35,7 +35,7 @@ private: QSize thumbnail_size = {}; }; -class VideoWidget : public QFrame { +class VideoWidget : public QWidget { Q_OBJECT public: From c21d9408a191ba8e3303f2459d1f7476fefd35ba Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 19 Jan 2023 05:19:23 +0800 Subject: [PATCH 0659/1179] cabana: use bootstrap icons (#26981) * use bootstrap icons * typo * build into asset_obj * add to files_common --- SConstruct | 2 +- release/files_common | 1 + selfdrive/assets/assets.qrc | 1 + selfdrive/ui/SConscript | 1 + selfdrive/ui/qt/util.cc | 37 ++++++++++++++++++++++++++++++++++++ selfdrive/ui/qt/util.h | 1 + tools/cabana/SConscript | 4 ++-- tools/cabana/chartswidget.cc | 13 ++++++++----- tools/cabana/detailwidget.cc | 5 +++-- tools/cabana/signaledit.cc | 6 ++++-- tools/cabana/videowidget.cc | 15 +++++++++++---- tools/cabana/videowidget.h | 1 + 12 files changed, 71 insertions(+), 16 deletions(-) diff --git a/SConstruct b/SConstruct index 3051f4298d..8864164f15 100644 --- a/SConstruct +++ b/SConstruct @@ -282,7 +282,7 @@ Export('envCython') # Qt build environment qt_env = env.Clone() -qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus"] +qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus", "Xml"] qt_libs = [] if arch == "Darwin": diff --git a/release/files_common b/release/files_common index 3d07924a91..0dc0e96226 100644 --- a/release/files_common +++ b/release/files_common @@ -436,6 +436,7 @@ third_party/acados/larch64/** third_party/acados/include/** third_party/acados/acados_template/** +third_party/bootstrap/** third_party/qt5/larch64/bin/** scripts/update_now.sh diff --git a/selfdrive/assets/assets.qrc b/selfdrive/assets/assets.qrc index 39be41aa65..79a1a1e272 100644 --- a/selfdrive/assets/assets.qrc +++ b/selfdrive/assets/assets.qrc @@ -1,5 +1,6 @@ + ../../third_party/bootstrap/bootstrap-icons.svg img_continue_triangle.svg img_circled_check.svg img_circled_slash.svg diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 669c214746..3ce7a0505d 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -41,6 +41,7 @@ assets_src = "#selfdrive/assets/assets.qrc" qt_env.Command(assets, assets_src, f"rcc $SOURCES -o $TARGET") qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, "#selfdrive/assets/assets.o"])) asset_obj = qt_env.Object("assets", assets) +Export('asset_obj') # build soundd qt_env.Program("soundd/_soundd", ["soundd/main.cc", "soundd/sound.cc"], LIBS=qt_libs) diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index 59903e3376..4f52310649 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -2,11 +2,14 @@ #include #include +#include #include #include #include #include #include +#include +#include #include "common/params.h" #include "common/swaglog.h" @@ -218,3 +221,37 @@ QColor interpColor(float xv, std::vector xp, std::vector fp) { ); } } + +static QHash load_bootstrap_icons() { + QHash icons; + + QFile f(":/bootstrap-icons.svg"); + if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { + QDomDocument xml; + xml.setContent(&f); + QDomNode n = xml.documentElement().firstChild(); + while (!n.isNull()) { + QDomElement e = n.toElement(); + if (!e.isNull() && e.hasAttribute("id")) { + QString svg_str; + QTextStream stream(&svg_str); + n.save(stream, 0); + svg_str.replace("", ""); + icons[e.attribute("id")] = svg_str.toUtf8(); + } + n = n.nextSibling(); + } + } + return icons; +} + +QPixmap bootstrapPixmap(const QString &id) { + static QHash icons = load_bootstrap_icons(); + + QPixmap pixmap; + if (auto it = icons.find(id); it != icons.end()) { + pixmap.loadFromData(it.value(), "svg"); + } + return pixmap; +} diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h index 61a27a8669..3188f3f9b9 100644 --- a/selfdrive/ui/qt/util.h +++ b/selfdrive/ui/qt/util.h @@ -22,6 +22,7 @@ void swagLogMessageHandler(QtMsgType type, const QMessageLogContext &context, co void initApp(int argc, char *argv[]); QWidget* topWidget (QWidget* widget); QPixmap loadPixmap(const QString &fileName, const QSize &size = {}, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio); +QPixmap bootstrapPixmap(const QString &id); QRect getTextRect(QPainter &p, int flags, const QString &text); void drawRoundedRect(QPainter &painter, const QRectF &rect, qreal xRadiusTop, qreal yRadiusTop, qreal xRadiusBottom, qreal yRadiusBottom); diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 507b98ae88..6726a042ad 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -1,6 +1,6 @@ import os Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', - 'cereal', 'transformations', 'widgets', 'opendbc') + 'cereal', 'transformations', 'widgets', 'opendbc', 'asset_obj') base_frameworks = qt_env['FRAMEWORKS'] base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq', @@ -22,7 +22,7 @@ prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) -cabana_env.Program('_cabana', ['cabana.cc', cabana_lib], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) +cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 33e133d140..69229baa64 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -12,6 +12,8 @@ #include #include +#include "selfdrive/ui/qt/util.h" + // ChartsWidget ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { @@ -19,14 +21,15 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); + toolbar->setIconSize({16, 16}); title_label = new QLabel(); title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(title_label); show_all_values_btn = toolbar->addAction(""); toolbar->addWidget(range_label = new QLabel()); - reset_zoom_btn = toolbar->addAction("⟲"); + reset_zoom_btn = toolbar->addAction(bootstrapPixmap("arrow-counterclockwise"), ""); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); - remove_all_btn = toolbar->addAction("✖"); + remove_all_btn = toolbar->addAction(bootstrapPixmap("x"), ""); remove_all_btn->setToolTip(tr("Remove all charts")); dock_btn = toolbar->addAction(""); main_layout->addWidget(toolbar); @@ -137,7 +140,7 @@ void ChartsWidget::updateToolBar() { reset_zoom_btn->setEnabled(is_zoomed); range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); title_label->setText(charts.size() > 0 ? tr("Charts (%1)").arg(charts.size()) : tr("Charts")); - dock_btn->setText(docking ? "⬈" : "⬋"); + dock_btn->setIcon(bootstrapPixmap(docking ? "arrow-up-right" : "arrow-down-left")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); } @@ -223,7 +226,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->layout()->setContentsMargins(0, 0, 0, 0); QToolButton *remove_btn = new QToolButton(); - remove_btn->setText("X"); + remove_btn->setIcon(bootstrapPixmap("x")); remove_btn->setAutoRaise(true); remove_btn->setToolTip(tr("Remove Chart")); close_btn_proxy = new QGraphicsProxyWidget(chart); @@ -231,7 +234,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { close_btn_proxy->setZValue(chart->zValue() + 11); QToolButton *manage_btn = new QToolButton(); - manage_btn->setText("🔧"); + manage_btn->setIcon(bootstrapPixmap("gear")); manage_btn->setAutoRaise(true); manage_btn->setToolTip(tr("Manage series")); manage_btn_proxy = new QGraphicsProxyWidget(chart); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 06377616da..247111aaf4 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -36,6 +36,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart // message title toolbar = new QToolBar(this); + toolbar->setIconSize({16, 16}); toolbar->addWidget(new QLabel("time:")); time_label = new QLabel(this); time_label->setStyleSheet("font-weight:bold"); @@ -45,8 +46,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart name_label->setAlignment(Qt::AlignCenter); name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(name_label); - toolbar->addAction("🖍", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); - remove_msg_act = toolbar->addAction("X", this, &DetailWidget::removeMsg); + toolbar->addAction(bootstrapPixmap("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); + remove_msg_act = toolbar->addAction(bootstrapPixmap("x-lg"), "", this, &DetailWidget::removeMsg); remove_msg_act->setToolTip(tr("Remove Message")); toolbar->setVisible(false); frame_layout->addWidget(toolbar); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 2a92e03461..e2025dcc82 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -6,6 +6,8 @@ #include #include +#include "selfdrive/ui/qt/util.h" + // SignalForm SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { @@ -104,13 +106,13 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa title_layout->addWidget(title); plot_btn = new QToolButton(this); - plot_btn->setText("📈"); + plot_btn->setIcon(bootstrapPixmap("graph-up")); plot_btn->setCheckable(true); plot_btn->setAutoRaise(true); title_layout->addWidget(plot_btn); auto remove_btn = new QToolButton(this); remove_btn->setAutoRaise(true); - remove_btn->setText("x"); + remove_btn->setIcon(bootstrapPixmap("x")); remove_btn->setToolTip(tr("Remove signal")); title_layout->addWidget(remove_btn); main_layout->addWidget(title_bar); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 99d82daccf..400cc5108a 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -13,6 +13,8 @@ #include #include +#include "selfdrive/ui/qt/util.h" + inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } @@ -43,8 +45,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { // btn controls QHBoxLayout *control_layout = new QHBoxLayout(); - play_btn = new QPushButton("⏸"); - play_btn->setStyleSheet("font-weight:bold; height:16px"); + play_btn = new QPushButton(); control_layout->addWidget(play_btn); QButtonGroup *group = new QButtonGroup(this); @@ -68,12 +69,13 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); - QObject::connect(can, &CANMessages::paused, [this]() { play_btn->setText("▶"); }); - QObject::connect(can, &CANMessages::resume, [this]() { play_btn->setText("⏸"); }); + QObject::connect(can, &CANMessages::paused, this, &VideoWidget::updatePlayBtnState); + QObject::connect(can, &CANMessages::resume, this, &VideoWidget::updatePlayBtnState); QObject::connect(can, &CANMessages::streamStarted, [this]() { end_time_label->setText(formatTime(can->totalSeconds())); slider->setRange(0, can->totalSeconds() * 1000); }); + updatePlayBtnState(); } void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { @@ -90,6 +92,11 @@ void VideoWidget::updateState() { slider->setValue(can->currentSec() * 1000); } +void VideoWidget::updatePlayBtnState() { + play_btn->setIcon(bootstrapPixmap(can->isPaused() ? "play" : "pause")); + play_btn->setToolTip(can->isPaused() ? tr("Play") : tr("Pause")); +} + // Slider Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { QTimer *timer = new QTimer(this); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 515dab6c87..424a5b08fe 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -44,6 +44,7 @@ public: protected: void updateState(); + void updatePlayBtnState(); CameraWidget *cam_widget; QLabel *end_time_label; From 669becadde77d79443d933364234212c10d56151 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 18 Jan 2023 19:57:54 -0700 Subject: [PATCH 0660/1179] Ublox tow continuity check (#27001) * add continuity check * simplify * remove pair * update refs * bump laika update refs Co-authored-by: Kurt Nistelberger --- laika_repo | 2 +- selfdrive/locationd/ublox_msg.cc | 13 +++++++++++-- selfdrive/locationd/ublox_msg.h | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/laika_repo b/laika_repo index 73bf110ae0..2e5c7b8a85 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 73bf110ae0093ad86755bf5eb6a03e46ff5c239d +Subproject commit 2e5c7b8a85cbaebda7fa715fe53d5e6ecbd62b0a diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 6431e9d48b..8bd9985170 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -170,9 +170,18 @@ kj::Array UbloxMsgParser::gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg) { kaitai::kstream stream(subframe_data); gps_t subframe(&stream); int subframe_id = subframe.how()->subframe_id(); + int sv_id = msg->sv_id(); + uint64_t tow_counter = subframe.how()->tow_count(); - if (subframe_id == 1) gps_subframes[msg->sv_id()].clear(); - gps_subframes[msg->sv_id()][subframe_id] = subframe_data; + bool clear_buffer = subframe_id == 1; + if (gps_sat_tow_count.count(sv_id) != 0) { + int64_t counter_diff = tow_counter - gps_sat_tow_count[sv_id]; + clear_buffer |= counter_diff != 1 && counter_diff != -100798; + } + if (clear_buffer) gps_subframes[sv_id].clear(); + + gps_subframes[sv_id][subframe_id] = subframe_data; + gps_sat_tow_count[sv_id] = tow_counter; } if (gps_subframes[msg->sv_id()].size() == 5) { diff --git a/selfdrive/locationd/ublox_msg.h b/selfdrive/locationd/ublox_msg.h index 542e72816b..919e9963f1 100644 --- a/selfdrive/locationd/ublox_msg.h +++ b/selfdrive/locationd/ublox_msg.h @@ -103,6 +103,7 @@ class UbloxMsgParser { inline bool valid_so_far(); std::unordered_map> gps_subframes; + std::unordered_map gps_sat_tow_count; size_t bytes_in_parse_buf = 0; uint8_t msg_parse_buf[ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_MAX_MSG_SIZE]; diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a173cf5205..1aa3aa6f1e 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -18a70665bdb6b6aee4a224e826417049415e8290 +acc5655633af6ade096ad41f680fd8a28c2e3790 \ No newline at end of file From b7ce77b3aa48c3605554f63068a13860023eff86 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 18 Jan 2023 23:29:12 -0700 Subject: [PATCH 0661/1179] Add low Gnss laikad test (#26987) * add low gnss test * enable laikad * temp fix for cache * update replay * save LaikadEphemeris for testing * rem * update refs * add comment Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/laikad.py | 6 +++- selfdrive/locationd/locationd.cc | 23 +++++------- selfdrive/locationd/test/test_laikad.py | 36 +++++++++++++++++-- selfdrive/locationd/test/test_locationd.py | 29 +++++---------- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 59 insertions(+), 39 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index b8d86c63fd..ac8fac01f0 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -391,13 +391,17 @@ def process_msg(laikad, gnss_msg, mono_time, block=False): def clear_tmp_cache(): + # TODO: remove this function once laika downloader is changed to not write to disk + if "CI" in os.environ or "REPLAY" in os.environ: + return + if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) os.mkdir(DOWNLOADS_CACHE_FOLDER) def main(sm=None, pm=None, qc=None): - #clear_tmp_cache() + clear_tmp_cache() use_qcom = not Params().get_bool("UbloxAvailable", block=True) if use_qcom or (qc is not None and qc): diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 8941b50248..e78b3d3903 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -589,12 +589,12 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->handle_sensor(t, log.getAccelerometer()); } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); - } else if (log.isGpsLocation()) { - this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); - } else if (log.isGpsLocationExternal()) { - this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); - //} else if (log.isGnssMeasurements()) { - // this->handle_gnss(t, log.getGnssMeasurements()); + //} else if (log.isGpsLocation()) { + // this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); + //} else if (log.isGpsLocationExternal()) { + // this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + } else if (log.isGnssMeasurements()) { + this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { @@ -658,17 +658,12 @@ void Localizer::determine_gps_mode(double current_time) { int Localizer::locationd_thread() { ublox_available = Params().getBool("UbloxAvailable", true); - const char* gps_location_socket; - if (ublox_available) { - gps_location_socket = "gpsLocationExternal"; - } else { - gps_location_socket = "gpsLocation"; - } - const std::initializer_list service_list = {gps_location_socket, "cameraOdometry", "liveCalibration", + + const std::initializer_list service_list = {"gnssMeasurements", "cameraOdometry", "liveCalibration", "carState", "carParams", "accelerometer", "gyroscope"}; // TODO: remove carParams once we're always sending at 100Hz - SubMaster sm(service_list, {}, nullptr, {gps_location_socket, "carParams"}); + SubMaster sm(service_list, {}, nullptr, {"gnssMeasurements", "carParams"}); PubMaster pm({"liveLocationKalman"}); uint64_t cnt = 0; diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 6059eab68f..8cd84d91c2 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -22,7 +22,26 @@ def get_log(segs=range(0)): logs = [] for i in segs: logs.extend(LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", i))) - return [m for m in logs if m.which() == 'ubloxGnss'] + all_logs = [m for m in logs if m.which() == 'ubloxGnss'] + + low_gnss = [] + for m in all_logs: + if m.ubloxGnss.which() != 'measurementReport': + continue + if m.ubloxGnss.measurementReport.numMeas == 0: + continue + + MAX_MEAS = 7 + if m.ubloxGnss.measurementReport.numMeas > MAX_MEAS: + mb = m.as_builder() + mb.ubloxGnss.measurementReport.numMeas = MAX_MEAS + mb.ubloxGnss.measurementReport.measurements = list(m.ubloxGnss.measurementReport.measurements)[:MAX_MEAS] + mb.ubloxGnss.measurementReport.measurements[0].pseudorange += 1000 + low_gnss.append(mb.as_reader()) + else: + low_gnss.append(m) + + return all_logs, low_gnss def verify_messages(lr, laikad, return_one_success=False): @@ -59,8 +78,9 @@ class TestLaikad(unittest.TestCase): @classmethod def setUpClass(cls): - logs = get_log(range(1)) + logs, low_gnss = get_log(range(1)) cls.logs = logs + cls.low_gnss = low_gnss first_gps_time = get_first_gps_time(logs) cls.first_gps_time = first_gps_time @@ -254,6 +274,18 @@ class TestLaikad(unittest.TestCase): # Verify orbit data is not downloaded mock_method.assert_not_called() + def test_low_gnss_meas(self): + cnt = 0 + laikad = Laikad() + for m in self.low_gnss: + msg = laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=True) + if msg is None: + continue + gm = msg.gnssMeasurements + if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: + cnt += 1 + self.assertEqual(cnt, 554) + def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py index 9f643e2b8f..943969a49e 100755 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -15,7 +15,7 @@ from selfdrive.manager.process_config import managed_processes class TestLocationdProc(unittest.TestCase): MAX_WAITS = 1000 - LLD_MSGS = ['gpsLocationExternal', 'cameraOdometry', 'carState', 'liveCalibration', + LLD_MSGS = ['gnssMeasurements', 'cameraOdometry', 'carState', 'liveCalibration', 'accelerometer', 'gyroscope', 'magnetometer'] def setUp(self): @@ -46,25 +46,14 @@ class TestLocationdProc(unittest.TestCase): except capnp.lib.capnp.KjException: msg = messaging.new_message(name, 0) - - if name == "gpsLocationExternal": - msg.gpsLocationExternal.flags = 1 - msg.gpsLocationExternal.verticalAccuracy = 1.0 - msg.gpsLocationExternal.speedAccuracy = 1.0 - msg.gpsLocationExternal.bearingAccuracyDeg = 1.0 - msg.gpsLocationExternal.vNED = [0.0, 0.0, 0.0] - msg.gpsLocationExternal.latitude = float(self.lat) - msg.gpsLocationExternal.longitude = float(self.lon) - msg.gpsLocationExternal.unixTimestampMillis = t * 1e6 - msg.gpsLocationExternal.altitude = float(self.alt) - #if name == "gnssMeasurements": - # msg.gnssMeasurements.measTime = t - # msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] - # msg.gnssMeasurements.positionECEF.std = [0,0,0] - # msg.gnssMeasurements.positionECEF.valid = True - # msg.gnssMeasurements.velocityECEF.value = [] - # msg.gnssMeasurements.velocityECEF.std = [0,0,0] - # msg.gnssMeasurements.velocityECEF.valid = True + if name == "gnssMeasurements": + msg.gnssMeasurements.measTime = t + msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] + msg.gnssMeasurements.positionECEF.std = [0,0,0] + msg.gnssMeasurements.positionECEF.valid = True + msg.gnssMeasurements.velocityECEF.value = [] + msg.gnssMeasurements.velocityECEF.std = [0,0,0] + msg.gnssMeasurements.velocityECEF.valid = True elif name == 'cameraOdometry': msg.cameraOdometry.rot = [0.0, 0.0, 0.0] msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0] diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 22ec099285..24ee87e471 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -331,7 +331,7 @@ CONFIGS = [ pub_sub={ "cameraOdometry": ["liveLocationKalman"], "accelerometer": [], "gyroscope": [], - "gpsLocationExternal": [], "liveCalibration": [], "carState": [], + "gnssMeasurements": [], "liveCalibration": [], "carState": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1aa3aa6f1e..629a9a2f51 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -acc5655633af6ade096ad41f680fd8a28c2e3790 \ No newline at end of file +660149849230afe36363100ab0f5935038d8191e \ No newline at end of file From cebee69f304357c5966dec9b316a4d15e68c571b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 20 Jan 2023 02:32:48 +0800 Subject: [PATCH 0662/1179] cabana: click time label to seek to a specified time (#27006) --- tools/cabana/canmessages.h | 1 + tools/cabana/videowidget.cc | 28 +++++++++++++++++++++++++--- tools/cabana/videowidget.h | 5 +++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 2451793742..2cdc010d8c 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -34,6 +34,7 @@ public: inline double totalSeconds() const { return replay->totalSeconds(); } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } inline double currentSec() const { return replay->currentSeconds(); } + inline QDateTime currentDateTime() const { return replay->currentDateTime(); } inline const CanData &lastMessage(const QString &id) { return can_msgs[id]; } inline const Route* route() const { return replay->route(); } diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 400cc5108a..2f6aab249a 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -3,11 +3,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -31,8 +31,9 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { frame_layout->addWidget(cam_widget); // slider controls - QHBoxLayout *slider_layout = new QHBoxLayout(); - QLabel *time_label = new QLabel("00:00"); + slider_layout = new QHBoxLayout(); + time_label = new ElidedLabel("00:00"); + time_label->setToolTip(tr("Click to set current time")); slider_layout->addWidget(time_label); slider = new Slider(this); @@ -64,6 +65,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + QObject::connect(time_label, &ElidedLabel::clicked, this, &VideoWidget::timeLabelClicked); 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, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); @@ -78,6 +80,26 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { updatePlayBtnState(); } +void VideoWidget::timeLabelClicked() { + auto time_edit = new QTimeEdit(this); + auto init_date_time = can->currentDateTime(); + time_edit->setDateTime(init_date_time); + time_edit->setDisplayFormat("hh:mm:ss"); + time_label->setVisible(false); + slider_layout->insertWidget(0, time_edit); + QTimer::singleShot(0, [=]() { time_edit->setFocus(); }); + + QObject::connect(time_edit, &QTimeEdit::editingFinished, [=]() { + if (time_edit->dateTime() != init_date_time) { + int seconds = can->route()->datetime().secsTo(time_edit->dateTime()); + can->seekTo(seconds); + } + time_edit->setVisible(false); + time_label->setVisible(true); + time_edit->deleteLater(); + }); +} + void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { if (!is_zoomed) { min = 0; diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 424a5b08fe..e9899abbbf 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -3,12 +3,14 @@ #include #include +#include #include #include #include #include #include "selfdrive/ui/qt/widgets/cameraview.h" +#include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/canmessages.h" class Slider : public QSlider { @@ -45,9 +47,12 @@ public: protected: void updateState(); void updatePlayBtnState(); + void timeLabelClicked(); CameraWidget *cam_widget; QLabel *end_time_label; + ElidedLabel *time_label; + QHBoxLayout *slider_layout; QPushButton *play_btn; Slider *slider; }; From 5b8d124be7d1277d816ff337fd69600da0e891e2 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 19 Jan 2023 19:35:18 +0100 Subject: [PATCH 0663/1179] cabana: color bytes based on activity (#26970) * cabana: color bytes based on activity * newlines * fix text color when selected * fix indent * add colors to binary view * no need to check contains * whitespace * Apply suggestions from code review Co-authored-by: Adeeb Shihadeh --- tools/cabana/binaryview.cc | 8 +++-- tools/cabana/canmessages.cc | 60 ++++++++++++++++++++++++++++++++++ tools/cabana/canmessages.h | 2 ++ tools/cabana/messageswidget.cc | 53 ++++++++++++++++++++++++++++-- tools/cabana/messageswidget.h | 8 +++++ 5 files changed, 127 insertions(+), 4 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index b98c75d452..b6a5fa75aa 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -177,7 +177,9 @@ void BinaryViewModel::setMessage(const QString &message_id) { void BinaryViewModel::updateState() { auto prev_items = items; - const auto &binary = can->lastMessage(msg_id).dat; + const auto &last_msg = can->lastMessage(msg_id); + const auto &binary = last_msg.dat; + // data size may changed. if (binary.size() > row_count) { beginInsertRows({}, row_count, binary.size() - 1); @@ -193,6 +195,7 @@ void BinaryViewModel::updateState() { hex[0] = toHex(binary[i] >> 4); hex[1] = toHex(binary[i] & 0xf); items[i * column_count + 8].val = hex; + items[i * column_count + 8].bg_color = last_msg.colors[i]; } for (int i = binary.size(); i < row_count; ++i) { for (int j = 0; j < column_count; ++j) { @@ -201,7 +204,7 @@ void BinaryViewModel::updateState() { } for (int i = 0; i < row_count * column_count; ++i) { - if (i >= prev_items.size() || prev_items[i].val != items[i].val) { + if (i >= prev_items.size() || prev_items[i].val != items[i].val || prev_items[i].bg_color != items[i].bg_color) { auto idx = index(i / column_count, i % column_count); emit dataChanged(idx, idx); } @@ -234,6 +237,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (index.column() == 8) { painter->setFont(hex_font); + painter->fillRect(option.rect, item->bg_color); } else if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, selection_color); painter->setPen(option.palette.color(QPalette::BrightText)); diff --git a/tools/cabana/canmessages.cc b/tools/cabana/canmessages.cc index a473313f90..9b5f41c60a 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/canmessages.cc @@ -18,6 +18,10 @@ static bool event_filter(const Event *e, void *opaque) { return c->eventFilter(e); } +static QColor blend(QColor a, QColor b) { + return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); +} + bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); replay->setSegmentCacheLimit(settings.cached_segment_limit); @@ -49,6 +53,9 @@ void CANMessages::process(QHash *messages) { bool CANMessages::eventFilter(const Event *event) { static std::unique_ptr new_msgs = std::make_unique>(); + static QHash prev_dat; + static QHash> colors; + static QHash> last_change_t; static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { @@ -71,6 +78,59 @@ bool CANMessages::eventFilter(const Event *event) { if (double delta = (current_sec - counters_begin_sec); delta > 0) { data.freq = data.count / delta; } + + // Init colors + if (colors[id].size() != data.dat.size()) { + colors[id].clear(); + for (int i = 0; i < data.dat.size(); i++){ + colors[id].append(QColor(0, 0, 0, 0)); + } + } + + // Init last_change_t + if (last_change_t[id].size() != data.dat.size()) { + last_change_t[id].clear(); + for (int i = 0; i < data.dat.size(); i++){ + last_change_t[id].append(data.ts); + } + } + + // Compute background color for the bytes based on changes + if (prev_dat[id].size() == data.dat.size()) { + for (int i = 0; i < data.dat.size(); i++){ + uint8_t last = prev_dat[id][i]; + uint8_t cur = data.dat[i]; + + const int periodic_threshold = 10; + const int start_alpha = 128; + const float fade_time = 2.0; + + if (last != cur) { + double delta_t = data.ts - last_change_t[id][i]; + + if (delta_t * data.freq > periodic_threshold) { + // Last change was while ago, choose color based on delta up or down + if (cur > last) { + colors[id][i] = QColor(0, 187, 255, start_alpha); // Cyan + } else { + colors[id][i] = QColor(255, 0, 0, start_alpha); // Red + } + } else { + // Periodic changes + colors[id][i] = blend(colors[id][i], QColor(102, 86, 169, start_alpha / 2)); // Greyish/Blue + } + + last_change_t[id][i] = data.ts; + } else { + // Fade out + float alpha_delta = 1.0 / (data.freq + 1) / fade_time; + colors[id][i].setAlphaF(std::max(0.0, colors[id][i].alphaF() - alpha_delta)); + } + } + } + + data.colors = colors[id]; + prev_dat[id] = data.dat; } double ts = millis_since_boot(); diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h index 2cdc010d8c..c30361af41 100644 --- a/tools/cabana/canmessages.h +++ b/tools/cabana/canmessages.h @@ -4,6 +4,7 @@ #include #include +#include #include "opendbc/can/common_dbc.h" #include "tools/cabana/settings.h" @@ -16,6 +17,7 @@ struct CanData { uint32_t count = 0; uint32_t freq = 0; QByteArray dat; + QList colors; }; class CANMessages : public QObject { diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 3477abe37b..10a9c2e849 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "tools/cabana/dbcmanager.h" @@ -21,6 +23,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget = new QTableView(this); model = new MessageListModel(this); table_widget->setModel(model); + table_widget->setItemDelegateForColumn(4, new MessageBytesDelegate(table_widget)); table_widget->setSelectionBehavior(QAbstractItemView::SelectRows); table_widget->setSelectionMode(QAbstractItemView::SingleSelection); table_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); @@ -31,6 +34,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget->setColumnWidth(2, 80); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); + main_layout->addWidget(table_widget); // signals/slots @@ -65,9 +69,10 @@ QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, } QVariant MessageListModel::data(const QModelIndex &index, int role) const { + const auto &id = msgs[index.row()]; + auto &can_data = can->lastMessage(id); + if (role == Qt::DisplayRole) { - const auto &id = msgs[index.row()]; - auto &can_data = can->lastMessage(id); switch (index.column()) { case 0: return msgName(id); case 1: return id; @@ -77,6 +82,13 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } } else if (role == Qt::FontRole && index.column() == columnCount() - 1) { return QFontDatabase::systemFont(QFontDatabase::FixedFont); + } else if (role == Qt::UserRole && index.column() == 4) { + + QList colors; + for (int i = 0; i < can_data.dat.size(); i++){ + colors.append(can_data.colors[i]); + } + return colors; } return {}; } @@ -146,3 +158,40 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { sortMessages(); } } + + +MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { +} + +void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + QList colors = index.data(Qt::UserRole).toList(); + + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + const QFont font = index.data(Qt::FontRole).value(); + painter->setFont(font); + + QRect rect = opt.rect; + QString bytes = QString(opt.text); + + QRect pos = rect; + QRect space = painter->boundingRect(pos, opt.displayAlignment, " "); + pos.setX(pos.x() + space.width()); + + if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { + painter->setPen(option.palette.color(QPalette::HighlightedText)); + } else { + painter->setPen(option.palette.color(QPalette::Text)); + } + + int i = 0; + for (auto &byte : bytes.split(" ")) { + QRect sz = painter->boundingRect(pos, opt.displayAlignment, byte); + const int m = space.width() / 2; + painter->fillRect(sz.marginsAdded(QMargins(m + 1, m, m, m)), colors[i].value()); + painter->drawText(pos, opt.displayAlignment, byte); + pos.setX(pos.x() + sz.width() + space.width()); + i++; + } +} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 62aa23c02e..8b74f1427e 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -2,6 +2,7 @@ #include #include +#include #include "tools/cabana/canmessages.h" @@ -41,3 +42,10 @@ protected: QString current_msg_id; MessageListModel *model; }; + +class MessageBytesDelegate : public QStyledItemDelegate { + Q_OBJECT +public: + MessageBytesDelegate(QObject *parent); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; +}; From d365d99cb005b99ce7385d169e696847b0726315 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 19 Jan 2023 19:36:17 +0100 Subject: [PATCH 0664/1179] cabana: improve open/save functions (#27007) --- tools/cabana/mainwin.cc | 23 +++++++++++++++-------- tools/cabana/mainwin.h | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index af89d26f4f..89876f4267 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -68,13 +68,14 @@ MainWindow::MainWindow() : QMainWindow() { void MainWindow::createActions() { QMenu *file_menu = menuBar()->addMenu(tr("&File")); - file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::loadDBCFromFile); + file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::loadDBCFromFile)->setShortcuts(QKeySequence::Open); file_menu->addAction(tr("Load DBC From Clipboard"), this, &MainWindow::loadDBCFromClipboard); file_menu->addSeparator(); - file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveDBCToFile); + file_menu->addAction(tr("Save DBC..."), this, &MainWindow::saveDBCToFile)->setShortcuts(QKeySequence::Save); + file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAsDBCToFile)->setShortcuts(QKeySequence::SaveAs); file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveDBCToClipboard); file_menu->addSeparator(); - file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption); + file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption)->setShortcuts(QKeySequence::Preferences); QMenu *edit_menu = menuBar()->addMenu(tr("&Edit")); auto undo_act = detail_widget->undo_stack->createUndoAction(this, tr("&Undo")); @@ -182,7 +183,7 @@ void MainWindow::loadDBCFromName(const QString &name) { } void MainWindow::loadDBCFromFile() { - QString file_name = QFileDialog::getOpenFileName(this, tr("Open File"), settings.last_dir, "DBC (*.dbc)"); + file_name = QFileDialog::getOpenFileName(this, tr("Open File"), settings.last_dir, "DBC (*.dbc)"); if (!file_name.isEmpty()) { settings.last_dir = QFileInfo(file_name).absolutePath(); QFile file(file_name); @@ -213,18 +214,24 @@ void MainWindow::loadDBCFromFingerprint() { } void MainWindow::saveDBCToFile() { - QString file_name = QFileDialog::getSaveFileName(this, tr("Save File"), - QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); - if (!file_name.isEmpty()) { + if (file_name.isEmpty()) { + saveAsDBCToFile(); + } else { settings.last_dir = QFileInfo(file_name).absolutePath(); QFile file(file_name); if (file.open(QIODevice::WriteOnly)) { file.write(dbc()->generateDBC().toUtf8()); - detail_widget->undo_stack->clear(); } } } +void MainWindow::saveAsDBCToFile() { + file_name = QFileDialog::getSaveFileName(this, tr("Save File"), QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); + if (!file_name.isEmpty()) { + saveDBCToFile(); + } +} + void MainWindow::saveDBCToClipboard() { QGuiApplication::clipboard()->setText(dbc()->generateDBC()); QMessageBox::information(this, tr("Copy To Clipboard"), tr("DBC Successfully copied!")); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 3e80ffa1aa..c1a5908a53 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -28,6 +28,7 @@ public slots: void loadDBCFromFile(); void loadDBCFromClipboard(); void saveDBCToFile(); + void saveAsDBCToFile(); void saveDBCToClipboard(); signals: @@ -57,4 +58,5 @@ protected: QJsonDocument fingerprint_to_dbc; QComboBox *dbc_combo; QSplitter *video_splitter;; + QString file_name = ""; }; From 35b83579634f2cdee4d6ef4652995b1844773b6e Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 19 Jan 2023 19:37:27 +0100 Subject: [PATCH 0665/1179] cabana: search by signal name (#26944) --- tools/cabana/messageswidget.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 10a9c2e849..5deac031a1 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -97,7 +97,24 @@ void MessageListModel::setFilterString(const QString &string) { filter_str = string; msgs.clear(); for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + bool found = false; + + // Search by message id or name if (it.key().contains(filter_str, Qt::CaseInsensitive) || msgName(it.key()).contains(filter_str, Qt::CaseInsensitive)) { + found = true; + } + + // Search by signal name + const DBCMsg *msg = dbc()->msg(it.key()); + if (msg != nullptr) { + for (auto &signal: msg->getSignals()) { + if (QString::fromStdString(signal->name).contains(filter_str, Qt::CaseInsensitive)) { + found = true; + } + } + } + + if (found) { msgs.push_back(it.key()); } } From 9131da9103718d6ae113ad7b3519037e2b4ffa70 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Thu, 19 Jan 2023 11:46:22 -0800 Subject: [PATCH 0666/1179] Revert "Add low Gnss laikad test (#26987)" This reverts commit b7ce77b3aa48c3605554f63068a13860023eff86. --- selfdrive/locationd/laikad.py | 6 +--- selfdrive/locationd/locationd.cc | 23 +++++++----- selfdrive/locationd/test/test_laikad.py | 36 ++----------------- selfdrive/locationd/test/test_locationd.py | 29 ++++++++++----- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 6 files changed, 39 insertions(+), 59 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index ac8fac01f0..b8d86c63fd 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -391,17 +391,13 @@ def process_msg(laikad, gnss_msg, mono_time, block=False): def clear_tmp_cache(): - # TODO: remove this function once laika downloader is changed to not write to disk - if "CI" in os.environ or "REPLAY" in os.environ: - return - if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) os.mkdir(DOWNLOADS_CACHE_FOLDER) def main(sm=None, pm=None, qc=None): - clear_tmp_cache() + #clear_tmp_cache() use_qcom = not Params().get_bool("UbloxAvailable", block=True) if use_qcom or (qc is not None and qc): diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index e78b3d3903..8941b50248 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -589,12 +589,12 @@ void Localizer::handle_msg(const cereal::Event::Reader& log) { this->handle_sensor(t, log.getAccelerometer()); } else if (log.isGyroscope()) { this->handle_sensor(t, log.getGyroscope()); - //} else if (log.isGpsLocation()) { - // this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); - //} else if (log.isGpsLocationExternal()) { - // this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); - } else if (log.isGnssMeasurements()) { - this->handle_gnss(t, log.getGnssMeasurements()); + } else if (log.isGpsLocation()) { + this->handle_gps(t, log.getGpsLocation(), GPS_QUECTEL_SENSOR_TIME_OFFSET); + } else if (log.isGpsLocationExternal()) { + this->handle_gps(t, log.getGpsLocationExternal(), GPS_UBLOX_SENSOR_TIME_OFFSET); + //} else if (log.isGnssMeasurements()) { + // this->handle_gnss(t, log.getGnssMeasurements()); } else if (log.isCarState()) { this->handle_car_state(t, log.getCarState()); } else if (log.isCameraOdometry()) { @@ -658,12 +658,17 @@ void Localizer::determine_gps_mode(double current_time) { int Localizer::locationd_thread() { ublox_available = Params().getBool("UbloxAvailable", true); - - const std::initializer_list service_list = {"gnssMeasurements", "cameraOdometry", "liveCalibration", + const char* gps_location_socket; + if (ublox_available) { + gps_location_socket = "gpsLocationExternal"; + } else { + gps_location_socket = "gpsLocation"; + } + const std::initializer_list service_list = {gps_location_socket, "cameraOdometry", "liveCalibration", "carState", "carParams", "accelerometer", "gyroscope"}; // TODO: remove carParams once we're always sending at 100Hz - SubMaster sm(service_list, {}, nullptr, {"gnssMeasurements", "carParams"}); + SubMaster sm(service_list, {}, nullptr, {gps_location_socket, "carParams"}); PubMaster pm({"liveLocationKalman"}); uint64_t cnt = 0; diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 8cd84d91c2..6059eab68f 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -22,26 +22,7 @@ def get_log(segs=range(0)): logs = [] for i in segs: logs.extend(LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", i))) - all_logs = [m for m in logs if m.which() == 'ubloxGnss'] - - low_gnss = [] - for m in all_logs: - if m.ubloxGnss.which() != 'measurementReport': - continue - if m.ubloxGnss.measurementReport.numMeas == 0: - continue - - MAX_MEAS = 7 - if m.ubloxGnss.measurementReport.numMeas > MAX_MEAS: - mb = m.as_builder() - mb.ubloxGnss.measurementReport.numMeas = MAX_MEAS - mb.ubloxGnss.measurementReport.measurements = list(m.ubloxGnss.measurementReport.measurements)[:MAX_MEAS] - mb.ubloxGnss.measurementReport.measurements[0].pseudorange += 1000 - low_gnss.append(mb.as_reader()) - else: - low_gnss.append(m) - - return all_logs, low_gnss + return [m for m in logs if m.which() == 'ubloxGnss'] def verify_messages(lr, laikad, return_one_success=False): @@ -78,9 +59,8 @@ class TestLaikad(unittest.TestCase): @classmethod def setUpClass(cls): - logs, low_gnss = get_log(range(1)) + logs = get_log(range(1)) cls.logs = logs - cls.low_gnss = low_gnss first_gps_time = get_first_gps_time(logs) cls.first_gps_time = first_gps_time @@ -274,18 +254,6 @@ class TestLaikad(unittest.TestCase): # Verify orbit data is not downloaded mock_method.assert_not_called() - def test_low_gnss_meas(self): - cnt = 0 - laikad = Laikad() - for m in self.low_gnss: - msg = laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=True) - if msg is None: - continue - gm = msg.gnssMeasurements - if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: - cnt += 1 - self.assertEqual(cnt, 554) - def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py index 943969a49e..9f643e2b8f 100755 --- a/selfdrive/locationd/test/test_locationd.py +++ b/selfdrive/locationd/test/test_locationd.py @@ -15,7 +15,7 @@ from selfdrive.manager.process_config import managed_processes class TestLocationdProc(unittest.TestCase): MAX_WAITS = 1000 - LLD_MSGS = ['gnssMeasurements', 'cameraOdometry', 'carState', 'liveCalibration', + LLD_MSGS = ['gpsLocationExternal', 'cameraOdometry', 'carState', 'liveCalibration', 'accelerometer', 'gyroscope', 'magnetometer'] def setUp(self): @@ -46,14 +46,25 @@ class TestLocationdProc(unittest.TestCase): except capnp.lib.capnp.KjException: msg = messaging.new_message(name, 0) - if name == "gnssMeasurements": - msg.gnssMeasurements.measTime = t - msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] - msg.gnssMeasurements.positionECEF.std = [0,0,0] - msg.gnssMeasurements.positionECEF.valid = True - msg.gnssMeasurements.velocityECEF.value = [] - msg.gnssMeasurements.velocityECEF.std = [0,0,0] - msg.gnssMeasurements.velocityECEF.valid = True + + if name == "gpsLocationExternal": + msg.gpsLocationExternal.flags = 1 + msg.gpsLocationExternal.verticalAccuracy = 1.0 + msg.gpsLocationExternal.speedAccuracy = 1.0 + msg.gpsLocationExternal.bearingAccuracyDeg = 1.0 + msg.gpsLocationExternal.vNED = [0.0, 0.0, 0.0] + msg.gpsLocationExternal.latitude = float(self.lat) + msg.gpsLocationExternal.longitude = float(self.lon) + msg.gpsLocationExternal.unixTimestampMillis = t * 1e6 + msg.gpsLocationExternal.altitude = float(self.alt) + #if name == "gnssMeasurements": + # msg.gnssMeasurements.measTime = t + # msg.gnssMeasurements.positionECEF.value = [self.x , self.y, self.z] + # msg.gnssMeasurements.positionECEF.std = [0,0,0] + # msg.gnssMeasurements.positionECEF.valid = True + # msg.gnssMeasurements.velocityECEF.value = [] + # msg.gnssMeasurements.velocityECEF.std = [0,0,0] + # msg.gnssMeasurements.velocityECEF.valid = True elif name == 'cameraOdometry': msg.cameraOdometry.rot = [0.0, 0.0, 0.0] msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0] diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 24ee87e471..22ec099285 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -331,7 +331,7 @@ CONFIGS = [ pub_sub={ "cameraOdometry": ["liveLocationKalman"], "accelerometer": [], "gyroscope": [], - "gnssMeasurements": [], "liveCalibration": [], "carState": [], + "gpsLocationExternal": [], "liveCalibration": [], "carState": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 629a9a2f51..1aa3aa6f1e 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -660149849230afe36363100ab0f5935038d8191e \ No newline at end of file +acc5655633af6ade096ad41f680fd8a28c2e3790 \ No newline at end of file From fd4dc109e1ab01b2d1ea6aaf3e99126dbaddc63b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 20 Jan 2023 05:51:55 +0800 Subject: [PATCH 0667/1179] cabana: add support for multiple columns charts (#27000) --- tools/cabana/chartswidget.cc | 68 +++++++++++++++++++++++++++++------- tools/cabana/chartswidget.h | 14 ++++++-- tools/cabana/settings.cc | 2 ++ tools/cabana/settings.h | 1 + 4 files changed, 70 insertions(+), 15 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 69229baa64..412365a15b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -22,9 +22,19 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); toolbar->setIconSize({16, 16}); - title_label = new QLabel(); - title_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - toolbar->addWidget(title_label); + + toolbar->addWidget(title_label = new QLabel()); + title_label->setContentsMargins(0 ,0, 12, 0); + columns_cb = new QComboBox(this); + columns_cb->addItems({"1", "2", "3", "4"}); + columns_cb->setCurrentIndex(std::clamp(settings.chart_column_count - 1, 0, 3)); + toolbar->addWidget(new QLabel(tr("Columns:"))); + toolbar->addWidget(columns_cb); + + QLabel *stretch_label = new QLabel(this); + stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + toolbar->addWidget(stretch_label); + show_all_values_btn = toolbar->addAction(""); toolbar->addWidget(range_label = new QLabel()); reset_zoom_btn = toolbar->addAction(bootstrapPixmap("arrow-counterclockwise"), ""); @@ -36,8 +46,11 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // charts QWidget *charts_container = new QWidget(this); - charts_layout = new QVBoxLayout(charts_container); - charts_layout->addStretch(); + QVBoxLayout *charts_main_layout = new QVBoxLayout(charts_container); + charts_main_layout->setContentsMargins(0, 0, 0, 0); + charts_layout = new QGridLayout(charts_container); + charts_main_layout->addLayout(charts_layout); + charts_main_layout->addStretch(0); QScrollArea *charts_scroll = new QScrollArea(this); charts_scroll->setWidgetResizable(true); @@ -53,6 +66,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { align_charts_timer = new QTimer(this); align_charts_timer->setSingleShot(true); align_charts_timer->callOnTimeout(this, &ChartsWidget::alignCharts); + column_count = settings.chart_column_count; QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &CANMessages::eventsMerged, this, &ChartsWidget::eventsMerged); @@ -60,6 +74,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(show_all_values_btn, &QAction::triggered, this, &ChartsWidget::showAllData); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); + QObject::connect(columns_cb, SIGNAL(activated(int)), SLOT(setColumnCount(int))); + QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged); QObject::connect(dock_btn, &QAction::triggered, [this]() { emit dock(!docking); docking = !docking; @@ -144,6 +160,14 @@ void ChartsWidget::updateToolBar() { dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); } +void ChartsWidget::settingChanged() { + for (auto c : charts) { + c->setFixedHeight(settings.chart_height); + columns_cb->setCurrentIndex(std::clamp(settings.chart_column_count - 1, 0, columns_cb->count() - 1)); + setColumnCount(settings.chart_column_count); + } +} + ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { for (auto c : charts) if (c->hasSeries(id, sig)) return c; @@ -157,6 +181,9 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo chart = merge && charts.size() > 0 ? charts.back() : nullptr; if (!chart) { chart = new ChartView(this); + chart->setFixedHeight(settings.chart_height); + chart->setMinimumWidth(CHART_MIN_WIDTH); + chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); chart->setEventsRange(display_range); auto range = is_zoomed ? zoomed_range : display_range; @@ -167,8 +194,8 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::axisYUpdated, [this]() { align_charts_timer->start(100); }); - charts_layout->insertWidget(0, chart); charts.push_back(chart); + updateLayout(); } chart->addSeries(id, sig); } else if (!show && chart) { @@ -178,6 +205,29 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo setUpdatesEnabled(true); } +void ChartsWidget::setColumnCount(int n) { + n = std::clamp(n + 1, 1, columns_cb->count()); + if (column_count != n) { + column_count = n; + updateLayout(); + } +} + +void ChartsWidget::updateLayout() { + int n = column_count; + for (; n >= 1; --n) { + if ((n * (CHART_MIN_WIDTH + charts_layout->spacing())) < rect().width()) break; + } + for (int i = 0; i < charts.size(); ++i) { + charts_layout->addWidget(charts[i], i / n, i % n); + } +} + +void ChartsWidget::resizeEvent(QResizeEvent *event) { + QWidget::resizeEvent(event); + updateLayout(); +} + void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); @@ -244,13 +294,11 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { setChart(chart); setRenderHint(QPainter::Antialiasing); setRubberBand(QChartView::HorizontalRubberBand); - updateFromSettings(); 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, this, &ChartView::remove); QObject::connect(manage_btn, &QToolButton::clicked, this, &ChartView::manageSeries); } @@ -386,10 +434,6 @@ void ChartView::updateTitle() { } } -void ChartView::updateFromSettings() { - setFixedHeight(settings.chart_height); -} - void ChartView::setEventsRange(const std::pair &range) { if (range != events_range) { events_range = range; diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index ebce8ceda6..54c84ad2db 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -3,11 +3,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -68,7 +68,6 @@ private: void resizeEvent(QResizeEvent *event) override; void updateAxisY(); void updateTitle(); - void updateFromSettings(); void drawForeground(QPainter *painter, const QRectF &rect) override; void applyNiceNumbers(qreal min, qreal max); qreal niceNumber(qreal x, bool ceiling); @@ -92,12 +91,16 @@ public: void showChart(const QString &id, const Signal *sig, bool show, bool merge); inline bool hasSignal(const QString &id, const Signal *sig) { return findChart(id, sig) != nullptr; } +public slots: + void setColumnCount(int n); + signals: void dock(bool floating); void rangeChanged(double min, double max, bool is_zommed); void seriesChanged(); private: + void resizeEvent(QResizeEvent *event) override; void alignCharts(); void removeChart(ChartView *chart); void eventsMerged(); @@ -108,6 +111,8 @@ private: void updateToolBar(); void removeAll(); void showAllData(); + void updateLayout(); + void settingChanged(); bool eventFilter(QObject *obj, QEvent *event) override; ChartView *findChart(const QString &id, const Signal *sig); @@ -119,7 +124,7 @@ private: QAction *reset_zoom_btn; QAction *remove_all_btn; QTimer *align_charts_timer; - QVBoxLayout *charts_layout; + QGridLayout *charts_layout; QList charts; uint32_t max_chart_range = 0; bool is_zoomed = false; @@ -127,6 +132,9 @@ private: std::pair display_range; std::pair zoomed_range; bool use_dark_theme = false; + QComboBox *columns_cb; + int column_count = 1; + const int CHART_MIN_WIDTH = 300; }; class SeriesSelector : public QDialog { diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index a5b490e9fb..0b0610edc9 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -18,6 +18,7 @@ void Settings::save() { s.setValue("cached_segment", cached_segment_limit); s.setValue("chart_height", chart_height); s.setValue("max_chart_x_range", max_chart_x_range); + s.setValue("chart_column_count", chart_column_count); s.setValue("last_dir", last_dir); s.setValue("window_state", window_state); s.setValue("geometry", geometry); @@ -30,6 +31,7 @@ void Settings::load() { cached_segment_limit = s.value("cached_segment", 3).toInt(); chart_height = s.value("chart_height", 200).toInt(); max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); + chart_column_count = s.value("chart_column_count", 1).toInt(); last_dir = s.value("last_dir", QDir::homePath()).toString(); window_state = s.value("window_state").toByteArray(); geometry = s.value("geometry").toByteArray(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 76be2f1487..924021eb94 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -16,6 +16,7 @@ public: int fps = 10; int cached_segment_limit = 3; int chart_height = 200; + int chart_column_count = 1; int max_chart_x_range = 3 * 60; // 3 minutes QString last_dir; QByteArray geometry; From f9490739ab37ae680aef272d51eb3cf2b36b4103 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 20 Jan 2023 07:26:00 +0800 Subject: [PATCH 0668/1179] Cabana: support live streaming (#26946) * support live streaming * update live stream's time * cleanup stream classes * disable video control in live streaming mode * emit streamStarted() in LiveStream::streamThread * disable some features in live streaming mode * refactor charts to support live streaming mode * disable dynamic mode checkbox in live streaming mode * updateDispalyRange * thread safe events * TODO: add support for ZMQ * atomic time stamp * only keep settings.cached_segment_limit*60 seconds data in liveStream * make charts work better in live mode * cleanup ChartView * fix toolbar * cleanup cleanup * disable openpilotPrefix and useOpenGL on macos * add comment * exit gracefully * support ZMQ * use ::operator new/delete * cleanup streams * cleanup * align stream buffers * check looping back * check if series is empty * cleanup * add TODO: write stream to log file to replay it * upper_bound * remove class member event_range * change default settings value * cleanup updateDisplayrange * fix merge error --- tools/cabana/SConscript | 4 +- tools/cabana/binaryview.cc | 2 +- tools/cabana/cabana.cc | 47 +++++---- tools/cabana/canmessages.h | 86 ----------------- tools/cabana/chartswidget.cc | 95 +++++++++++-------- tools/cabana/chartswidget.h | 6 +- tools/cabana/commands.h | 1 - tools/cabana/dbcmanager.h | 2 - tools/cabana/detailwidget.cc | 4 +- tools/cabana/historylog.cc | 9 +- tools/cabana/historylog.h | 2 +- tools/cabana/mainwin.cc | 11 ++- tools/cabana/mainwin.h | 2 +- tools/cabana/messageswidget.cc | 3 +- tools/cabana/messageswidget.h | 2 +- tools/cabana/settings.cc | 6 +- tools/cabana/settings.h | 2 +- tools/cabana/signaledit.h | 2 +- .../abstractstream.cc} | 69 +++----------- tools/cabana/streams/abstractstream.h | 76 +++++++++++++++ tools/cabana/streams/livestream.cc | 71 ++++++++++++++ tools/cabana/streams/livestream.h | 31 ++++++ tools/cabana/streams/replaystream.cc | 54 +++++++++++ tools/cabana/streams/replaystream.h | 32 +++++++ tools/cabana/tools/findsimilarbits.cc | 2 +- tools/cabana/videowidget.cc | 10 +- tools/cabana/videowidget.h | 2 +- 27 files changed, 395 insertions(+), 238 deletions(-) delete mode 100644 tools/cabana/canmessages.h rename tools/cabana/{canmessages.cc => streams/abstractstream.cc} (64%) create mode 100644 tools/cabana/streams/abstractstream.h create mode 100644 tools/cabana/streams/livestream.cc create mode 100644 tools/cabana/streams/livestream.h create mode 100644 tools/cabana/streams/replaystream.cc create mode 100644 tools/cabana/streams/replaystream.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 6726a042ad..9b172a544f 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -20,8 +20,8 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', - 'canmessages.cc', 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', + 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index b6a5fa75aa..8d28080790 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -6,7 +6,7 @@ #include #include -#include "tools/cabana/canmessages.h" +#include "tools/cabana/streams/abstractstream.h" // BinaryView diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index 6a9db120e9..ce0cb443cb 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -4,6 +4,8 @@ #include "common/prefix.h" #include "selfdrive/ui/qt/util.h" #include "tools/cabana/mainwin.h" +#include "tools/cabana/streams/livestream.h" +#include "tools/cabana/streams/replaystream.h" int main(int argc, char *argv[]) { QCoreApplication::setApplicationName("Cabana"); @@ -17,33 +19,40 @@ int main(int argc, char *argv[]) { cmd_parser.addOption({"demo", "use a demo route instead of providing your own"}); cmd_parser.addOption({"qcam", "load qcamera"}); cmd_parser.addOption({"ecam", "load wide road camera"}); + cmd_parser.addOption({"stream", "read can messages from live streaming"}); + cmd_parser.addOption({"zmq", "the ip address on which to receive zmq messages", "zmq"}); cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"}); cmd_parser.process(app); const QStringList args = cmd_parser.positionalArguments(); - if (args.empty() && !cmd_parser.isSet("demo")) { + if (args.empty() && !cmd_parser.isSet("demo") && !cmd_parser.isSet("stream")) { cmd_parser.showHelp(); } + std::unique_ptr op_prefix; + std::unique_ptr stream; - const QString route = args.empty() ? DEMO_ROUTE : args.first(); - uint32_t replay_flags = REPLAY_FLAG_NONE; - if (cmd_parser.isSet("ecam")) { - replay_flags |= REPLAY_FLAG_ECAM; - } else if (cmd_parser.isSet("qcam")) { - replay_flags |= REPLAY_FLAG_QCAMERA; - } - - // TODO: Remove when OpenpilotPrefix supports ZMQ + if (cmd_parser.isSet("stream")) { + stream.reset(new LiveStream(&app, cmd_parser.value("zmq"))); + } else { + // TODO: Remove when OpenpilotPrefix supports ZMQ #ifndef __APPLE__ - OpenpilotPrefix op_prefix; + op_prefix.reset(new OpenpilotPrefix()); #endif - - CANMessages p(&app); - int ret = 0; - if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { - MainWindow w; - w.show(); - ret = app.exec(); + const QString route = args.empty() ? DEMO_ROUTE : args.first(); + uint32_t replay_flags = REPLAY_FLAG_NONE; + if (cmd_parser.isSet("ecam")) { + replay_flags |= REPLAY_FLAG_ECAM; + } else if (cmd_parser.isSet("qcam")) { + replay_flags |= REPLAY_FLAG_QCAMERA; + } + auto replay_stream = new ReplayStream(&app); + stream.reset(replay_stream); + if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { + return 0; + } } - return ret; + + MainWindow w; + w.show(); + return app.exec(); } diff --git a/tools/cabana/canmessages.h b/tools/cabana/canmessages.h deleted file mode 100644 index c30361af41..0000000000 --- a/tools/cabana/canmessages.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include "opendbc/can/common_dbc.h" -#include "tools/cabana/settings.h" -#include "tools/replay/replay.h" - -struct CanData { - double ts = 0.; - uint8_t src = 0; - uint32_t address = 0; - uint32_t count = 0; - uint32_t freq = 0; - QByteArray dat; - QList colors; -}; - -class CANMessages : public QObject { - Q_OBJECT - -public: - CANMessages(QObject *parent); - ~CANMessages(); - bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); - void seekTo(double ts); - bool eventFilter(const Event *event); - - inline QString routeName() const { return replay->route()->name(); } - inline QString carFingerprint() const { return replay->carFingerprint().c_str(); } - inline VisionStreamType visionStreamType() const { return replay->hasFlag(REPLAY_FLAG_ECAM) ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD; } - inline double totalSeconds() const { return replay->totalSeconds(); } - inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } - inline double currentSec() const { return replay->currentSeconds(); } - inline QDateTime currentDateTime() const { return replay->currentDateTime(); } - inline const CanData &lastMessage(const QString &id) { return can_msgs[id]; } - - inline const Route* route() const { return replay->route(); } - inline const std::vector *events() const { return replay->events(); } - inline void setSpeed(float speed) { replay->setSpeed(speed); } - inline bool isPaused() const { return replay->isPaused(); } - void pause(bool pause); - inline const std::vector> getTimeline() { return replay->getTimeline(); } - -signals: - void paused(); - void resume(); - void seekedTo(double sec); - void streamStarted(); - void eventsMerged(); - void updated(); - void msgsReceived(const QHash *); - void received(QHash *); - -public: - QMap can_msgs; - -protected: - void process(QHash *); - void settingChanged(); - - Replay *replay = nullptr; - std::atomic counters_begin_sec = 0; - std::atomic processing = false; - QHash counters; -}; - -inline QString toHex(const QByteArray &dat) { - return dat.toHex(' ').toUpper(); -} -inline char toHex(uint value) { - return "0123456789ABCDEF"[value & 0xF]; -} - -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)]; -} - -// A global pointer referring to the unique CANMessages object -extern CANMessages *can; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 412365a15b..0a855b851b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -69,8 +69,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { column_count = settings.chart_column_count; 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(can, &AbstractStream::eventsMerged, this, &ChartsWidget::updateState); + QObject::connect(can, &AbstractStream::updated, this, &ChartsWidget::updateState); QObject::connect(show_all_values_btn, &QAction::triggered, this, &ChartsWidget::showAllData); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); @@ -83,27 +83,33 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { }); } -void ChartsWidget::eventsMerged() { - if (auto events = can->events(); events && !events->empty()) { - event_range.first = (events->front()->mono_time / (double)1e9) - can->routeStartTime(); - event_range.second = (events->back()->mono_time / (double)1e9) - can->routeStartTime(); - updateState(); - } -} - void ChartsWidget::updateDisplayRange() { - auto prev_range = display_range; - double current_sec = can->currentSec(); - if (current_sec < display_range.first || current_sec >= (display_range.second - 5)) { - // reached the end, or seeked to a timestamp out of range. - display_range.first = current_sec - 5; - } - display_range.first = std::floor(std::max(display_range.first, event_range.first) * 10.0) / 10.0; - display_range.second = std::floor(std::min(display_range.first + max_chart_range, event_range.second) * 10.0) / 10.0; - if (prev_range != display_range) { - QFutureSynchronizer future_synchronizer; - for (auto c : charts) - future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::setEventsRange, display_range)); + auto events = can->events(); + double min_event_sec = (events->front()->mono_time / (double)1e9) - can->routeStartTime(); + double max_event_sec = (events->back()->mono_time / (double)1e9) - can->routeStartTime(); + const double cur_sec = can->currentSec(); + if (!can->liveStreaming()) { + auto prev_range = display_range; + if (cur_sec < display_range.first || cur_sec >= (display_range.second - 5)) { + // reached the end, or seeked to a timestamp out of range. + display_range.first = cur_sec - 5; + } + display_range.first = std::floor(std::max(min_event_sec, display_range.first)); + display_range.second = std::floor(std::min(display_range.first + max_chart_range, max_event_sec)); + if (prev_range != display_range) { + QFutureSynchronizer future_synchronizer; + for (auto c : charts) { + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::setEventsRange, display_range)); + } + } + } else { + if (cur_sec >= (display_range.second - 5)) { + display_range.first = std::floor(std::max(min_event_sec, cur_sec - settings.max_chart_x_range / 2.0)); + } + display_range.second = std::floor(display_range.first + settings.max_chart_x_range); + for (auto c : charts) { + c->updateSeries(nullptr, events, false); + } } } @@ -151,7 +157,7 @@ void ChartsWidget::updateToolBar() { bool displaying_all = max_chart_range != min_range; show_all_values_btn->setText(tr("%1 minutes").arg(max_chart_range / 60)); show_all_values_btn->setToolTip(tr("Click to display %1 data").arg(displaying_all ? tr("%1 minutes").arg(min_range / 60) : tr("ALL cached"))); - show_all_values_btn->setVisible(!is_zoomed); + show_all_values_btn->setVisible(!is_zoomed && !can->liveStreaming()); remove_all_btn->setEnabled(!charts.isEmpty()); reset_zoom_btn->setEnabled(is_zoomed); range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); @@ -274,6 +280,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->addAxis(axis_y, Qt::AlignLeft); chart->legend()->setShowToolTips(true); chart->layout()->setContentsMargins(0, 0, 0, 0); + chart->setMargins({20, 11, 11, 11}); QToolButton *remove_btn = new QToolButton(); remove_btn->setIcon(bootstrapPixmap("x")); @@ -293,7 +300,8 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { setChart(chart); setRenderHint(QPainter::Antialiasing); - setRubberBand(QChartView::HorizontalRubberBand); + // TODO: enable zoomIn/seekTo in live streaming mode. + setRubberBand(can->liveStreaming() ? QChartView::NoRubberBand : QChartView::HorizontalRubberBand); QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); @@ -331,7 +339,6 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); updateTitle(); updateSeries(sig); - updateAxisY(); emit seriesAdded(msg_id, sig); } @@ -366,7 +373,6 @@ void ChartView::signalUpdated(const Signal *sig) { updateTitle(); // TODO: don't update series if only name changed. updateSeries(sig); - updateAxisY(); } } @@ -448,22 +454,21 @@ void ChartView::setDisplayRange(double min, double max) { } } -void ChartView::updateSeries(const Signal *sig) { - auto events = can->events(); +void ChartView::updateSeries(const Signal *sig, const std::vector *events, bool clear) { + if (!events) events = can->events(); if (!events || sigs.isEmpty()) return; for (auto &s : sigs) { if (!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(); - + if (clear) { + s.vals.clear(); + s.last_value_mono_time = 0; + } 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; - + uint64_t begin_ts = can->liveStreaming() ? s.last_value_mono_time : (route_start_time + events_range.first) * 1e9; + Event begin_event(cereal::Event::Which::INIT_DATA, begin_ts); + auto begin = std::upper_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); + uint64_t end_ns = can->liveStreaming() ? events->back()->mono_time : (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()) { @@ -472,14 +477,20 @@ void ChartView::updateSeries(const Signal *sig) { 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; } } } } + if (!s.vals.isEmpty()) { + auto [min_v, max_v] = std::minmax_element(s.vals.begin(), s.vals.end(), [](auto &l, auto &r) { return l.y() < r.y(); }); + s.min_y = min_v->y(); + s.max_y = max_v->y(); + s.last_value_mono_time = events->back()->mono_time; + } else { + s.min_y = s.max_y = 0; + } s.series->replace(s.vals); + updateAxisY(); } } } @@ -490,7 +501,7 @@ void ChartView::updateAxisY() { 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()}) { + if (can->liveStreaming() || 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; @@ -583,7 +594,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { emit zoomIn(min, max); } event->accept(); - } else if (event->button() == Qt::RightButton) { + } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { emit zoomReset(); event->accept(); } else { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 54c84ad2db..9ba5ce5a30 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -12,8 +12,8 @@ #include #include -#include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" using namespace QtCharts; @@ -25,7 +25,7 @@ public: 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 updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void setEventsRange(const std::pair &range); void setDisplayRange(double min, double max); void setPlotAreaLeftPosition(int pos); @@ -40,6 +40,7 @@ public: double min_y = 0; double max_y = 0; QVector vals; + uint64_t last_value_mono_time = 0; }; signals: @@ -128,7 +129,6 @@ private: QList charts; uint32_t max_chart_range = 0; bool is_zoomed = false; - std::pair event_range; std::pair display_range; std::pair zoomed_range; bool use_dark_theme = false; diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 7ea1f66653..e46223d630 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -2,7 +2,6 @@ #include -#include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" class EditMsgCommand : public QUndoCommand { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index c7675121bb..5db6737be8 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -28,9 +28,7 @@ public: static std::pair parseId(const QString &id); inline static std::vector allDBCNames() { return get_dbc_names(); } - inline std::map &allMsgs() { return msgs; } inline QString name() const { return dbc ? dbc->name.c_str() : ""; } - void updateMsg(const QString &id, const QString &name, uint32_t size); void removeMsg(const QString &id); inline const std::map &messages() const { return msgs; } diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 247111aaf4..78e5a6a6f6 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -8,9 +8,9 @@ #include #include "selfdrive/ui/qt/util.h" -#include "tools/cabana/canmessages.h" #include "tools/cabana/commands.h" #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" // DetailWidget @@ -99,7 +99,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart 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(); }); - QObject::connect(can, &CANMessages::msgsReceived, this, &DetailWidget::updateState); + QObject::connect(can, &AbstractStream::msgsReceived, this, &DetailWidget::updateState); QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { dbcMsgChanged(); }); QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index c6ee7d9086..f0f40697b8 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -222,8 +222,13 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(comp_box, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); QObject::connect(dynamic_mode, &QCheckBox::stateChanged, model, &HistoryLogModel::setDynamicMode); - QObject::connect(can, &CANMessages::seekedTo, model, &HistoryLogModel::refresh); - QObject::connect(can, &CANMessages::eventsMerged, model, &HistoryLogModel::segmentsMerged); + QObject::connect(can, &AbstractStream::seekedTo, model, &HistoryLogModel::refresh); + QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged); + + if (can->liveStreaming()) { + dynamic_mode->setChecked(true); + dynamic_mode->setEnabled(false); + } } void LogsWidget::setMessage(const QString &message_id) { diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 1eea7e5eba..2ab204af15 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -7,8 +7,8 @@ #include #include -#include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" class HeaderView : public QHeaderView { public: diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 89876f4267..48c9ad3a56 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -58,8 +58,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); - QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); - QObject::connect(can, &CANMessages::streamStarted, this, &MainWindow::loadDBCFromFingerprint); + QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(detail_widget->undo_stack, &QUndoStack::indexChanged, [this](int index) { setWindowTitle(tr("%1%2 - Cabana").arg(index > 0 ? "* " : "").arg(dbc()->name())); @@ -123,9 +122,13 @@ void MainWindow::createDockWindows() { charts_layout->setContentsMargins(0, 0, 0, 0); charts_layout->addWidget(charts_widget); - video_widget = new VideoWidget(this); video_splitter = new QSplitter(Qt::Vertical,this); - video_splitter->addWidget(video_widget); + + if (!can->liveStreaming()) { + video_widget = new VideoWidget(this); + video_splitter->addWidget(video_widget); + QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); + } video_splitter->addWidget(charts_container); video_splitter->restoreState(settings.video_splitter_state); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index c1a5908a53..a38834b997 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -47,7 +47,7 @@ protected: void setOption(); void findSimilarBits(); - VideoWidget *video_widget; + VideoWidget *video_widget = nullptr; QDockWidget *video_dock; MessagesWidget *messages_widget; DetailWidget *detail_widget; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 5deac031a1..0d06604fdc 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -26,7 +26,6 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget->setItemDelegateForColumn(4, new MessageBytesDelegate(table_widget)); table_widget->setSelectionBehavior(QAbstractItemView::SelectRows); table_widget->setSelectionMode(QAbstractItemView::SingleSelection); - table_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); table_widget->setSortingEnabled(true); table_widget->sortByColumn(0, Qt::AscendingOrder); table_widget->setColumnWidth(0, 250); @@ -39,7 +38,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { // signals/slots QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); - QObject::connect(can, &CANMessages::msgsReceived, model, &MessageListModel::msgsReceived); + QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 8b74f1427e..187e4715b9 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -4,7 +4,7 @@ #include #include -#include "tools/cabana/canmessages.h" +#include "tools/cabana/streams/abstractstream.h" class MessageListModel : public QAbstractTableModel { Q_OBJECT diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 0b0610edc9..7a25449c81 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -28,7 +28,7 @@ void Settings::save() { void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); - cached_segment_limit = s.value("cached_segment", 3).toInt(); + cached_segment_limit = s.value("cached_segment", 5).toInt(); chart_height = s.value("chart_height", 200).toInt(); max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); chart_column_count = s.value("chart_column_count", 1).toInt(); @@ -51,13 +51,13 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { form_layout->addRow("FPS", fps); cached_segment = new QSpinBox(this); - cached_segment->setRange(3, 60); + cached_segment->setRange(5, 60); cached_segment->setSingleStep(1); cached_segment->setValue(settings.cached_segment_limit); form_layout->addRow(tr("Cached segments limit"), cached_segment); max_chart_x_range = new QSpinBox(this); - max_chart_x_range->setRange(1, 60); + max_chart_x_range->setRange(3, 60); max_chart_x_range->setSingleStep(1); max_chart_x_range->setValue(settings.max_chart_x_range / 60); form_layout->addRow(tr("Chart range (minutes)"), max_chart_x_range); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 924021eb94..ed0ba3a549 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -14,7 +14,7 @@ public: void load(); int fps = 10; - int cached_segment_limit = 3; + int cached_segment_limit = 5; int chart_height = 200; int chart_column_count = 1; int max_chart_x_range = 3 * 60; // 3 minutes diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index a18f1d34f0..fcc27baeb1 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -7,8 +7,8 @@ #include #include "selfdrive/ui/qt/widgets/controls.h" -#include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" class SignalForm : public QWidget { Q_OBJECT diff --git a/tools/cabana/canmessages.cc b/tools/cabana/streams/abstractstream.cc similarity index 64% rename from tools/cabana/canmessages.cc rename to tools/cabana/streams/abstractstream.cc index 9b5f41c60a..6ae1900184 100644 --- a/tools/cabana/canmessages.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,47 +1,13 @@ -#include "tools/cabana/canmessages.h" -#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" -CANMessages *can = nullptr; +AbstractStream *can = nullptr; -CANMessages::CANMessages(QObject *parent) : QObject(parent) { +AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_live_streaming(is_live_streaming), QObject(parent) { can = this; - QObject::connect(this, &CANMessages::received, this, &CANMessages::process, Qt::QueuedConnection); - QObject::connect(&settings, &Settings::changed, this, &CANMessages::settingChanged); + QObject::connect(this, &AbstractStream::received, this, &AbstractStream::process, Qt::QueuedConnection); } -CANMessages::~CANMessages() { - replay->stop(); -} - -static bool event_filter(const Event *e, void *opaque) { - CANMessages *c = (CANMessages *)opaque; - return c->eventFilter(e); -} - -static QColor blend(QColor a, QColor b) { - return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); -} - -bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { - replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); - replay->setSegmentCacheLimit(settings.cached_segment_limit); - replay->installEventFilter(event_filter, this); - QObject::connect(replay, &Replay::seekedTo, this, &CANMessages::seekedTo); - QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); - QObject::connect(replay, &Replay::streamStarted, this, &CANMessages::streamStarted); - if (replay->load()) { - const auto &segments = replay->route()->segments(); - if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { - qWarning() << "no rlogs in route" << route; - return false; - } - replay->start(); - return true; - } - return false; -} - -void CANMessages::process(QHash *messages) { +void AbstractStream::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { can_msgs[it.key()] = it.value(); } @@ -51,7 +17,11 @@ void CANMessages::process(QHash *messages) { processing = false; } -bool CANMessages::eventFilter(const Event *event) { +static QColor blend(QColor a, QColor b) { + return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); +} + +bool AbstractStream::updateEvent(const Event *event) { static std::unique_ptr new_msgs = std::make_unique>(); static QHash prev_dat; static QHash> colors; @@ -59,7 +29,7 @@ bool CANMessages::eventFilter(const Event *event) { static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { - double current_sec = replay->currentSeconds(); + double current_sec = currentSec(); if (counters_begin_sec == 0 || counters_begin_sec >= current_sec) { new_msgs->clear(); counters.clear(); @@ -79,7 +49,7 @@ bool CANMessages::eventFilter(const Event *event) { data.freq = data.count / delta; } - // Init colors + // Init colors if (colors[id].size() != data.dat.size()) { colors[id].clear(); for (int i = 0; i < data.dat.size(); i++){ @@ -146,18 +116,3 @@ bool CANMessages::eventFilter(const Event *event) { } return true; } - -void CANMessages::seekTo(double ts) { - replay->seekTo(std::max(double(0), ts), false); - counters_begin_sec = 0; - emit updated(); -} - -void CANMessages::pause(bool pause) { - replay->pause(pause); - emit (pause ? paused() : resume()); -} - -void CANMessages::settingChanged() { - replay->setSegmentCacheLimit(settings.cached_segment_limit); -} diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h new file mode 100644 index 0000000000..1fe90c8595 --- /dev/null +++ b/tools/cabana/streams/abstractstream.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include +#include + +#include "tools/cabana/settings.h" +#include "tools/replay/replay.h" + +struct CanData { + double ts = 0.; + uint8_t src = 0; + uint32_t address = 0; + uint32_t count = 0; + uint32_t freq = 0; + QByteArray dat; + QList colors; +}; + +class AbstractStream : public QObject { + Q_OBJECT + +public: + AbstractStream(QObject *parent, bool is_live_streaming); + virtual ~AbstractStream() {}; + inline bool liveStreaming() const { return is_live_streaming; } + virtual void seekTo(double ts) {} + virtual QString routeName() const = 0; + virtual QString carFingerprint() const { return ""; } + virtual double totalSeconds() const { return 0; } + virtual double routeStartTime() const { return 0; } + virtual double currentSec() const = 0; + virtual QDateTime currentDateTime() const { return {}; } + virtual const CanData &lastMessage(const QString &id) { return can_msgs[id]; } + virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } + virtual const Route *route() const { return nullptr; } + virtual const std::vector *events() const = 0; + virtual void setSpeed(float speed) {} + virtual bool isPaused() const { return false; } + virtual void pause(bool pause) {} + virtual const std::vector> getTimeline() { return {}; } + +signals: + void paused(); + void resume(); + void seekedTo(double sec); + void streamStarted(); + void eventsMerged(); + void updated(); + void msgsReceived(const QHash *); + void received(QHash *); + +public: + QMap can_msgs; + +protected: + void process(QHash *); + bool updateEvent(const Event *event); + + bool is_live_streaming = false; + std::atomic counters_begin_sec = 0; + std::atomic processing = false; + QHash counters; +}; + +inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } +inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } +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)]; +} + +// A global pointer referring to the unique AbstractStream object +extern AbstractStream *can; diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc new file mode 100644 index 0000000000..bc5b811f44 --- /dev/null +++ b/tools/cabana/streams/livestream.cc @@ -0,0 +1,71 @@ +#include "tools/cabana/streams/livestream.h" + +LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), AbstractStream(parent, true) { + if (!zmq_address.isEmpty()) { + setenv("ZMQ", "1", 1); + } + updateCachedNS(); + QObject::connect(&settings, &Settings::changed, this, &LiveStream::updateCachedNS); + stream_thread = new QThread(this); + QObject::connect(stream_thread, &QThread::started, [=]() { streamThread(); }); + QObject::connect(stream_thread, &QThread::finished, stream_thread, &QThread::deleteLater); + stream_thread->start(); +} + +LiveStream::~LiveStream() { + stream_thread->requestInterruption(); + stream_thread->quit(); + stream_thread->wait(); + for (Event *e : can_events) ::delete e; + for (auto m : messages) delete m; +} + +void LiveStream::streamThread() { + std::unique_ptr context(Context::create()); + std::string address = zmq_address.isEmpty() ? "127.0.0.1" : zmq_address.toStdString(); + std::unique_ptr sock(SubSocket::create(context.get(), "can", address)); + assert(sock != NULL); + sock->setTimeout(50); + + // run as fast as messages come in + while (!QThread::currentThread()->isInterruptionRequested()) { + Message *msg = sock->receive(true); + if (!msg) { + QThread::msleep(50); + continue; + } + AlignedBuffer *buf = messages.emplace_back(new AlignedBuffer()); + Event *evt = ::new Event(buf->align(msg)); + delete msg; + + { + std::lock_guard lk(lock); + can_events.push_back(evt); + if ((evt->mono_time - can_events.front()->mono_time) > cache_ns) { + ::delete can_events.front(); + delete messages.front(); + can_events.pop_front(); + messages.pop_front(); + } + } + if (start_ts == 0) { + start_ts = evt->mono_time; + emit streamStarted(); + } + current_ts = evt->mono_time; + if (start_ts > current_ts) { + qDebug() << "stream is looping back to old time stamp"; + start_ts = current_ts.load(); + } + updateEvent(evt); + // TODO: write stream to log file to replay it with cabana --data_dir flag. + } +} + +const std::vector *LiveStream::events() const { + std::lock_guard lk(lock); + events_vector.clear(); + events_vector.reserve(can_events.size()); + std::copy(can_events.begin(), can_events.end(), std::back_inserter(events_vector)); + return &events_vector; +} diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h new file mode 100644 index 0000000000..17301d48e7 --- /dev/null +++ b/tools/cabana/streams/livestream.h @@ -0,0 +1,31 @@ +#pragma once + +#include "tools/cabana/streams/abstractstream.h" + +class LiveStream : public AbstractStream { + Q_OBJECT + +public: + LiveStream(QObject *parent, QString address = {}); + ~LiveStream(); + inline QString routeName() const override { + return QString("Live Streaming From %1").arg(zmq_address.isEmpty() ? "127.0.0.1" : zmq_address); + } + inline double routeStartTime() const override { return start_ts / (double)1e9; } + inline double currentSec() const override { return (current_ts - start_ts) / (double)1e9; } + const std::vector *events() const override; + +protected: + void streamThread(); + void updateCachedNS() { cache_ns = (settings.cached_segment_limit * 60) * 1e9; } + + mutable std::mutex lock; + mutable std::vector events_vector; + std::deque can_events; + std::deque messages; + std::atomic start_ts = 0; + std::atomic current_ts = 0; + std::atomic cache_ns = 0; + const QString zmq_address; + QThread *stream_thread; +}; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc new file mode 100644 index 0000000000..97a3911adf --- /dev/null +++ b/tools/cabana/streams/replaystream.cc @@ -0,0 +1,54 @@ +#include "tools/cabana/streams/replaystream.h" + +#include "tools/cabana/dbcmanager.h" + +ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent, false) { + QObject::connect(&settings, &Settings::changed, [this]() { + if (replay) replay->setSegmentCacheLimit(settings.cached_segment_limit); + }); +} + +ReplayStream::~ReplayStream() { + if (replay) replay->stop(); +} + +static bool event_filter(const Event *e, void *opaque) { + return ((ReplayStream *)opaque)->eventFilter(e); +} + +bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { + replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); + replay->setSegmentCacheLimit(settings.cached_segment_limit); + replay->installEventFilter(event_filter, this); + QObject::connect(replay, &Replay::seekedTo, this, &AbstractStream::seekedTo); + QObject::connect(replay, &Replay::segmentsMerged, this, &AbstractStream::eventsMerged); + QObject::connect(replay, &Replay::streamStarted, this, &AbstractStream::streamStarted); + if (replay->load()) { + const auto &segments = replay->route()->segments(); + if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { + qWarning() << "no rlogs in route" << route; + return false; + } + replay->start(); + return true; + } + return false; +} + +bool ReplayStream::eventFilter(const Event *event) { + if (event->which == cereal::Event::Which::CAN) { + updateEvent(event); + } + return true; +} + +void ReplayStream::seekTo(double ts) { + replay->seekTo(std::max(double(0), ts), false); + counters_begin_sec = 0; + emit updated(); +} + +void ReplayStream::pause(bool pause) { + replay->pause(pause); + emit(pause ? paused() : resume()); +} diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h new file mode 100644 index 0000000000..1688915212 --- /dev/null +++ b/tools/cabana/streams/replaystream.h @@ -0,0 +1,32 @@ +#pragma once + +#include "opendbc/can/common_dbc.h" +#include "tools/cabana/streams/abstractstream.h" +#include "tools/cabana/settings.h" + +class ReplayStream : public AbstractStream { + Q_OBJECT + +public: + ReplayStream(QObject *parent); + ~ReplayStream(); + bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); + bool eventFilter(const Event *event); + void seekTo(double ts) override; + inline QString routeName() const override { return replay->route()->name(); } + inline QString carFingerprint() const override { return replay->carFingerprint().c_str(); } + inline VisionStreamType visionStreamType() const override { return replay->hasFlag(REPLAY_FLAG_ECAM) ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD; } + inline double totalSeconds() const override { return replay->totalSeconds(); } + inline double routeStartTime() const override { return replay->routeStartTime() / (double)1e9; } + inline double currentSec() const override { return replay->currentSeconds(); } + inline QDateTime currentDateTime() const override { return replay->currentDateTime(); } + inline const Route *route() const override { return replay->route(); } + inline const std::vector *events() const override { return replay->events(); } + inline void setSpeed(float speed) override { replay->setSpeed(speed); } + inline bool isPaused() const override { return replay->isPaused(); } + void pause(bool pause) override; + inline const std::vector> getTimeline() override { return replay->getTimeline(); } + +private: + Replay *replay = nullptr; +}; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 8a05e3e236..63d01b152d 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -7,8 +7,8 @@ #include #include -#include "tools/cabana/canmessages.h" #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) { setWindowTitle(tr("Find similar bits")); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 2f6aab249a..7d46769a47 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -70,10 +70,10 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(formatTime(value / 1000)); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); - QObject::connect(can, &CANMessages::updated, this, &VideoWidget::updateState); - QObject::connect(can, &CANMessages::paused, this, &VideoWidget::updatePlayBtnState); - QObject::connect(can, &CANMessages::resume, this, &VideoWidget::updatePlayBtnState); - QObject::connect(can, &CANMessages::streamStarted, [this]() { + QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); + QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); + QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState); + QObject::connect(can, &AbstractStream::streamStarted, [this]() { end_time_label->setText(formatTime(can->totalSeconds())); slider->setRange(0, can->totalSeconds() * 1000); }); @@ -130,7 +130,7 @@ Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { setMouseTracking(true); QObject::connect(can, SIGNAL(streamStarted()), timer, SLOT(start())); - QObject::connect(can, &CANMessages::streamStarted, this, &Slider::streamStarted); + QObject::connect(can, &AbstractStream::streamStarted, this, &Slider::streamStarted); } void Slider::streamStarted() { diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index e9899abbbf..6b4c02c573 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -11,7 +11,7 @@ #include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/qt/widgets/controls.h" -#include "tools/cabana/canmessages.h" +#include "tools/cabana/streams/abstractstream.h" class Slider : public QSlider { Q_OBJECT From c1fcd63bba1797133309d94b360d98e147b69548 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 19 Jan 2023 18:42:34 -0800 Subject: [PATCH 0669/1179] cameraview: fix spaces in debug print --- selfdrive/ui/qt/widgets/cameraview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 16aad13437..4a7874b160 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -358,7 +358,7 @@ void CameraWidget::vipcThread() { while (!QThread::currentThread()->isInterruptionRequested()) { if (!vipc_client || cur_stream != requested_stream_type) { clearFrames(); - qDebug() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; + qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; cur_stream = requested_stream_type; vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); } From 1c128db8b07a1abf10b9a2f2cc6a7af22c9ae065 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 19 Jan 2023 20:54:50 -0800 Subject: [PATCH 0670/1179] Cabana: darken signal backgrounds on hover (#27010) * darker signal background when hovering * remove import * little better --- tools/cabana/binaryview.cc | 5 +++-- tools/cabana/signaledit.cc | 9 ++++++--- tools/cabana/signaledit.h | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 8d28080790..84c2dd2a52 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -242,8 +242,9 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->fillRect(option.rect, selection_color); painter->setPen(option.palette.color(QPalette::BrightText)); } else if (!item->sigs.isEmpty() && (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig))) { - painter->fillRect(option.rect, item->bg_color); - painter->setPen(item->sigs.contains(bin_view->hovered_sig) ? option.palette.color(QPalette::BrightText) : Qt::black); + bool sig_hovered = item->sigs.contains(bin_view->hovered_sig); + painter->fillRect(option.rect, sig_hovered ? item->bg_color.darker(125) : item->bg_color); // 4/5x brightness + painter->setPen(sig_hovered ? option.palette.color(QPalette::BrightText) : Qt::black); } painter->drawText(option.rect, Qt::AlignCenter, item->val); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index e2025dcc82..cc57cf0f3e 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -89,6 +89,8 @@ SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(pa main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); + bg_color = QColor(getColor(form_idx)); + // title bar auto title_bar = new QWidget(this); title_bar->setFixedHeight(32); @@ -142,7 +144,7 @@ void SignalEdit::setSignal(const QString &message_id, const Signal *signal) { updateForm(msg_id == message_id && form->isVisible()); msg_id = message_id; color_label->setText(QString::number(form_idx + 1)); - color_label->setStyleSheet(QString("color:black; background-color:%2").arg(getColor(form_idx))); + color_label->setStyleSheet(QString("color:black; background-color:%2").arg(bg_color.name())); title->setText(sig->name.c_str()); show(); } @@ -199,8 +201,9 @@ void SignalEdit::updateForm(bool visible) { } void SignalEdit::signalHovered(const Signal *s) { - auto color = sig == s ? "white" : "black"; - color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(color).arg(getColor(form_idx))); + auto text_color = sig == s ? "white" : "black"; + auto _bg_color = sig == s ? bg_color.darker(125) : bg_color; // 4/5x brightness + color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(text_color).arg(_bg_color.name())); } void SignalEdit::enterEvent(QEvent *event) { diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index fcc27baeb1..90df3fd3f4 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -54,5 +54,6 @@ protected: QLabel *color_label; QLabel *icon; int form_idx = 0; + QColor bg_color; QToolButton *plot_btn; }; From c408b7e30609ca64971a4278eab16643fbb123b3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 19 Jan 2023 23:06:18 -0800 Subject: [PATCH 0671/1179] UI: show experimental long available to release users (#26910) * UI: show experimental long available to release users * more description * cleanup * hide toggle * fix process replay * clear param * actually fix --- common/params.cc | 3 ++- selfdrive/car/car_helpers.py | 6 ++--- selfdrive/controls/controlsd.py | 8 +++---- selfdrive/manager/manager.py | 3 ++- .../test/process_replay/process_replay.py | 2 +- selfdrive/ui/qt/offroad/settings.cc | 20 ++++++++++++---- selfdrive/ui/translations/main_de.ts | 16 +++++++++---- selfdrive/ui/translations/main_ja.ts | 24 ++++++++++++------- selfdrive/ui/translations/main_ko.ts | 24 ++++++++++++------- selfdrive/ui/translations/main_pt-BR.ts | 24 ++++++++++++------- selfdrive/ui/translations/main_zh-CHS.ts | 24 ++++++++++++------- selfdrive/ui/translations/main_zh-CHT.ts | 24 ++++++++++++------- 12 files changed, 117 insertions(+), 61 deletions(-) diff --git a/common/params.cc b/common/params.cc index 8f6532bc79..35ceecfdc3 100644 --- a/common/params.cc +++ b/common/params.cc @@ -104,7 +104,7 @@ std::unordered_map keys = { {"DisablePowerDown", PERSISTENT}, {"ExperimentalMode", PERSISTENT}, {"ExperimentalModeConfirmed", PERSISTENT}, - {"ExperimentalLongitudinalEnabled", PERSISTENT}, // WARNING: THIS MAY DISABLE AEB + {"ExperimentalLongitudinalEnabled", PERSISTENT}, {"DisableUpdates", PERSISTENT}, {"DisengageOnAccelerator", PERSISTENT}, {"DongleId", PERSISTENT}, @@ -134,6 +134,7 @@ std::unordered_map keys = { {"IsRhdDetected", PERSISTENT}, {"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"IsTestedBranch", CLEAR_ON_MANAGER_START}, + {"IsReleaseBranch", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"LaikadEphemeris", PERSISTENT | DONT_LOG}, diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 61e7a3d55d..88e8c72153 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -173,17 +173,15 @@ def fingerprint(logcan, sendcan, num_pandas): return car_fingerprint, finger, vin, car_fw, source, exact_match -def get_car(logcan, sendcan, num_pandas=1): +def get_car(logcan, sendcan, experimental_long_allowed, 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) candidate = "mock" - experimental_long = Params().get_bool("ExperimentalLongitudinalEnabled") - CarInterface, CarController, CarState = interfaces[candidate] - CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long) + CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed) CP.carVin = vin CP.carFw = car_fw CP.fingerprintSource = source diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index ac36df7aa2..c0b01bfc99 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -99,7 +99,8 @@ class Controls: 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) + experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled") and not is_release_branch() + self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas) else: self.CI, self.CP = CI, CI.CP @@ -132,9 +133,6 @@ class Controls: safety_config.safetyModel = car.CarParams.SafetyModel.noOutput self.CP.safetyConfigs = [safety_config] - if is_release_branch(): - self.CP.experimentalLongitudinalAvailable = False - # Write CarParams for radard cp_bytes = self.CP.to_bytes() self.params.put("CarParams", cp_bytes) @@ -142,7 +140,7 @@ class Controls: put_nonblocking("CarParamsPersistent", cp_bytes) # cleanup old params - if not self.CP.experimentalLongitudinalAvailable: + if not self.CP.experimentalLongitudinalAvailable or is_release_branch(): self.params.remove("ExperimentalLongitudinalEnabled") if not self.CP.openpilotLongitudinalControl: self.params.remove("ExperimentalMode") diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 369c529626..865966d6c5 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -20,7 +20,7 @@ from selfdrive.manager.process_config import managed_processes from selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID from system.swaglog import cloudlog, add_file_handler from system.version import is_dirty, get_commit, get_version, get_origin, get_short_branch, \ - terms_version, training_version, is_tested_branch + terms_version, training_version, is_tested_branch, is_release_branch @@ -76,6 +76,7 @@ def manager_init() -> None: params.put("GitBranch", get_short_branch(default="")) params.put("GitRemote", get_origin(default="")) params.put_bool("IsTestedBranch", is_tested_branch()) + params.put_bool("IsReleaseBranch", is_release_branch()) # set dongle id reg_res = register(show_spinner=True) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 22ec099285..a7d53bf9da 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -188,7 +188,7 @@ def get_car_params(msgs, fsm, can_sock, fingerprint): canmsgs = [msg for msg in msgs if msg.which() == 'can'] for m in canmsgs[:300]: can.send(m.as_builder().to_bytes()) - _, CP = get_car(can, sendcan) + _, CP = get_car(can, sendcan, Params().get_bool("ExperimentalLongitudinalEnabled")) Params().put("CarParams", CP.to_bytes()) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index bde8628dc4..63b87149d4 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -132,16 +132,17 @@ void TogglesPanel::updateToggles() { .arg(tr("New Driving Visualization")) .arg(tr("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.")); + const bool is_release = params.getBool("IsReleaseBranch"); auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { AlignedBuffer aligned_buf; capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); cereal::CarParams::Reader CP = cmsg.getRoot(); - if (!CP.getExperimentalLongitudinalAvailable()) { + if (!CP.getExperimentalLongitudinalAvailable() || is_release) { params.remove("ExperimentalLongitudinalEnabled"); } - op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable()); + op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release); const bool op_long = CP.getOpenpilotLongitudinalControl() && !CP.getExperimentalLongitudinalAvailable(); const bool exp_long_enabled = CP.getExperimentalLongitudinalAvailable() && params.getBool("ExperimentalLongitudinalEnabled"); @@ -154,9 +155,18 @@ void TogglesPanel::updateToggles() { e2e_toggle->setEnabled(false); params.remove("ExperimentalMode"); - const QString no_long = tr("Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control."); - const QString exp_long = tr("Enable experimental longitudinal control to allow experimental mode."); - e2e_toggle->setDescription("" + (CP.getExperimentalLongitudinalAvailable() ? exp_long : no_long) + "

" + e2e_description); + const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control."); + + QString long_desc = unavailable + " " + \ + tr("openpilot longitudinal control may come in a future update."); + if (CP.getExperimentalLongitudinalAvailable()) { + if (is_release) { + long_desc = unavailable + " " + tr("An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches."); + } else { + long_desc = tr("Enable experimental longitudinal control to allow Experimental mode."); + } + } + e2e_toggle->setDescription("" + long_desc + "

" + e2e_description); } e2e_toggle->refresh(); diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index ecb44557c9..987202a03f 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1044,12 +1044,20 @@ location set Die Fahrvisualisierung wechselt bei niedrigen Geschwindigkeiten zur Straßengewandten Weitwinkelkamera, um manche Kurven besser zu zeigen. Außerdem wird das Experimenteller Modus logo oben rechts angezeigt.
- Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. - Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar, da es den eingebauten adaptiven Tempomaten des Autos benutzt. + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + - Enable experimental longitudinal control to allow experimental mode. - Aktiviere den experimentellen Openpilot Tempomaten für experimentelle Funktionen. + openpilot longitudinal control may come in a future update. + + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable experimental longitudinal control to allow Experimental mode. +
diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 8226dd59f9..aeeac6104b 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1017,14 +1017,6 @@ 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によるアクセル制御を利用できます。実験モードと合わせて利用することをお勧めします。 - - 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によるアクセル制御を有効にしてください。 - 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: openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。 @@ -1045,6 +1037,22 @@ location set 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. 新しい運転画面では、低速時に広角カメラの映像を表示することで、曲がる際の道路の視覚を向上します。実験段階を表すマークが右上に表示されます。 + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + + + + openpilot longitudinal control may come in a future update. + + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable experimental longitudinal control to allow Experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index bda64c53ab..80cf61c2c3 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -1017,14 +1017,6 @@ 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: openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 @@ -1045,6 +1037,22 @@ location set 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. 주행 시각화는 저속에서 도로를 향하는 광각 카메라로 전환되어 일부 회전을 더 잘 보여줍니다. 실험적 모드 로고도 우측상단에 표시됩니다. + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + + + + openpilot longitudinal control may come in a future update. + + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable experimental longitudinal control to allow Experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 105d6f77f0..3356372496 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1021,14 +1021,6 @@ trabalho definido 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. Neste carro o penpilot por padrão utiliza o ACC nativo do veículo ao invés de controlar longitudinalmente. Ative isto para mudar para o controle longitudinal do openpilot. Ativar o Modo Experimental é recomendado quando em uso do controle longitudinal experimental do openpilot. - - Experimental mode is currently unavailable on this car, since the car's stock ACC is used for longitudinal control. - O Modo Experimental está atualmente indisponível para este carro, já que o ACC original do carro é usado para controle longitudinal. - - - Enable experimental longitudinal control to allow experimental mode. - Ative o controle longitudinal experimental para permitir o modo experimental. - 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: openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-alfa</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: @@ -1049,6 +1041,22 @@ trabalho definido 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. A visualização da direção fará a transição para a câmera grande angular voltada para a estrada em baixas velocidades para mostrar melhor algumas curvas. O logotipo do modo Experimental também será exibido no canto superior direito. + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + + + + openpilot longitudinal control may come in a future update. + + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable experimental longitudinal control to allow Experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 31202e45f2..c0838e18f3 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1015,14 +1015,6 @@ 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纵向控制。当使用试验性的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: openpilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: @@ -1043,6 +1035,22 @@ location set 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. 当低速行驶时,驾驶视角将切换到前向广角摄像头,便于更完整地显示转向路径。右上角将显示试验模式图标。 + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + + + + openpilot longitudinal control may come in a future update. + + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable experimental longitudinal control to allow Experimental mode. + + Updater diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 0379e926c4..82e6cf0fc1 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1017,14 +1017,6 @@ 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: openpilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: @@ -1045,6 +1037,22 @@ location set 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. 低速行駛時,將會切換成路側廣角鏡頭,以完整顯示轉彎路徑,右上角將出現實驗模式圖案。 + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + + + + openpilot longitudinal control may come in a future update. + + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + + + + Enable experimental longitudinal control to allow Experimental mode. + + Updater From 42b0ecc891cf34fc6a82af587889096b7ee3ce3c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 19 Jan 2023 23:32:16 -0800 Subject: [PATCH 0672/1179] Genesis: GV60 2023 Advanced: add missing camera FW (#27011) add new camera FW from c104d893f7c211bb|2023-01-19--20-13-10 --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index ec7605657b..31cbe68d13 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1544,6 +1544,7 @@ FW_VERSIONS = { CAR.GENESIS_GV60_EV_1ST_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215', + b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU000 211215', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ', From 40cc43c076df7d0998b61a0a473b8127637fd07f Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Sat, 21 Jan 2023 03:43:14 +0900 Subject: [PATCH 0673/1179] Multilang: kor translation update (#27013) --- selfdrive/ui/translations/main_ko.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 80cf61c2c3..f50d2d9b3f 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -501,7 +501,7 @@ location set Become a comma prime member at connect.comma.ai - connect.comma.ai에서 comma prime에 가입합니다 + connect.comma.ai 접속 comma prime 가입 PRIME FEATURES: @@ -1019,7 +1019,7 @@ location set 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: - openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험 모드의 특징은 아래에 나열되어 있습니다 + openpilot은 기본적으로 <b>안정적 모드</b>로 주행합니다. 실험적 모드는 안정적 모드에 준비되지 않은 <b>알파 수준 기능</b>을 활성화 합니다. 실험적 모드의 특징은 아래에 나열되어 있습니다 🌮 End-to-End Longitudinal Control 🌮 @@ -1035,23 +1035,23 @@ location set 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. - 주행 시각화는 저속에서 도로를 향하는 광각 카메라로 전환되어 일부 회전을 더 잘 보여줍니다. 실험적 모드 로고도 우측상단에 표시됩니다. + 주행 시각화는 저속에서 도로를 향하는 광각 카메라로 전환되어 일부 회전을 더 잘 보여줍니다. 실험적 모드의 로고도 우측상단에 표시됩니다. Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - + 차량에 장착된 ACC가 롱컨트롤에 사용되기 때문에 현재 이 차량은 실험적 모드를 사용할 수 없습니다. openpilot longitudinal control may come in a future update. - + 오픈파일럿 롱컨트롤은 향후 업데이트에서 제공될 수 있습니다. An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - + 오픈파일럿 롱컨트롤의 실험 버전은 실험적 모드와 함께 릴리즈 되지 않은 브랜치에서 테스트할 수 있습니다. Enable experimental longitudinal control to allow Experimental mode. - + 실험적 롱컨트롤을 사용하려면 실험적 모드를 활성화 하세요. From 21af68e3c36eef4a84b076a41305caabf76bd4a9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 21 Jan 2023 02:43:30 +0800 Subject: [PATCH 0674/1179] cabana: improve video splitter (#27012) --- tools/cabana/mainwin.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 48c9ad3a56..d2e4ff9ca7 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -124,13 +124,20 @@ void MainWindow::createDockWindows() { video_splitter = new QSplitter(Qt::Vertical,this); + // splitter between video and charts + video_splitter = new QSplitter(Qt::Vertical, this); if (!can->liveStreaming()) { video_widget = new VideoWidget(this); video_splitter->addWidget(video_widget); QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); } video_splitter->addWidget(charts_container); + video_splitter->setStretchFactor(1, 1); video_splitter->restoreState(settings.video_splitter_state); + if (!can->liveStreaming() && video_splitter->sizes()[0] == 0) { + // display video at minimum size. + video_splitter->setSizes({1, 1}); + } video_dock = new QDockWidget(can->routeName(), this); video_dock->setObjectName(tr("VideoPanel")); @@ -284,7 +291,9 @@ void MainWindow::closeEvent(QCloseEvent *event) { settings.geometry = saveGeometry(); settings.window_state = saveState(); - settings.video_splitter_state = video_splitter->saveState(); + if (!can->liveStreaming()) { + settings.video_splitter_state = video_splitter->saveState(); + } settings.save(); QWidget::closeEvent(event); } From da621245b2cc84dd972b0582bec077a008c8e871 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 20 Jan 2023 10:46:45 -0800 Subject: [PATCH 0675/1179] UI: update translations during scons build (#27009) * UI: update translation during scons build * all in scons * debug * precious * debug * add missing * Update release/check-dirty.sh Co-authored-by: Shane Smiskol --- release/files_common | 6 ++++++ selfdrive/ui/SConscript | 14 +++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/release/files_common b/release/files_common index 0dc0e96226..edb37bc0de 100644 --- a/release/files_common +++ b/release/files_common @@ -320,6 +320,12 @@ selfdrive/ui/qt/widgets/*.cc selfdrive/ui/qt/widgets/*.h selfdrive/ui/qt/maps/*.cc selfdrive/ui/qt/maps/*.h +selfdrive/ui/qt/setup/*.cc +selfdrive/ui/qt/setup/*.h + +selfdrive/ui/installer/*.cc +selfdrive/ui/installer/*.h +selfdrive/ui/installer/*.cc system/camerad/SConscript system/camerad/main.cc diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 3ce7a0505d..0f28f5ccc3 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,4 +1,5 @@ import os +import json Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'transformations') @@ -67,11 +68,18 @@ if GetOption('test'): # build translation files -translation_sources = Glob("#selfdrive/ui/translations/*.ts", strings=True) +with open(File("translations/languages.json").abspath) as f: + languages = json.loads(f.read()) +translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.values()] translation_targets = [src.replace(".ts", ".qm") for src in translation_sources] -lrelease = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease' -qt_env.Command(translation_targets, translation_sources, f"{lrelease} $SOURCES") +lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease' +lupdate = qt_env.Command(translation_sources, qt_src, "selfdrive/ui/update_translations.py") +lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES") +qt_env.Depends(lrelease, lupdate) +qt_env.NoClean(translation_sources) +qt_env.Precious(translation_sources) +qt_env.NoCache(lupdate) # setup and factory resetter if GetOption('extras'): From 986ec99f827f98e01290461e8e35ebb5b68dd0f3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 20 Jan 2023 11:29:10 -0800 Subject: [PATCH 0676/1179] Multilang: add back some translations (#27019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add back translations * 🤔 * actually shouldn't be a space --- selfdrive/ui/translations/main_de.ts | 4 ++-- selfdrive/ui/translations/main_ja.ts | 4 ++-- selfdrive/ui/translations/main_pt-BR.ts | 6 +++--- selfdrive/ui/translations/main_zh-CHS.ts | 4 ++-- selfdrive/ui/translations/main_zh-CHT.ts | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 987202a03f..2606df5efe 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -1045,7 +1045,7 @@ location set Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - + Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar da es den eingebauten adaptiven Tempomaten des Autos benutzt. openpilot longitudinal control may come in a future update. @@ -1057,7 +1057,7 @@ location set Enable experimental longitudinal control to allow Experimental mode. - + Aktiviere den experimentellen Openpilot Tempomaten für experimentelle Funktionen. diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index aeeac6104b..16f35dffaa 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -1039,7 +1039,7 @@ location set Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - + この車のACCがアクセル制御を行うため実験モードを利用することができません。 openpilot longitudinal control may come in a future update. @@ -1051,7 +1051,7 @@ location set Enable experimental longitudinal control to allow Experimental mode. - + 実験段階のopenpilotによるアクセル制御を有効にしてください。 diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 3356372496..2bbc1abace 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -388,7 +388,7 @@ Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai - Obtenha instruções passo a passo exibidas e muito mais com + Obtenha instruções passo a passo exibidas e muito mais com uma assinatura prime Inscreva-se agora: https://connect.comma.ai @@ -1043,7 +1043,7 @@ trabalho definido Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - + O modo Experimental está atualmente indisponível para este carro já que o ACC original do carro é usado para controle longitudinal. openpilot longitudinal control may come in a future update. @@ -1055,7 +1055,7 @@ trabalho definido Enable experimental longitudinal control to allow Experimental mode. - + Ative o controle longitudinal experimental para permitir o modo Experimental. diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index c0838e18f3..792a918770 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -1037,7 +1037,7 @@ location set Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - + 由于此车辆使用自带的ACC纵向控制,当前无法使用试验模式。 openpilot longitudinal control may come in a future update. @@ -1049,7 +1049,7 @@ location set Enable experimental longitudinal control to allow Experimental mode. - + 启用试验性的纵向控制,以便允许使用试验模式。 diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 82e6cf0fc1..e8e2ab6bd3 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -1039,7 +1039,7 @@ location set Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - + 因車輛使用內建ACC系統,無法在本車輛上啟動實驗模式。 openpilot longitudinal control may come in a future update. @@ -1051,7 +1051,7 @@ location set Enable experimental longitudinal control to allow Experimental mode. - + 啟用實驗性縱向控制以使用實驗模式。 From 2c5a952a1c84a799b2951867943c4748618721d2 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Fri, 20 Jan 2023 16:33:05 -0300 Subject: [PATCH 0677/1179] Multilang: improve pt-BR translations (#26962) Co-authored-by: Shane Smiskol --- selfdrive/ui/translations/main_pt-BR.ts | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 2bbc1abace..92bb552d3d 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -132,19 +132,19 @@ Driver Camera - Câmera voltada para o Motorista + Câmera do Motorista PREVIEW - PREVISUAL + VER Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off) - Pré-visualizar a câmera voltada para o motorista para garantir que monitor tem uma boa visibilidade (veículo precisa estar desligado) + Pré-visualizar a câmera voltada para o motorista para garantir que o monitoramento do sistema tenha uma boa visibilidade (veículo precisa estar desligado) Reset Calibration - Resetar Calibragem + Reinicializar Calibragem RESET @@ -200,7 +200,7 @@ openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. - o openpilot requer que o dispositivo seja montado dentro de 4° esquerda ou direita e dentro de 5° para cima ou 8° para baixo. o openpilot está continuamente calibrando, resetar raramente é necessário. + O openpilot requer que o dispositivo seja montado dentro de 4° esquerda ou direita e dentro de 5° para cima ou 8° para baixo. O openpilot está continuamente calibrando, resetar raramente é necessário. Your device is pointed %1° %2 and %3° %4. @@ -389,7 +389,7 @@ Get turn-by-turn directions displayed and more with a comma prime subscription. Sign up now: https://connect.comma.ai Obtenha instruções passo a passo exibidas e muito mais com -uma assinatura prime Inscreva-se agora: https://connect.comma.ai +uma assinatura prime. Inscreva-se agora: https://connect.comma.ai No home @@ -502,7 +502,7 @@ trabalho definido Become a comma prime member at connect.comma.ai - Torne-se um membro comma prime em connect.comma.ai + Seja um membro comma prime em connect.comma.ai PRIME FEATURES: @@ -514,11 +514,11 @@ trabalho definido 1 year of storage - 1 ano de armazenamento + 1 ano na nuvem Developer perks - Benefícios para desenvolvedor + Benefícios para devs @@ -835,7 +835,7 @@ trabalho definido Current Version - Versao Atual + Versão Atual Download @@ -863,11 +863,11 @@ trabalho definido UNINSTALL - DESINSTAL + REMOVER Uninstall %1 - Desintalar o %1 + Desinstalar o %1 Are you sure you want to uninstall? @@ -987,7 +987,7 @@ trabalho definido Disengage on Accelerator Pedal - Desacionar Com Pedal Do Acelerador + Desacionar com Pedal do Acelerador When enabled, pressing the accelerator pedal will disengage openpilot. @@ -995,7 +995,7 @@ trabalho definido Show ETA in 24h Format - Mostrar ETA em formato 24h + Mostrar ETA em Formato 24h Use 24h format instead of am/pm From 3efb22e82bb77601fc86db8ba02eafd9cc7ead51 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 20 Jan 2023 11:46:02 -0800 Subject: [PATCH 0678/1179] release pre-commit: test translations (#27017) we should be able to run on the stripped dir now --- .github/workflows/selfdrive_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 7cc45d23b9..a4f7c68573 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -61,7 +61,7 @@ jobs: cp .pylintrc $STRIPPED_DIR cp mypy.ini $STRIPPED_DIR cd $STRIPPED_DIR - ${{ env.RUN }} "SKIP=test_translations pre-commit run --all" + ${{ env.RUN }} "pre-commit run --all" build_all: name: build all From f0d22f88e183c381897a3d48c34bfac63feb63a3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 21 Jan 2023 03:47:29 +0800 Subject: [PATCH 0679/1179] cabana: add a slider to adjust chart range from 1 sec to max cached seconds. (#27005) * add slider to set chart range * set minumu to 1 sec * make chart work in any range * cleanup * rename to max_cached_minitues * more * dont draw out of plotarea * cleanup * updateLayout after chart removed * cleanup * fix clamp * usea same cur_sec to update all charts --- tools/cabana/chartswidget.cc | 187 ++++++++++++--------------- tools/cabana/chartswidget.h | 17 +-- tools/cabana/settings.cc | 29 ++--- tools/cabana/settings.h | 7 +- tools/cabana/streams/livestream.h | 2 +- tools/cabana/streams/replaystream.cc | 4 +- 6 files changed, 110 insertions(+), 136 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 0a855b851b..edca0e4d6a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -2,10 +2,11 @@ #include #include +#include #include -#include #include #include +#include #include #include #include @@ -24,10 +25,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { toolbar->setIconSize({16, 16}); toolbar->addWidget(title_label = new QLabel()); - title_label->setContentsMargins(0 ,0, 12, 0); + title_label->setContentsMargins(0, 0, 12, 0); columns_cb = new QComboBox(this); columns_cb->addItems({"1", "2", "3", "4"}); - columns_cb->setCurrentIndex(std::clamp(settings.chart_column_count - 1, 0, 3)); toolbar->addWidget(new QLabel(tr("Columns:"))); toolbar->addWidget(columns_cb); @@ -35,8 +35,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(stretch_label); - show_all_values_btn = toolbar->addAction(""); - toolbar->addWidget(range_label = new QLabel()); + toolbar->addWidget(new QLabel(tr("Range:"))); + toolbar->addWidget(range_lb = new QLabel(this)); + range_slider = new QSlider(Qt::Horizontal, this); + range_slider->setToolTip(tr("Set the chart range")); + range_slider->setRange(1, settings.max_cached_minutes * 60); + range_slider->setSingleStep(1); + range_slider->setPageStep(60); // 1 min + toolbar->addWidget(range_slider); + + toolbar->addWidget(zoom_range_lb = new QLabel()); reset_zoom_btn = toolbar->addAction(bootstrapPixmap("arrow-counterclockwise"), ""); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); remove_all_btn = toolbar->addAction(bootstrapPixmap("x"), ""); @@ -48,8 +56,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QWidget *charts_container = new QWidget(this); QVBoxLayout *charts_main_layout = new QVBoxLayout(charts_container); charts_main_layout->setContentsMargins(0, 0, 0, 0); - charts_layout = new QGridLayout(charts_container); - charts_main_layout->addLayout(charts_layout); + charts_main_layout->addLayout(charts_layout = new QGridLayout); charts_main_layout->addStretch(0); QScrollArea *charts_scroll = new QScrollArea(this); @@ -58,20 +65,24 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { charts_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); main_layout->addWidget(charts_scroll); - max_chart_range = settings.max_chart_x_range; - use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > - QApplication::style()->standardPalette().color(QPalette::Background).value(); - updateToolBar(); - align_charts_timer = new QTimer(this); align_charts_timer->setSingleShot(true); align_charts_timer->callOnTimeout(this, &ChartsWidget::alignCharts); - column_count = settings.chart_column_count; + + // init settings + use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > + QApplication::style()->standardPalette().color(QPalette::Background).value(); + column_count = std::clamp(settings.chart_column_count, 1, columns_cb->count()); + max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); + display_range = {0, max_chart_range}; + columns_cb->setCurrentIndex(column_count); + range_slider->setValue(max_chart_range); + updateToolBar(); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); - QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::updateState); + QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &AbstractStream::updated, this, &ChartsWidget::updateState); - QObject::connect(show_all_values_btn, &QAction::triggered, this, &ChartsWidget::showAllData); + QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); QObject::connect(columns_cb, SIGNAL(activated(int)), SLOT(setColumnCount(int))); @@ -83,34 +94,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { }); } -void ChartsWidget::updateDisplayRange() { - auto events = can->events(); - double min_event_sec = (events->front()->mono_time / (double)1e9) - can->routeStartTime(); - double max_event_sec = (events->back()->mono_time / (double)1e9) - can->routeStartTime(); - const double cur_sec = can->currentSec(); - if (!can->liveStreaming()) { - auto prev_range = display_range; - if (cur_sec < display_range.first || cur_sec >= (display_range.second - 5)) { - // reached the end, or seeked to a timestamp out of range. - display_range.first = cur_sec - 5; - } - display_range.first = std::floor(std::max(min_event_sec, display_range.first)); - display_range.second = std::floor(std::min(display_range.first + max_chart_range, max_event_sec)); - if (prev_range != display_range) { - QFutureSynchronizer future_synchronizer; - for (auto c : charts) { - future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::setEventsRange, display_range)); - } - } - } else { - if (cur_sec >= (display_range.second - 5)) { - display_range.first = std::floor(std::max(min_event_sec, cur_sec - settings.max_chart_x_range / 2.0)); - } - display_range.second = std::floor(display_range.first + settings.max_chart_x_range); +void ChartsWidget::eventsMerged() { + { + assert(!can->liveStreaming()); + QFutureSynchronizer future_synchronizer; + const auto events = can->events(); for (auto c : charts) { - c->updateSeries(nullptr, events, false); + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr, events, true)); } } + updateState(); } void ChartsWidget::zoomIn(double min, double max) { @@ -128,49 +121,61 @@ void ChartsWidget::zoomReset() { void ChartsWidget::updateState() { if (charts.isEmpty()) return; + if (can->liveStreaming()) { + // appends incoming events to the end of series + const auto events = can->events(); + for (auto c : charts) { + c->updateSeries(nullptr, events, false); + } + } + + const double cur_sec = can->currentSec(); if (!is_zoomed) { - updateDisplayRange(); - } else if (can->currentSec() < zoomed_range.first || can->currentSec() >= zoomed_range.second) { + double pos = (cur_sec - display_range.first) / max_chart_range; + if (pos > 0.8) { + const double min_event_sec = (can->events()->front()->mono_time / (double)1e9) - can->routeStartTime(); + display_range.first = std::floor(std::max(min_event_sec, cur_sec - max_chart_range * 0.2)); + } + display_range.second = std::floor(display_range.first + max_chart_range); + } else if (cur_sec < zoomed_range.first || cur_sec >= zoomed_range.second) { + // loop in zoommed range can->seekTo(zoomed_range.first); } - const auto &range = is_zoomed ? zoomed_range : display_range; setUpdatesEnabled(false); + const auto &range = is_zoomed ? zoomed_range : display_range; for (auto c : charts) { - c->setDisplayRange(range.first, range.second); - c->scene()->invalidate({}, QGraphicsScene::ForegroundLayer); + c->updatePlot(cur_sec, range.first, range.second); } setUpdatesEnabled(true); } -void ChartsWidget::showAllData() { - bool switch_to_show_all = max_chart_range == settings.max_chart_x_range; - max_chart_range = switch_to_show_all ? settings.cached_segment_limit * 60 - : settings.max_chart_x_range; - max_chart_range = std::min(max_chart_range, (uint32_t)can->totalSeconds()); +void ChartsWidget::setMaxChartRange(int value) { + max_chart_range = settings.chart_range = value; + double current_sec = can->currentSec(); + const double min_event_sec = (can->events()->front()->mono_time / (double)1e9) - can->routeStartTime(); + // keep current_sec's pos + double pos = (current_sec - display_range.first) / (display_range.second - display_range.first); + display_range.first = std::floor(std::max(min_event_sec, current_sec - max_chart_range * (1.0 - pos))); + display_range.second = std::floor(display_range.first + max_chart_range); updateToolBar(); updateState(); } void ChartsWidget::updateToolBar() { - int min_range = std::min(settings.max_chart_x_range, (int)can->totalSeconds()); - bool displaying_all = max_chart_range != min_range; - show_all_values_btn->setText(tr("%1 minutes").arg(max_chart_range / 60)); - show_all_values_btn->setToolTip(tr("Click to display %1 data").arg(displaying_all ? tr("%1 minutes").arg(min_range / 60) : tr("ALL cached"))); - show_all_values_btn->setVisible(!is_zoomed && !can->liveStreaming()); - remove_all_btn->setEnabled(!charts.isEmpty()); - reset_zoom_btn->setEnabled(is_zoomed); - range_label->setText(is_zoomed ? tr("%1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); - title_label->setText(charts.size() > 0 ? tr("Charts (%1)").arg(charts.size()) : tr("Charts")); + range_lb->setText(QString(" %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); + zoom_range_lb->setText(is_zoomed ? tr("Zooming: %1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); + title_label->setText(tr("Charts: %1").arg(charts.size())); dock_btn->setIcon(bootstrapPixmap(docking ? "arrow-up-right" : "arrow-down-left")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); + remove_all_btn->setEnabled(!charts.isEmpty()); + reset_zoom_btn->setEnabled(is_zoomed); } void ChartsWidget::settingChanged() { + range_slider->setRange(1, settings.max_cached_minutes * 60); for (auto c : charts) { c->setFixedHeight(settings.chart_height); - columns_cb->setCurrentIndex(std::clamp(settings.chart_column_count - 1, 0, columns_cb->count() - 1)); - setColumnCount(settings.chart_column_count); } } @@ -189,11 +194,8 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo chart = new ChartView(this); chart->setFixedHeight(settings.chart_height); chart->setMinimumWidth(CHART_MIN_WIDTH); - chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + chart->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); - chart->setEventsRange(display_range); - auto range = is_zoomed ? zoomed_range : display_range; - chart->setDisplayRange(range.first, range.second); QObject::connect(chart, &ChartView::remove, [=]() { removeChart(chart); }); QObject::connect(chart, &ChartView::zoomIn, this, &ChartsWidget::zoomIn); QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); @@ -204,6 +206,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo updateLayout(); } chart->addSeries(id, sig); + updateState(); } else if (!show && chart) { chart->removeSeries(id, sig); } @@ -214,7 +217,7 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo void ChartsWidget::setColumnCount(int n) { n = std::clamp(n + 1, 1, columns_cb->count()); if (column_count != n) { - column_count = n; + column_count = settings.chart_column_count = n; updateLayout(); } } @@ -239,6 +242,7 @@ void ChartsWidget::removeChart(ChartView *chart) { chart->deleteLater(); updateToolBar(); alignCharts(); + updateLayout(); emit seriesChanged(); } @@ -440,36 +444,28 @@ void ChartView::updateTitle() { } } -void ChartView::setEventsRange(const std::pair &range) { - if (range != events_range) { - events_range = range; - updateSeries(); - } -} - -void ChartView::setDisplayRange(double min, double max) { +void ChartView::updatePlot(double cur, double min, double max) { + cur_sec = cur; if (min != axis_x->min() || max != axis_x->max()) { axis_x->setRange(min, max); updateAxisY(); } + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } -void ChartView::updateSeries(const Signal *sig, const std::vector *events, bool clear) { - if (!events) events = can->events(); - if (!events || sigs.isEmpty()) return; - +void ChartView::updateSeries(const Signal *sig, const std::vector *events, bool clear) { + events = events ? events : can->events(); for (auto &s : sigs) { if (!sig || s.sig == sig) { if (clear) { s.vals.clear(); + s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz s.last_value_mono_time = 0; } double route_start_time = can->routeStartTime(); - uint64_t begin_ts = can->liveStreaming() ? s.last_value_mono_time : (route_start_time + events_range.first) * 1e9; - Event begin_event(cereal::Event::Which::INIT_DATA, begin_ts); + Event begin_event(cereal::Event::Which::INIT_DATA, s.last_value_mono_time); auto begin = std::upper_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); - uint64_t end_ns = can->liveStreaming() ? events->back()->mono_time : (route_start_time + events_range.second) * 1e9; - for (auto it = begin; it != events->end() && (*it)->mono_time <= end_ns; ++it) { + for (auto it = begin; it != events->end(); ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { if (s.source == c.getSrc() && s.address == c.getAddress()) { @@ -481,13 +477,8 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *event } } } - if (!s.vals.isEmpty()) { - auto [min_v, max_v] = std::minmax_element(s.vals.begin(), s.vals.end(), [](auto &l, auto &r) { return l.y() < r.y(); }); - s.min_y = min_v->y(); - s.max_y = max_v->y(); + if (events->size()) { s.last_value_mono_time = events->back()->mono_time; - } else { - s.min_y = s.max_y = 0; } s.series->replace(s.vals); updateAxisY(); @@ -501,18 +492,11 @@ void ChartView::updateAxisY() { double min_y = std::numeric_limits::max(); double max_y = std::numeric_limits::lowest(); - if (can->liveStreaming() || 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 { - 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; }); - for (auto it = begin; it != s.vals.end() && it->x() <= axis_x->max(); ++it) { - if (it->y() < min_y) min_y = it->y(); - if (it->y() > max_y) max_y = it->y(); - } + 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; }); + for (auto it = begin; it != s.vals.end() && it->x() <= axis_x->max(); ++it) { + if (it->y() < min_y) min_y = it->y(); + if (it->y() > max_y) max_y = it->y(); } } @@ -664,7 +648,8 @@ void ChartView::dropEvent(QDropEvent *event) { } void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { - qreal x = chart()->mapToPosition(QPointF{can->currentSec(), 0}).x(); + qreal x = chart()->mapToPosition(QPointF{cur_sec, 0}).x(); + x = std::clamp(x, chart()->plotArea().left(), chart()->plotArea().right()); qreal y1 = chart()->plotArea().top() - 2; qreal y2 = chart()->plotArea().bottom() + 2; painter->setPen(QPen(chart()->titleBrush().color(), 2)); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 9ba5ce5a30..94218918df 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -1,12 +1,12 @@ #pragma once #include -#include #include #include #include #include #include +#include #include #include #include @@ -26,8 +26,7 @@ public: 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, const std::vector *events = nullptr, bool clear = true); - void setEventsRange(const std::pair &range); - void setDisplayRange(double min, double max); + void updatePlot(double cur, double min, double max); void setPlotAreaLeftPosition(int pos); qreal getYAsixLabelWidth() const; @@ -37,8 +36,6 @@ public: uint32_t address = 0; const Signal *sig = nullptr; QLineSeries *series = nullptr; - double min_y = 0; - double max_y = 0; QVector vals; uint64_t last_value_mono_time = 0; }; @@ -79,8 +76,8 @@ private: QPointF track_pt; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; - std::pair events_range = {0, 0}; QList sigs; + double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; }; @@ -106,21 +103,21 @@ private: void removeChart(ChartView *chart); void eventsMerged(); void updateState(); - void updateDisplayRange(); void zoomIn(double min, double max); void zoomReset(); void updateToolBar(); void removeAll(); - void showAllData(); + void setMaxChartRange(int value); void updateLayout(); void settingChanged(); bool eventFilter(QObject *obj, QEvent *event) override; ChartView *findChart(const QString &id, const Signal *sig); QLabel *title_label; - QLabel *range_label; + QLabel *zoom_range_lb; + QLabel *range_lb; + QSlider *range_slider; bool docking = true; - QAction *show_all_values_btn; QAction *dock_btn; QAction *reset_zoom_btn; QAction *remove_all_btn; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 7a25449c81..8c26b265e0 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -15,9 +15,9 @@ Settings::Settings() { void Settings::save() { QSettings s("settings", QSettings::IniFormat); s.setValue("fps", fps); - s.setValue("cached_segment", cached_segment_limit); + s.setValue("max_cached_minutes", max_cached_minutes); s.setValue("chart_height", chart_height); - s.setValue("max_chart_x_range", max_chart_x_range); + s.setValue("chart_range", chart_range); s.setValue("chart_column_count", chart_column_count); s.setValue("last_dir", last_dir); s.setValue("window_state", window_state); @@ -28,9 +28,9 @@ void Settings::save() { void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); - cached_segment_limit = s.value("cached_segment", 5).toInt(); + max_cached_minutes = s.value("cached_minutes", 5).toInt(); chart_height = s.value("chart_height", 200).toInt(); - max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt(); + chart_range = s.value("chart_range", 3 * 60).toInt(); chart_column_count = s.value("chart_column_count", 1).toInt(); last_dir = s.value("last_dir", QDir::homePath()).toString(); window_state = s.value("window_state").toByteArray(); @@ -50,23 +50,17 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { fps->setValue(settings.fps); form_layout->addRow("FPS", fps); - cached_segment = new QSpinBox(this); - cached_segment->setRange(5, 60); - cached_segment->setSingleStep(1); - cached_segment->setValue(settings.cached_segment_limit); - form_layout->addRow(tr("Cached segments limit"), cached_segment); - - max_chart_x_range = new QSpinBox(this); - max_chart_x_range->setRange(3, 60); - max_chart_x_range->setSingleStep(1); - max_chart_x_range->setValue(settings.max_chart_x_range / 60); - form_layout->addRow(tr("Chart range (minutes)"), max_chart_x_range); + cached_minutes = new QSpinBox(this); + cached_minutes->setRange(5, 60); + cached_minutes->setSingleStep(1); + cached_minutes->setValue(settings.max_cached_minutes); + form_layout->addRow(tr("Max Cached Minutes"), cached_minutes); 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); + form_layout->addRow(tr("Chart Height"), chart_height); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); form_layout->addRow(buttonBox); @@ -78,9 +72,8 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { void SettingsDlg::save() { settings.fps = fps->value(); - settings.cached_segment_limit = cached_segment->value(); + settings.max_cached_minutes = cached_minutes->value(); settings.chart_height = chart_height->value(); - settings.max_chart_x_range = max_chart_x_range->value() * 60; settings.save(); accept(); emit settings.changed(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index ed0ba3a549..86ebd73113 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -14,10 +14,10 @@ public: void load(); int fps = 10; - int cached_segment_limit = 5; + int max_cached_minutes = 5; int chart_height = 200; int chart_column_count = 1; - int max_chart_x_range = 3 * 60; // 3 minutes + int chart_range = 3 * 60; // e minutes QString last_dir; QByteArray geometry; QByteArray video_splitter_state; @@ -34,9 +34,8 @@ public: SettingsDlg(QWidget *parent); void save(); QSpinBox *fps; - QSpinBox *cached_segment; + QSpinBox *cached_minutes; QSpinBox *chart_height; - QSpinBox *max_chart_x_range; }; extern Settings settings; diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 17301d48e7..95c6e3811c 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -17,7 +17,7 @@ public: protected: void streamThread(); - void updateCachedNS() { cache_ns = (settings.cached_segment_limit * 60) * 1e9; } + void updateCachedNS() { cache_ns = (settings.max_cached_minutes * 60) * 1e9; } mutable std::mutex lock; mutable std::vector events_vector; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 97a3911adf..fd58f7a409 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -4,7 +4,7 @@ ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent, false) { QObject::connect(&settings, &Settings::changed, [this]() { - if (replay) replay->setSegmentCacheLimit(settings.cached_segment_limit); + if (replay) replay->setSegmentCacheLimit(settings.max_cached_minutes); }); } @@ -18,7 +18,7 @@ static bool event_filter(const Event *e, void *opaque) { bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); - replay->setSegmentCacheLimit(settings.cached_segment_limit); + replay->setSegmentCacheLimit(settings.max_cached_minutes); replay->installEventFilter(event_filter, this); QObject::connect(replay, &Replay::seekedTo, this, &AbstractStream::seekedTo); QObject::connect(replay, &Replay::segmentsMerged, this, &AbstractStream::eventsMerged); From c88853afaeab9c9ccf7f7c693c69d9d3e77ae6ac Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 21 Jan 2023 04:45:47 +0800 Subject: [PATCH 0680/1179] cabana: fix wrong column count displayed in combobox (#27020) fix wrong column count displayed in combobox --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index edca0e4d6a..d80ab7a2a0 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -75,7 +75,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { column_count = std::clamp(settings.chart_column_count, 1, columns_cb->count()); max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); display_range = {0, max_chart_range}; - columns_cb->setCurrentIndex(column_count); + columns_cb->setCurrentIndex(column_count - 1); range_slider->setValue(max_chart_range); updateToolBar(); From b8ec32103a4fab1ede5fc431eabc23118da82856 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 20 Jan 2023 13:03:02 -0800 Subject: [PATCH 0681/1179] boardd: include SPI panda in list (#27018) * boardd: include SPI panda in list * hexlify * fix hexlify * cleanup * little more Co-authored-by: Comma Device --- selfdrive/boardd/panda.cc | 23 ++++++++++++++++++++++- selfdrive/boardd/panda_comms.h | 5 ++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index d4d53aa230..b12b26fb62 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include "cereal/messaging/messaging.h" #include "common/swaglog.h" @@ -40,7 +42,26 @@ bool Panda::comms_healthy() { } std::vector Panda::list() { - return PandaUsbHandle::list(); + std::vector serials = PandaUsbHandle::list(); + + // check SPI + const int uid_len = 12; + uint8_t uid[uid_len] = {0}; + PandaSpiHandle spi_handle("/dev/spidev0.0"); + int ret = spi_handle.control_read(0xc3, 0, 0, uid, uid_len); + if (ret == uid_len) { + std::stringstream stream; + for (int i = 0; i < uid_len; i++) { + stream << std::hex << std::setw(2) << std::setfill('0') << int(uid[i]); + } + + // might be on USB too + if (std::find(serials.begin(), serials.end(), stream.str()) == serials.end()) { + serials.push_back(stream.str()); + } + } + + return serials; } void Panda::set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param) { diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index bd262dfa0e..9d1f69e671 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -30,9 +30,6 @@ public: virtual int control_read(uint8_t request, uint16_t param1, uint16_t param2, unsigned char *data, uint16_t length, unsigned int timeout=TIMEOUT) = 0; virtual int bulk_write(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; virtual int bulk_read(unsigned char endpoint, unsigned char* data, int length, unsigned int timeout=TIMEOUT) = 0; - -protected: - std::recursive_mutex hw_lock; }; class PandaUsbHandle : public PandaCommsHandle { @@ -50,6 +47,7 @@ public: private: libusb_context *ctx = NULL; libusb_device_handle *dev_handle = NULL; + std::recursive_mutex hw_lock; void handle_usb_issue(int err, const char func[]); }; @@ -69,6 +67,7 @@ private: int spi_fd = -1; uint8_t tx_buf[SPI_BUF_SIZE]; uint8_t rx_buf[SPI_BUF_SIZE]; + inline static std::recursive_mutex hw_lock; int wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack); int bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t rx_len); From 75fd2e119946d2e5a850f924b5f33945435cad3f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 20 Jan 2023 13:11:51 -0800 Subject: [PATCH 0682/1179] skip lupdate on device --- selfdrive/ui/SConscript | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 0f28f5ccc3..2fb7227f63 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -74,12 +74,13 @@ translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.v translation_targets = [src.replace(".ts", ".qm") for src in translation_sources] lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease' -lupdate = qt_env.Command(translation_sources, qt_src, "selfdrive/ui/update_translations.py") lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES") -qt_env.Depends(lrelease, lupdate) -qt_env.NoClean(translation_sources) -qt_env.Precious(translation_sources) -qt_env.NoCache(lupdate) +if arch != 'larch64': + lupdate = qt_env.Command(translation_sources, qt_src, "selfdrive/ui/update_translations.py") + qt_env.Depends(lrelease, lupdate) + qt_env.NoClean(translation_sources) + qt_env.Precious(translation_sources) + qt_env.NoCache(lupdate) # setup and factory resetter if GetOption('extras'): From e883976a32a4190123d891f51cc567dfd77e6c85 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 20 Jan 2023 14:11:43 -0800 Subject: [PATCH 0683/1179] set path for extra qt bins on device (#27022) * set path for extra qt bins on device * no print Co-authored-by: Comma Device --- SConstruct | 1 + selfdrive/ui/SConscript | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/SConstruct b/SConstruct index 8864164f15..31aa6ecced 100644 --- a/SConstruct +++ b/SConstruct @@ -311,6 +311,7 @@ else: qt_libs = [f"Qt5{m}" for m in qt_modules] if arch == "larch64": qt_libs += ["GLESv2", "wayland-client"] + qt_env.PrependENVPath('PATH', Dir("#third_party/qt5/larch64/bin/").abspath) elif arch != "Darwin": qt_libs += ["GL"] diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 2fb7227f63..0f28f5ccc3 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -74,13 +74,12 @@ translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.v translation_targets = [src.replace(".ts", ".qm") for src in translation_sources] lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease' +lupdate = qt_env.Command(translation_sources, qt_src, "selfdrive/ui/update_translations.py") lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES") -if arch != 'larch64': - lupdate = qt_env.Command(translation_sources, qt_src, "selfdrive/ui/update_translations.py") - qt_env.Depends(lrelease, lupdate) - qt_env.NoClean(translation_sources) - qt_env.Precious(translation_sources) - qt_env.NoCache(lupdate) +qt_env.Depends(lrelease, lupdate) +qt_env.NoClean(translation_sources) +qt_env.Precious(translation_sources) +qt_env.NoCache(lupdate) # setup and factory resetter if GetOption('extras'): From e507830a1c21490701d53093777bd2b5727202ca Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Fri, 20 Jan 2023 20:28:48 -0300 Subject: [PATCH 0684/1179] Multilang: new pt-BR translations (#27021) * improve pt-BR translations * update pt-BR translation Co-authored-by: Shane Smiskol --- selfdrive/ui/translations/main_pt-BR.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 92bb552d3d..445de72fc3 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -1047,11 +1047,11 @@ trabalho definido openpilot longitudinal control may come in a future update. - + O controle longitudinal openpilot pode vir em uma atualização futura. An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - + Uma versão experimental do controle longitudinal openpilot pode ser testada, juntamente com o modo Experimental, em branches de desenvolvimento. Enable experimental longitudinal control to allow Experimental mode. From fa6e6a4eb52010466efb5a65d3b9ee7b59e86a58 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 21 Jan 2023 07:43:42 +0800 Subject: [PATCH 0685/1179] cabana: add no-vipc flag (#26999) --- tools/cabana/cabana.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index ce0cb443cb..fc6c37fb72 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -22,6 +22,7 @@ int main(int argc, char *argv[]) { cmd_parser.addOption({"stream", "read can messages from live streaming"}); cmd_parser.addOption({"zmq", "the ip address on which to receive zmq messages", "zmq"}); cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"}); + cmd_parser.addOption({"no-vipc", "do not output video"}); cmd_parser.process(app); const QStringList args = cmd_parser.positionalArguments(); if (args.empty() && !cmd_parser.isSet("demo") && !cmd_parser.isSet("stream")) { @@ -44,6 +45,8 @@ int main(int argc, char *argv[]) { replay_flags |= REPLAY_FLAG_ECAM; } else if (cmd_parser.isSet("qcam")) { replay_flags |= REPLAY_FLAG_QCAMERA; + } else if (cmd_parser.isSet("no-vipc")) { + replay_flags |= REPLAY_FLAG_NO_VIPC; } auto replay_stream = new ReplayStream(&app); stream.reset(replay_stream); From e710dc1b7ed5fb3c30263bd81e844a03e0889049 Mon Sep 17 00:00:00 2001 From: Comma Device Date: Fri, 20 Jan 2023 21:07:01 -0600 Subject: [PATCH 0686/1179] lower spi log level --- selfdrive/boardd/spi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 8a6bf8be7f..2779494ae4 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -214,7 +214,7 @@ int PandaSpiHandle::wait_for_ack(spi_ioc_transfer &transfer, uint8_t ack) { // handle timeout if (millis_since_boot() - start_millis > SPI_ACK_TIMEOUT) { - LOGE("SPI: timed out waiting for ACK"); + LOGD("SPI: timed out waiting for ACK"); return -1; } } From 027c27cd690120d8ff8823f0b53cc2c9d6af7df3 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 20 Jan 2023 23:19:01 -0700 Subject: [PATCH 0687/1179] Laikad: add test (#27028) * add laikad tropo test Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/test/test_laikad.py | 34 +++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 6059eab68f..d89f521228 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -22,7 +22,24 @@ def get_log(segs=range(0)): logs = [] for i in segs: logs.extend(LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", i))) - return [m for m in logs if m.which() == 'ubloxGnss'] + + all_logs = [m for m in logs if m.which() == 'ubloxGnss'] + low_gnss = [] + for m in all_logs: + if m.ubloxGnss.which() != 'measurementReport': + continue + + MAX_MEAS = 7 + if m.ubloxGnss.measurementReport.numMeas > MAX_MEAS: + mb = m.as_builder() + mb.ubloxGnss.measurementReport.numMeas = MAX_MEAS + mb.ubloxGnss.measurementReport.measurements = list(m.ubloxGnss.measurementReport.measurements)[:MAX_MEAS] + mb.ubloxGnss.measurementReport.measurements[0].pseudorange += 1000 + low_gnss.append(mb.as_reader()) + else: + low_gnss.append(m) + + return all_logs, low_gnss def verify_messages(lr, laikad, return_one_success=False): @@ -59,8 +76,9 @@ class TestLaikad(unittest.TestCase): @classmethod def setUpClass(cls): - logs = get_log(range(1)) + logs, low_gnss = get_log(range(1)) cls.logs = logs + cls.low_gnss = low_gnss first_gps_time = get_first_gps_time(logs) cls.first_gps_time = first_gps_time @@ -254,6 +272,18 @@ class TestLaikad(unittest.TestCase): # Verify orbit data is not downloaded mock_method.assert_not_called() + def test_low_gnss_meas(self): + cnt = 0 + laikad = Laikad() + for m in self.low_gnss: + msg = laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=True) + if msg is None: + continue + gm = msg.gnssMeasurements + if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: + cnt += 1 + self.assertEqual(cnt, 554) + def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) From 945d0c7696e79fd1889743f112d68060c0b67650 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 22 Jan 2023 04:41:55 +0800 Subject: [PATCH 0688/1179] cabana: new chart on top (#27031) --- tools/cabana/chartswidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index d80ab7a2a0..a9b1d66fb9 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -224,11 +224,11 @@ void ChartsWidget::setColumnCount(int n) { void ChartsWidget::updateLayout() { int n = column_count; - for (; n >= 1; --n) { + for (; n > 1; --n) { if ((n * (CHART_MIN_WIDTH + charts_layout->spacing())) < rect().width()) break; } for (int i = 0; i < charts.size(); ++i) { - charts_layout->addWidget(charts[i], i / n, i % n); + charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); } } From 51cb45e7a88d1f0cf908292df2438c23df35d523 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Sat, 21 Jan 2023 16:07:58 -0500 Subject: [PATCH 0689/1179] VW MQB: Add FW for 2015 Volkswagen Passat (#27032) --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 6ae4969cc0..51161f2972 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -568,6 +568,7 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8703N906026E \xf1\x892114', b'\xf1\x8704E906023AH\xf1\x893379', + b'\xf1\x8704L906026DP\xf1\x891538', b'\xf1\x8704L906026ET\xf1\x891990', b'\xf1\x8704L906026FP\xf1\x892012', b'\xf1\x8704L906026GA\xf1\x892013', @@ -586,6 +587,7 @@ FW_VERSIONS = { ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AE\xf1\x890195\xf1\x82\r56140056130012416612124111', + b'\xf1\x873Q0959655AF\xf1\x890195\xf1\x82\r56140056130012026612120211', b'\xf1\x873Q0959655AN\xf1\x890306\xf1\x82\r58160058140013036914110311', b'\xf1\x873Q0959655BA\xf1\x890195\xf1\x82\r56140056130012516612125111', b'\xf1\x873Q0959655BB\xf1\x890195\xf1\x82\r56140056130012026612120211', @@ -596,6 +598,7 @@ FW_VERSIONS = { (Ecu.eps, 0x712, None): [ b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00611A1', b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\x0566B00711A1', + b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820514B0060703', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0060803', b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820522B0080803', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521B00606A1', @@ -604,6 +607,7 @@ FW_VERSIONS = { b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567B0020600', ], (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x873Q0907572A \xf1\x890126', b'\xf1\x873Q0907572A \xf1\x890130', b'\xf1\x873Q0907572B \xf1\x890192', b'\xf1\x873Q0907572C \xf1\x890195', From 35a943030ba67b89a13bdf95257e0b349ffb0ef7 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 22 Jan 2023 08:00:39 +0800 Subject: [PATCH 0690/1179] cabana: add new plot btn to create chart (#27023) --- tools/cabana/chartswidget.cc | 48 ++++++++++++++++++++++++------------ tools/cabana/chartswidget.h | 4 ++- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index a9b1d66fb9..ca52e44474 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -24,6 +24,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QToolBar *toolbar = new QToolBar(tr("Charts"), this); toolbar->setIconSize({16, 16}); + QAction *new_plot_btn = toolbar->addAction(bootstrapPixmap("file-plus"), ""); + new_plot_btn->setToolTip(tr("New Plot")); toolbar->addWidget(title_label = new QLabel()); title_label->setContentsMargins(0, 0, 12, 0); columns_cb = new QComboBox(this); @@ -83,6 +85,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &AbstractStream::updated, this, &ChartsWidget::updateState); QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); + QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); QObject::connect(columns_cb, SIGNAL(activated(int)), SLOT(setColumnCount(int))); @@ -185,26 +188,28 @@ ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { return nullptr; } +ChartView *ChartsWidget::createChart() { + auto chart = new ChartView(this); + chart->setFixedHeight(settings.chart_height); + chart->setMinimumWidth(CHART_MIN_WIDTH); + chart->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); + 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::seriesChanged); + QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); + QObject::connect(chart, &ChartView::axisYUpdated, [this]() { align_charts_timer->start(100); }); + charts.push_back(chart); + updateLayout(); + return chart; +} + void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bool merge) { setUpdatesEnabled(false); ChartView *chart = findChart(id, sig); if (show && !chart) { - chart = merge && charts.size() > 0 ? charts.back() : nullptr; - if (!chart) { - chart = new ChartView(this); - chart->setFixedHeight(settings.chart_height); - chart->setMinimumWidth(CHART_MIN_WIDTH); - chart->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); - 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::seriesChanged); - QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); - QObject::connect(chart, &ChartView::axisYUpdated, [this]() { align_charts_timer->start(100); }); - charts.push_back(chart); - updateLayout(); - } + chart = merge && charts.size() > 0 ? charts.back() : createChart(); chart->addSeries(id, sig); updateState(); } else if (!show && chart) { @@ -237,6 +242,17 @@ void ChartsWidget::resizeEvent(QResizeEvent *event) { updateLayout(); } +void ChartsWidget::newChart() { + SeriesSelector dlg(this); + if (dlg.exec() == QDialog::Accepted) { + QList series_list = dlg.series(); + if (!series_list.isEmpty()) { + auto c = createChart(); + c->addSeries(series_list); + } + } +} + void ChartsWidget::removeChart(ChartView *chart) { charts.removeOne(chart); chart->deleteLater(); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 94218918df..f134136323 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -23,6 +23,7 @@ class ChartView : public QChartView { public: ChartView(QWidget *parent = nullptr); void addSeries(const QString &msg_id, const Signal *sig); + void addSeries(const QList &series_list); 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, const std::vector *events = nullptr, bool clear = true); @@ -69,7 +70,6 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; void applyNiceNumbers(qreal min, qreal max); qreal niceNumber(qreal x, bool ceiling); - void addSeries(const QList &series_list); QValueAxis *axis_x; QValueAxis *axis_y; @@ -100,6 +100,8 @@ signals: private: void resizeEvent(QResizeEvent *event) override; void alignCharts(); + void newChart(); + ChartView * createChart(); void removeChart(ChartView *chart); void eventsMerged(); void updateState(); From d7bcbfd54bd4a2ba34423222557181ff50d55134 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 21 Jan 2023 17:28:56 -0800 Subject: [PATCH 0691/1179] rawgpsd: enable gps power (#27034) --- selfdrive/sensord/rawgps/rawgpsd.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/sensord/rawgps/rawgpsd.py b/selfdrive/sensord/rawgps/rawgpsd.py index 1c65051665..3fa5e927a2 100755 --- a/selfdrive/sensord/rawgps/rawgpsd.py +++ b/selfdrive/sensord/rawgps/rawgpsd.py @@ -11,7 +11,9 @@ from struct import unpack_from, calcsize, pack from cereal import log import cereal.messaging as messaging +from common.gpio import gpio_init, gpio_set from laika.gps_time import GPSTime +from system.hardware.tici.pins import GPIO from system.swaglog import cloudlog from selfdrive.sensord.rawgps.modemdiag import ModemDiag, DIAG_LOG_F, setup_logs, send_recv from selfdrive.sensord.rawgps.structs import (dict_unpacker, position_report, relist, @@ -182,6 +184,7 @@ def main() -> NoReturn: def cleanup(sig, frame): cloudlog.warning(f"caught sig {sig}, disabling quectel gps") + gpio_set(GPIO.UBLOX_PWR_EN, False) teardown_quectel(diag) cloudlog.warning("quectel cleanup done") sys.exit(0) @@ -190,6 +193,8 @@ def main() -> NoReturn: setup_quectel(diag) cloudlog.warning("quectel setup done") + gpio_init(GPIO.UBLOX_PWR_EN, True) + gpio_set(GPIO.UBLOX_PWR_EN, True) pm = messaging.PubMaster(['qcomGnss', 'gpsLocation']) From 66ff2de0a29438c80e8834ac78a696ca21b30601 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 21 Jan 2023 19:42:10 -0800 Subject: [PATCH 0692/1179] boardd: connect to SPI panda by UID (#27035) * move list * connect by serial * cleanup hw serial * little more * rm excessive print Co-authored-by: Comma Device --- selfdrive/boardd/boardd.cc | 4 +-- selfdrive/boardd/panda.cc | 31 ++++++++------------ selfdrive/boardd/panda.h | 2 +- selfdrive/boardd/panda_comms.cc | 2 +- selfdrive/boardd/panda_comms.h | 1 + selfdrive/boardd/spi.cc | 50 +++++++++++++++++++++++++-------- 6 files changed, 54 insertions(+), 36 deletions(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index e626882191..bc454aa54e 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -225,9 +225,9 @@ void can_send_thread(std::vector pandas, bool fake_send) { //Dont send if older than 1 second if ((nanos_since_boot() - event.getLogMonoTime() < 1e9) && !fake_send) { for (const auto& panda : pandas) { - LOGT("sending sendcan to panda: %s", (panda->hw_serial).c_str()); + LOGT("sending sendcan to panda: %s", (panda->hw_serial()).c_str()); panda->can_send(event.getSendcan()); - LOGT("sendcan sent to panda: %s", (panda->hw_serial).c_str()); + LOGT("sendcan sent to panda: %s", (panda->hw_serial()).c_str()); } } } diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index b12b26fb62..600a46c809 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -3,20 +3,18 @@ #include #include -#include #include -#include #include "cereal/messaging/messaging.h" #include "common/swaglog.h" #include "common/util.h" Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { - // TODO: support SPI here one day... - if (serial.find("spi") != std::string::npos) { - handle = std::make_unique(serial); - } else { + // try USB first, then SPI + try { handle = std::make_unique(serial); + } catch (std::exception &e) { + handle = std::make_unique(serial); } hw_type = get_hw_type(); @@ -41,23 +39,16 @@ bool Panda::comms_healthy() { return handle->comms_healthy; } +std::string Panda::hw_serial() { + return handle->hw_serial; +} + std::vector Panda::list() { std::vector serials = PandaUsbHandle::list(); - // check SPI - const int uid_len = 12; - uint8_t uid[uid_len] = {0}; - PandaSpiHandle spi_handle("/dev/spidev0.0"); - int ret = spi_handle.control_read(0xc3, 0, 0, uid, uid_len); - if (ret == uid_len) { - std::stringstream stream; - for (int i = 0; i < uid_len; i++) { - stream << std::hex << std::setw(2) << std::setfill('0') << int(uid[i]); - } - - // might be on USB too - if (std::find(serials.begin(), serials.end(), stream.str()) == serials.end()) { - serials.push_back(stream.str()); + for (auto s : PandaSpiHandle::list()) { + if (std::find(serials.begin(), serials.end(), s) == serials.end()) { + serials.push_back(s); } } diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index 156efe7ef3..69df2e2b66 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -48,13 +48,13 @@ private: public: Panda(std::string serial="", uint32_t bus_offset=0); - std::string hw_serial; cereal::PandaState::PandaType hw_type = cereal::PandaState::PandaType::UNKNOWN; bool has_rtc = false; const uint32_t bus_offset; bool connected(); bool comms_healthy(); + std::string hw_serial(); // Static functions static std::vector list(); diff --git a/selfdrive/boardd/panda_comms.cc b/selfdrive/boardd/panda_comms.cc index e73cb69318..120d2f67d5 100644 --- a/selfdrive/boardd/panda_comms.cc +++ b/selfdrive/boardd/panda_comms.cc @@ -44,7 +44,7 @@ PandaUsbHandle::PandaUsbHandle(std::string serial) : PandaCommsHandle(serial) { ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber, desc_serial, std::size(desc_serial)); if (ret < 0) { goto fail; } - auto hw_serial = std::string((char *)desc_serial, ret); + hw_serial = std::string((char *)desc_serial, ret); if (serial.empty() || serial == hw_serial) { break; } diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index 9d1f69e671..b669d77e7f 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -21,6 +21,7 @@ public: virtual ~PandaCommsHandle() {}; virtual void cleanup() = 0; + std::string hw_serial; std::atomic connected = true; std::atomic comms_healthy = true; static std::vector list(); diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index 2779494ae4..bcc446b050 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "common/util.h" #include "common/timing.h" @@ -28,6 +30,7 @@ struct __attribute__((packed)) spi_header { const int SPI_MAX_RETRIES = 5; const int SPI_ACK_TIMEOUT = 50; // milliseconds +const std::string SPI_DEVICE = "/dev/spidev0.0"; class LockEx { public: @@ -48,38 +51,56 @@ private: PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) { - LOGD("opening SPI panda: %s", serial.c_str()); + int ret; + const int uid_len = 12; + uint8_t uid[uid_len] = {0}; - int err; uint32_t spi_mode = SPI_MODE_0; uint32_t spi_speed = 30000000; uint8_t spi_bits_per_word = 8; - spi_fd = open(serial.c_str(), O_RDWR); + spi_fd = open(SPI_DEVICE.c_str(), O_RDWR); if (spi_fd < 0) { - LOGE("failed opening SPI device %d", err); + LOGE("failed opening SPI device %d", spi_fd); goto fail; } // SPI settings - err = util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode); - if (err < 0) { - LOGE("failed setting SPI mode %d", err); + ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode); + if (ret < 0) { + LOGE("failed setting SPI mode %d", ret); goto fail; } - err = util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); - if (err < 0) { + ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); + if (ret < 0) { LOGE("failed setting SPI speed"); goto fail; } - err = util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word); - if (err < 0) { + ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word); + if (ret < 0) { LOGE("failed setting SPI bits per word"); goto fail; } + // get hw UID/serial + ret = control_read(0xc3, 0, 0, uid, uid_len); + if (ret == uid_len) { + std::stringstream stream; + for (int i = 0; i < uid_len; i++) { + stream << std::hex << std::setw(2) << std::setfill('0') << int(uid[i]); + } + hw_serial = stream.str(); + } else { + LOGD("failed to get serial %d", ret); + goto fail; + } + + if (!serial.empty() && (serial != hw_serial)) { + goto fail; + } + return; fail: @@ -163,7 +184,12 @@ int PandaSpiHandle::bulk_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t t } std::vector PandaSpiHandle::list() { - // TODO: list all pandas available over SPI + try { + PandaSpiHandle sh(""); + return {sh.hw_serial}; + } catch (std::exception &e) { + // no panda on SPI + } return {}; } From 3018d1c8ff93c15edf37aa8ab8c745438133b200 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 21 Jan 2023 19:43:38 -0800 Subject: [PATCH 0693/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index e83b2189c1..4750449f3c 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e83b2189c148499b8ba430433886791217f3389a +Subproject commit 4750449f3cc41e2dc8141b4818025c5c538dad17 From 1e4721ad62d8953ed2e55ebcb4c02d7e06d393df Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 23 Jan 2023 05:20:20 +0800 Subject: [PATCH 0694/1179] cabana: fix memory corruption in live stream (#27037) --- tools/cabana/streams/livestream.cc | 33 ++++++++++++++++++++---------- tools/cabana/streams/livestream.h | 5 +++-- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index bc5b811f44..b0af9f3281 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -4,8 +4,11 @@ LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), if (!zmq_address.isEmpty()) { setenv("ZMQ", "1", 1); } - updateCachedNS(); - QObject::connect(&settings, &Settings::changed, this, &LiveStream::updateCachedNS); + + timer = new QTimer(this); + timer->callOnTimeout(this, &LiveStream::removeExpiredEvents); + timer->start(3 * 1000); + stream_thread = new QThread(this); QObject::connect(stream_thread, &QThread::started, [=]() { streamThread(); }); QObject::connect(stream_thread, &QThread::finished, stream_thread, &QThread::deleteLater); @@ -37,23 +40,17 @@ void LiveStream::streamThread() { AlignedBuffer *buf = messages.emplace_back(new AlignedBuffer()); Event *evt = ::new Event(buf->align(msg)); delete msg; - { std::lock_guard lk(lock); can_events.push_back(evt); - if ((evt->mono_time - can_events.front()->mono_time) > cache_ns) { - ::delete can_events.front(); - delete messages.front(); - can_events.pop_front(); - messages.pop_front(); - } } + if (start_ts == 0) { start_ts = evt->mono_time; emit streamStarted(); } current_ts = evt->mono_time; - if (start_ts > current_ts) { + if (current_ts < start_ts) { qDebug() << "stream is looping back to old time stamp"; start_ts = current_ts.load(); } @@ -62,9 +59,23 @@ void LiveStream::streamThread() { } } -const std::vector *LiveStream::events() const { +void LiveStream::removeExpiredEvents() { std::lock_guard lk(lock); + if (can_events.size() > 0) { + const uint64_t max_ns = settings.max_cached_minutes * 60 * 1e9; + const uint64_t last_ns = can_events.back()->mono_time; + while (!can_events.empty() && (last_ns - can_events.front()->mono_time) > max_ns) { + ::delete can_events.front(); + delete messages.front(); + can_events.pop_front(); + messages.pop_front(); + } + } +} + +const std::vector *LiveStream::events() const { events_vector.clear(); + std::lock_guard lk(lock); events_vector.reserve(can_events.size()); std::copy(can_events.begin(), can_events.end(), std::back_inserter(events_vector)); return &events_vector; diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 95c6e3811c..db1638d761 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -1,5 +1,6 @@ #pragma once +#include #include "tools/cabana/streams/abstractstream.h" class LiveStream : public AbstractStream { @@ -17,7 +18,7 @@ public: protected: void streamThread(); - void updateCachedNS() { cache_ns = (settings.max_cached_minutes * 60) * 1e9; } + void removeExpiredEvents(); mutable std::mutex lock; mutable std::vector events_vector; @@ -25,7 +26,7 @@ protected: std::deque messages; std::atomic start_ts = 0; std::atomic current_ts = 0; - std::atomic cache_ns = 0; const QString zmq_address; QThread *stream_thread; + QTimer *timer; }; From a0f91b0a8b1f9e8d14adfb32691c8dec66807d13 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 23 Jan 2023 05:20:40 +0800 Subject: [PATCH 0695/1179] cabana: fix chart range not updated when replay is seeking back. (#27036) --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index ca52e44474..2965ae0476 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -135,7 +135,7 @@ void ChartsWidget::updateState() { const double cur_sec = can->currentSec(); if (!is_zoomed) { double pos = (cur_sec - display_range.first) / max_chart_range; - if (pos > 0.8) { + if (pos < 0 || pos > 0.8) { const double min_event_sec = (can->events()->front()->mono_time / (double)1e9) - can->routeStartTime(); display_range.first = std::floor(std::max(min_event_sec, cur_sec - max_chart_range * 0.2)); } From 42937056481be5959664d00c8dd0a78220574695 Mon Sep 17 00:00:00 2001 From: Comma Device Date: Sun, 22 Jan 2023 16:26:55 -0600 Subject: [PATCH 0696/1179] test manager: use ensure_running to start relevant procs --- selfdrive/manager/process.py | 6 +++++- selfdrive/manager/test/test_manager.py | 27 +++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/selfdrive/manager/process.py b/selfdrive/manager/process.py index dabfbe4ee0..ce18073d9b 100644 --- a/selfdrive/manager/process.py +++ b/selfdrive/manager/process.py @@ -290,10 +290,11 @@ class DaemonProcess(ManagerProcess): def ensure_running(procs: ValuesView[ManagerProcess], started: bool, params=None, CP: car.CarParams=None, - not_run: Optional[List[str]]=None) -> None: + not_run: Optional[List[str]]=None) -> List[ManagerProcess]: if not_run is None: not_run = [] + running = [] for p in procs: # Conditions that make a process run run = any(( @@ -311,7 +312,10 @@ def ensure_running(procs: ValuesView[ManagerProcess], started: bool, params=None if run: p.start() + running.append(p) else: p.stop(block=False) p.check_watchdog(started) + + return running diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index 6d4df0423a..8712c9478e 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -4,17 +4,17 @@ import signal import time import unittest +from cereal import car from common.params import Params import selfdrive.manager.manager as manager -from selfdrive.manager.process import DaemonProcess +from selfdrive.manager.process import ensure_running, DaemonProcess from selfdrive.manager.process_config import managed_processes from system.hardware import HARDWARE os.environ['FAKEUPLOAD'] = "1" MAX_STARTUP_TIME = 3 -ALL_PROCESSES = [p.name for p in managed_processes.values() if (type(p) is not DaemonProcess) and p.enabled and (p.name not in ['pandad', ])] - +BLACKLIST_PROCS = ['manage_athenad', 'pandad', 'pigeond'] class TestManager(unittest.TestCase): def setUp(self): @@ -47,24 +47,25 @@ class TestManager(unittest.TestCase): HARDWARE.set_power_save(False) manager.manager_init() manager.manager_prepare() - for p in ALL_PROCESSES: - managed_processes[p].start() + + CP = car.CarParams.new_message() + procs = ensure_running(managed_processes.values(), True, Params(), CP, not_run=BLACKLIST_PROCS) time.sleep(10) - for p in reversed(ALL_PROCESSES): - with self.subTest(proc=p): - state = managed_processes[p].get_process_state_msg() - self.assertTrue(state.running, f"{p} not running") - exit_code = managed_processes[p].stop(retry=False) + for p in procs: + with self.subTest(proc=p.name): + state = p.get_process_state_msg() + self.assertTrue(state.running, f"{p.name} not running") + exit_code = p.stop(retry=False) - self.assertTrue(exit_code is not None, f"{p} failed to exit") + self.assertTrue(exit_code is not None, f"{p.name} failed to exit") # TODO: interrupted blocking read exits with 1 in cereal. use a more unique return code exit_codes = [0, 1] - if managed_processes[p].sigkill: + if p.sigkill: exit_codes = [-signal.SIGKILL] - self.assertIn(exit_code, exit_codes, f"{p} died with {exit_code}") + self.assertIn(exit_code, exit_codes, f"{p.name} died with {exit_code}") if __name__ == "__main__": From 100fe10c7c326f3d22685ca8a0ebb486c57c85cf Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 22 Jan 2023 15:08:36 -0800 Subject: [PATCH 0697/1179] jenkins: tmp disable sim test due to ZMQ bug (#27043) --- Jenkinsfile | 2 ++ selfdrive/manager/test/test_manager.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index bd138bed76..1841c68bba 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -81,6 +81,7 @@ pipeline { parallel { + /* stage('simulator') { agent { dockerfile { @@ -108,6 +109,7 @@ pipeline { } } } + */ stage('build') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } diff --git a/selfdrive/manager/test/test_manager.py b/selfdrive/manager/test/test_manager.py index 8712c9478e..889ab3d279 100755 --- a/selfdrive/manager/test/test_manager.py +++ b/selfdrive/manager/test/test_manager.py @@ -7,7 +7,7 @@ import unittest from cereal import car from common.params import Params import selfdrive.manager.manager as manager -from selfdrive.manager.process import ensure_running, DaemonProcess +from selfdrive.manager.process import ensure_running from selfdrive.manager.process_config import managed_processes from system.hardware import HARDWARE From f5d253764cc3219fae26361af07bf5de9bf94b0a Mon Sep 17 00:00:00 2001 From: "Michael G. Inso" <68110223+MiChaelinzo@users.noreply.github.com> Date: Mon, 23 Jan 2023 20:49:48 +0300 Subject: [PATCH 0698/1179] Update cell.sh (#27055) You can combine the two nmcli commands into a single command by specifying both ipv4 and ipv6 options at the same time. You can use the nmcli command with the --wait option to wait for the connection to be fully established before exiting. You can use nmcli command with the --ask option to prompt the user to confirm the action before proceeding. --- scripts/cell.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/cell.sh b/scripts/cell.sh index cae701eccc..3623fe5b16 100755 --- a/scripts/cell.sh +++ b/scripts/cell.sh @@ -1,5 +1,3 @@ #!/usr/bin/bash - -nmcli connection modify --temporary lte ipv4.route-metric 1 -nmcli connection modify --temporary lte ipv6.route-metric 1 -nmcli con up lte +nmcli connection modify --temporary lte ipv4.route-metric 1 ipv6.route-metric 1 +nmcli con up --wait --ask lte From e49c7fa2bf3bbc2eb6aa851c51d82f1cfd6b9212 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 24 Jan 2023 02:16:11 +0800 Subject: [PATCH 0699/1179] cabana: fix slider crash on exit if loadThumbnails is running (#27052) --- tools/cabana/videowidget.cc | 5 +++++ tools/cabana/videowidget.h | 1 + 2 files changed, 6 insertions(+) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 7d46769a47..729302adaa 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -133,6 +133,11 @@ Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { QObject::connect(can, &AbstractStream::streamStarted, this, &Slider::streamStarted); } +Slider::~Slider() { + abort_load_thumbnail = true; + thumnail_future.waitForFinished(); +} + void Slider::streamStarted() { abort_load_thumbnail = true; thumnail_future.waitForFinished(); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 6b4c02c573..392db23512 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -18,6 +18,7 @@ class Slider : public QSlider { public: Slider(QWidget *parent); + ~Slider(); private: void mousePressEvent(QMouseEvent *e) override; From b2c6d5d34a1cc194aaf98c4963677a5581bf0a94 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 23 Jan 2023 20:16:50 -0800 Subject: [PATCH 0700/1179] Honda: merge Passport platform into Pilot (#27061) * Move Passport FW versions to Pilot * lol, all duplicates already in pilot * No Passport * Better params for both --- selfdrive/car/honda/carstate.py | 2 +- selfdrive/car/honda/interface.py | 8 ++-- selfdrive/car/honda/values.py | 55 +++++++-------------------- selfdrive/car/tests/routes.py | 2 +- selfdrive/car/tests/test_models.py | 2 +- selfdrive/car/torque_data/params.yaml | 1 - 6 files changed, 21 insertions(+), 49 deletions(-) diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index a37667fd3a..16880d1b1f 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -274,7 +274,7 @@ class CarState(CarStateBase): ret.cruiseState.available = bool(cp.vl[self.main_on_sig_msg]["MAIN_ON"]) # Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models - if self.CP.carFingerprint in (CAR.PILOT, CAR.PASSPORT, CAR.RIDGELINE): + if self.CP.carFingerprint in (CAR.PILOT, CAR.RIDGELINE): if ret.brake > 0.1: ret.brakePressed = True diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 990238ae5d..da921ccda7 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -231,11 +231,11 @@ class CarInterface(CarInterfaceBase): else: ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end - elif candidate in (CAR.PILOT, CAR.PASSPORT): - ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight - ret.wheelbase = 2.82 + elif candidate == CAR.PILOT: + ret.mass = 4278. * CV.LB_TO_KG + STD_CARGO_KG # average weight + ret.wheelbase = 2.86 ret.centerToFront = ret.wheelbase * 0.428 - ret.steerRatio = 17.25 # as spec + ret.steerRatio = 16.0 # as spec ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end tire_stiffness_factor = 0.444 ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]] diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 2906b23bda..1455609226 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -91,7 +91,6 @@ class CAR: ACURA_RDX = "ACURA RDX 2018" ACURA_RDX_3G = "ACURA RDX 2020" PILOT = "HONDA PILOT 2017" - PASSPORT = "HONDA PASSPORT 2021" RIDGELINE = "HONDA RIDGELINE 2017" INSIGHT = "HONDA INSIGHT 2019" HONDA_E = "HONDA E 2020" @@ -142,8 +141,10 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { CAR.ODYSSEY_CHN: None, # Chinese version of Odyssey CAR.ACURA_RDX: HondaCarInfo("Acura RDX 2016-18", "AcuraWatch Plus", min_steer_speed=12. * CV.MPH_TO_MS), CAR.ACURA_RDX_3G: HondaCarInfo("Acura RDX 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), - CAR.PILOT: HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS), - CAR.PASSPORT: HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS), + CAR.PILOT: [ + HondaCarInfo("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS), + HondaCarInfo("Honda Passport 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS), + ], CAR.RIDGELINE: HondaCarInfo("Honda Ridgeline 2017-22", min_steer_speed=12. * CV.MPH_TO_MS), CAR.INSIGHT: HondaCarInfo("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS), CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS), @@ -1067,6 +1068,8 @@ FW_VERSIONS = { b'28101-5EZ-A060\x00\x00', b'28101-5EZ-A100\x00\x00', b'28101-5EZ-A210\x00\x00', + b'28101-5EZ-A600\x00\x00', + b'28101-5EZ-A430\x00\x00', ], (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-RLV-4060\x00\x00', @@ -1078,6 +1081,9 @@ FW_VERSIONS = { b'37805-RLV-C520\x00\x00', b'37805-RLV-C530\x00\x00', b'37805-RLV-C910\x00\x00', + b'37805-RLV-B220\x00\x00', + b'37805-RLV-B210\x00\x00', + b'37805-RLV-L160\x00\x00', ], (Ecu.gateway, 0x18daeff1, None): [ b'38897-TG7-A030\x00\x00', @@ -1110,6 +1116,7 @@ FW_VERSIONS = { b'36161-TGS-A130\x00\x00', b'36161-TGT-A030\x00\x00', b'36161-TGT-A130\x00\x00', + b'36161-TGS-A030\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TG7-A020\x00\x00', @@ -1147,6 +1154,9 @@ FW_VERSIONS = { b'78109-TGS-AP20\x00\x00', b'78109-TGT-AJ20\x00\x00', b'78109-TGT-AK30\x00\x00', + b'78109-TGS-AT20\x00\x00', + b'78109-TGS-AX20\x00\x00', + b'78109-TGS-AJ20\x00\x00', ], (Ecu.vsa, 0x18da28f1, None): [ b'57114-TG7-A130\x00\x00', @@ -1163,42 +1173,6 @@ FW_VERSIONS = { b'57114-TGT-A530\x00\x00', ], }, - CAR.PASSPORT: { - (Ecu.programmedFuelInjection, 0x18da10f1, None): [ - b'37805-RLV-B220\x00\x00', - b'37805-RLV-B210\x00\x00', - b'37805-RLV-L160\x00\x00', - ], - (Ecu.eps, 0x18da30f1, None): [ - b'39990-TGS-A230\x00\x00', - ], - (Ecu.fwdRadar, 0x18dab0f1, None): [ - b'36161-TGS-A030\x00\x00', - b'36161-TGS-A130\x00\x00', - ], - (Ecu.gateway, 0x18daeff1, None): [ - b'38897-TG7-A040\x00\x00', - b'38897-TG7-A030\x00\x00', - ], - (Ecu.srs, 0x18da53f1, None): [ - b'77959-TGS-A010\x00\x00', - ], - (Ecu.shiftByWire, 0x18da0bf1, None): [ - b'54008-TG7-A530\x00\x00', - ], - (Ecu.transmission, 0x18da1ef1, None): [ - b'28101-5EZ-A600\x00\x00', - b'28101-5EZ-A430\x00\x00', - ], - (Ecu.combinationMeter, 0x18da60f1, None): [ - b'78109-TGS-AT20\x00\x00', - b'78109-TGS-AX20\x00\x00', - b'78109-TGS-AJ20\x00\x00', - ], - (Ecu.vsa, 0x18da28f1, None): [ - b'57114-TGS-A530\x00\x00', - ], - }, CAR.ACURA_RDX: { (Ecu.vsa, 0x18da28f1, None): [ b'57114-TX5-A220\x00\x00', @@ -1499,7 +1473,6 @@ DBC = { CAR.ODYSSEY: dbc_dict('honda_odyssey_exl_2018_generated', 'acura_ilx_2016_nidec'), CAR.ODYSSEY_CHN: dbc_dict('honda_odyssey_extreme_edition_2018_china_can_generated', 'acura_ilx_2016_nidec'), CAR.PILOT: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'), - CAR.PASSPORT: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'), CAR.RIDGELINE: dbc_dict('acura_ilx_2016_can_generated', 'acura_ilx_2016_nidec'), CAR.INSIGHT: dbc_dict('honda_insight_ex_2019_can_generated', None), CAR.HONDA_E: dbc_dict('acura_rdx_2020_can_generated', None), @@ -1514,7 +1487,7 @@ STEER_THRESHOLD = { HONDA_NIDEC_ALT_PCM_ACCEL = {CAR.ODYSSEY} HONDA_NIDEC_ALT_SCM_MESSAGES = {CAR.ACURA_ILX, CAR.ACURA_RDX, CAR.CRV, CAR.CRV_EU, CAR.FIT, CAR.FREED, CAR.HRV, CAR.ODYSSEY_CHN, - CAR.PILOT, CAR.PASSPORT, CAR.RIDGELINE} + CAR.PILOT, CAR.RIDGELINE} HONDA_BOSCH = {CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_5G, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E, CAR.CIVIC_2022} HONDA_BOSCH_ALT_BRAKE_SIGNAL = {CAR.ACCORD, CAR.CRV_5G, CAR.ACURA_RDX_3G} diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index ac0521cc68..29cea9c030 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -72,7 +72,7 @@ routes = [ CarTestRoute("d83f36766f8012a5|2020-02-05--18-42-21", HONDA.CIVIC_BOSCH_DIESEL), CarTestRoute("f0890d16a07a236b|2021-05-25--17-27-22", HONDA.INSIGHT), CarTestRoute("07d37d27996096b6|2020-03-04--21-57-27", HONDA.PILOT), - CarTestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.PASSPORT), + CarTestRoute("684e8f96bd491a0e|2021-11-03--11-08-42", HONDA.PILOT), # Passport CarTestRoute("0a78dfbacc8504ef|2020-03-04--13-29-55", HONDA.CIVIC_BOSCH), CarTestRoute("f34a60d68d83b1e5|2020-10-06--14-35-55", HONDA.ACURA_RDX), CarTestRoute("54fd8451b3974762|2021-04-01--14-50-10", HONDA.RIDGELINE), diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index b6f78c4b47..4627b9a570 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -245,7 +245,7 @@ class TestCarModelBase(unittest.TestCase): # TODO: remove this exception once this mismatch is resolved brake_pressed = CS.brakePressed if CS.brakePressed and not self.safety.get_brake_pressed_prev(): - if self.CP.carFingerprint in (HONDA.PILOT, HONDA.PASSPORT, HONDA.RIDGELINE) and CS.brake > 0.05: + if self.CP.carFingerprint in (HONDA.PILOT, HONDA.RIDGELINE) and CS.brake > 0.05: brake_pressed = False checks['brakePressed'] += brake_pressed != self.safety.get_brake_pressed_prev() checks['regenBraking'] += CS.regenBraking != self.safety.get_regen_braking_prev() diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index eb1a04cee6..397b29525d 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -22,7 +22,6 @@ HONDA FIT 2018: [1.5719981427109775, 0.5712761407108976, 0.110773383324281] HONDA HRV 2019: [2.0661212805710205, 0.7521343418694775, 0.17760375789242094] HONDA INSIGHT 2019: [1.5201671214069354, 0.5660229120683284, 0.25808042580281876] HONDA ODYSSEY 2018: [1.8774809275211801, 0.8394431662987996, 0.2096978613792822] -HONDA PASSPORT 2021: [1.5305538930036766, 0.7956063674638759, 0.19599407381531284] HONDA PILOT 2017: [1.7262026201812795, 0.9470005614967523, 0.21351430733218763] HONDA RIDGELINE 2017: [1.4146525028237624, 0.7356572861629564, 0.23307177552211328] HYUNDAI ELANTRA 2021: [3.169, 2.1259108157250735, 0.0819] From 7090a8841935d3a1c67fd915e4898a9880c237b5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 24 Jan 2023 00:04:56 -0800 Subject: [PATCH 0701/1179] Fix fuzz_fw_fingerprint.py script --- selfdrive/debug/internal/fuzz_fw_fingerprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/debug/internal/fuzz_fw_fingerprint.py b/selfdrive/debug/internal/fuzz_fw_fingerprint.py index 1ea133cc19..a18390fef3 100755 --- a/selfdrive/debug/internal/fuzz_fw_fingerprint.py +++ b/selfdrive/debug/internal/fuzz_fw_fingerprint.py @@ -28,7 +28,7 @@ if __name__ == "__main__": for candidate, fws in FWS.items(): fw_dict = {} for (tp, addr, subaddr), fw_list in fws.items(): - fw_dict[(addr, subaddr)] = random.choice(fw_list) + fw_dict[(addr, subaddr)] = [random.choice(fw_list)] matches = match_fw_to_car_fuzzy(fw_dict, log=False, exclude=candidate) From 75f6dc385d86f587504ad2b8d676dcf5a3f40ddd Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Tue, 24 Jan 2023 14:10:31 +0100 Subject: [PATCH 0702/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 4750449f3c..687676be40 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 4750449f3cc41e2dc8141b4818025c5c538dad17 +Subproject commit 687676be4025d9caf9520be89cb328d6a3cc3e10 From b2675cef9a9d4993859b0cd924a1ca74281024f9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 25 Jan 2023 03:36:40 +0800 Subject: [PATCH 0703/1179] cabana: colorful logs based on activity (#27008) * color logs * remove space * update in updateColors --- tools/cabana/SConscript | 2 +- tools/cabana/historylog.cc | 34 +++++++-- tools/cabana/historylog.h | 7 +- tools/cabana/messageswidget.cc | 46 +----------- tools/cabana/messageswidget.h | 7 -- tools/cabana/streams/abstractstream.cc | 62 +--------------- tools/cabana/streams/abstractstream.h | 11 +-- tools/cabana/util.cc | 99 ++++++++++++++++++++++++++ tools/cabana/util.h | 38 ++++++++++ 9 files changed, 176 insertions(+), 130 deletions(-) create mode 100644 tools/cabana/util.cc create mode 100644 tools/cabana/util.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 9b172a544f..fbf3c03d36 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -21,7 +21,7 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', - 'commands.cc', 'messageswidget.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + 'commands.cc', 'messageswidget.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('test'): diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index f0f40697b8..4a975afc4d 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -16,16 +16,16 @@ void HistoryLogModel::setDisplayType(HistoryLogModel::DisplayType type) { QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { const bool display_signals = display_type == HistoryLogModel::Signals; + const auto &m = messages[index.row()]; if (role == Qt::DisplayRole) { - const auto &m = messages[index.row()]; if (index.column() == 0) { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } - return display_signals ? QString::number(m.sig_values[index.column() - 1]) : m.data; - } else if (role == Qt::FontRole && index.column() == 1 && !display_signals) { - return QFontDatabase::systemFont(QFontDatabase::FixedFont); + return display_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); } else if (role == Qt::ToolTipRole && index.column() > 0 && display_signals) { return tr("double click to open the chart"); + } else if (role == Qt::UserRole && index.column() == 1 && !display_signals) { + return HexColors::toVariantList(m.colors); } return {}; } @@ -45,6 +45,7 @@ void HistoryLogModel::refresh() { beginResetModel(); last_fetch_time = 0; messages.clear(); + hex_colors.clear(); updateState(); endResetModel(); } @@ -91,6 +92,7 @@ void HistoryLogModel::updateState() { if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, 0, new_msgs.size() - 1); messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); + updateColors(); endInsertRows(); } last_fetch_time = current_time; @@ -103,11 +105,29 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) { if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, messages.size(), messages.size() + new_msgs.size() - 1); messages.insert(messages.end(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); + if (!dynamic_mode) { + updateColors(); + } endInsertRows(); } } } +void HistoryLogModel::updateColors() { + if (display_type == HistoryLogModel::Hex) { + const auto freq = can->lastMessage(msg_id).freq; + if (dynamic_mode) { + for (auto it = messages.rbegin(); it != messages.rend(); ++it) { + it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + } + } else { + for (auto it = messages.begin(); it != messages.end(); ++it) { + it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + } + } + } +} + template std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; @@ -124,7 +144,7 @@ std::deque HistoryLogModel::fetchData(InputIt first, I if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { auto &m = msgs.emplace_back(); m.mono_time = (*it)->mono_time; - m.data = toHex(QByteArray((char *)dat.begin(), dat.size())); + m.data = QByteArray((char *)dat.begin(), dat.size()); m.sig_values = values; if (msgs.size() >= batch_size && min_time == 0) return msgs; @@ -135,6 +155,7 @@ std::deque HistoryLogModel::fetchData(InputIt first, I } return msgs; } + template std::deque HistoryLogModel::fetchData<>(std::vector::iterator first, std::vector::iterator last, uint64_t min_time); template std::deque HistoryLogModel::fetchData<>(std::vector::reverse_iterator first, std::vector::reverse_iterator last, uint64_t min_time); @@ -183,6 +204,7 @@ HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); verticalHeader()->setVisible(false); + setItemDelegateForColumn(1, new MessageBytesDelegate(this)); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); } @@ -225,8 +247,8 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &AbstractStream::seekedTo, model, &HistoryLogModel::refresh); QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged); + dynamic_mode->setChecked(true); if (can->liveStreaming()) { - dynamic_mode->setChecked(true); dynamic_mode->setEnabled(false); } } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 2ab204af15..34af713fd3 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -41,12 +41,14 @@ public: } void setDynamicMode(int state); void segmentsMerged(); + void updateColors(); void refresh(); struct Message { uint64_t mono_time = 0; QVector sig_values; - QString data; + QByteArray data; + QVector colors; }; template @@ -54,6 +56,7 @@ public: std::deque fetchData(uint64_t from_time, uint64_t min_time = 0); QString msg_id; + HexColors hex_colors; bool has_more_data = true; const int batch_size = 50; int filter_sig_idx = -1; @@ -62,7 +65,7 @@ public: std::function filter_cmp = nullptr; std::deque messages; std::vector sigs; - bool dynamic_mode = false; + bool dynamic_mode = true; DisplayType display_type = HistoryLogModel::Signals; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 0d06604fdc..353fe26340 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -79,15 +79,8 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { case 3: return can_data.count; case 4: return toHex(can_data.dat); } - } else if (role == Qt::FontRole && index.column() == columnCount() - 1) { - return QFontDatabase::systemFont(QFontDatabase::FixedFont); } else if (role == Qt::UserRole && index.column() == 4) { - - QList colors; - for (int i = 0; i < can_data.dat.size(); i++){ - colors.append(can_data.colors[i]); - } - return colors; + return HexColors::toVariantList(can_data.colors); } return {}; } @@ -174,40 +167,3 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { sortMessages(); } } - - -MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { -} - -void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QList colors = index.data(Qt::UserRole).toList(); - - QStyleOptionViewItemV4 opt = option; - initStyleOption(&opt, index); - - const QFont font = index.data(Qt::FontRole).value(); - painter->setFont(font); - - QRect rect = opt.rect; - QString bytes = QString(opt.text); - - QRect pos = rect; - QRect space = painter->boundingRect(pos, opt.displayAlignment, " "); - pos.setX(pos.x() + space.width()); - - if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { - painter->setPen(option.palette.color(QPalette::HighlightedText)); - } else { - painter->setPen(option.palette.color(QPalette::Text)); - } - - int i = 0; - for (auto &byte : bytes.split(" ")) { - QRect sz = painter->boundingRect(pos, opt.displayAlignment, byte); - const int m = space.width() / 2; - painter->fillRect(sz.marginsAdded(QMargins(m + 1, m, m, m)), colors[i].value()); - painter->drawText(pos, opt.displayAlignment, byte); - pos.setX(pos.x() + sz.width() + space.width()); - i++; - } -} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 187e4715b9..49f57b78e6 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -42,10 +42,3 @@ protected: QString current_msg_id; MessageListModel *model; }; - -class MessageBytesDelegate : public QStyledItemDelegate { - Q_OBJECT -public: - MessageBytesDelegate(QObject *parent); - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; -}; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 6ae1900184..b188c41826 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -17,15 +17,9 @@ void AbstractStream::process(QHash *messages) { processing = false; } -static QColor blend(QColor a, QColor b) { - return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); -} - bool AbstractStream::updateEvent(const Event *event) { static std::unique_ptr new_msgs = std::make_unique>(); - static QHash prev_dat; - static QHash> colors; - static QHash> last_change_t; + static QHash hex_colors; static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { @@ -48,59 +42,7 @@ bool AbstractStream::updateEvent(const Event *event) { if (double delta = (current_sec - counters_begin_sec); delta > 0) { data.freq = data.count / delta; } - - // Init colors - if (colors[id].size() != data.dat.size()) { - colors[id].clear(); - for (int i = 0; i < data.dat.size(); i++){ - colors[id].append(QColor(0, 0, 0, 0)); - } - } - - // Init last_change_t - if (last_change_t[id].size() != data.dat.size()) { - last_change_t[id].clear(); - for (int i = 0; i < data.dat.size(); i++){ - last_change_t[id].append(data.ts); - } - } - - // Compute background color for the bytes based on changes - if (prev_dat[id].size() == data.dat.size()) { - for (int i = 0; i < data.dat.size(); i++){ - uint8_t last = prev_dat[id][i]; - uint8_t cur = data.dat[i]; - - const int periodic_threshold = 10; - const int start_alpha = 128; - const float fade_time = 2.0; - - if (last != cur) { - double delta_t = data.ts - last_change_t[id][i]; - - if (delta_t * data.freq > periodic_threshold) { - // Last change was while ago, choose color based on delta up or down - if (cur > last) { - colors[id][i] = QColor(0, 187, 255, start_alpha); // Cyan - } else { - colors[id][i] = QColor(255, 0, 0, start_alpha); // Red - } - } else { - // Periodic changes - colors[id][i] = blend(colors[id][i], QColor(102, 86, 169, start_alpha / 2)); // Greyish/Blue - } - - last_change_t[id][i] = data.ts; - } else { - // Fade out - float alpha_delta = 1.0 / (data.freq + 1) / fade_time; - colors[id][i].setAlphaF(std::max(0.0, colors[id][i].alphaF() - alpha_delta)); - } - } - } - - data.colors = colors[id]; - prev_dat[id] = data.dat; + data.colors = hex_colors[id].compute(data.dat, data.ts, data.freq); } double ts = millis_since_boot(); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 1fe90c8595..9a0187da5e 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -6,6 +6,7 @@ #include #include "tools/cabana/settings.h" +#include "tools/cabana/util.h" #include "tools/replay/replay.h" struct CanData { @@ -15,7 +16,7 @@ struct CanData { uint32_t count = 0; uint32_t freq = 0; QByteArray dat; - QList colors; + QVector colors; }; class AbstractStream : public QObject { @@ -64,13 +65,5 @@ protected: QHash counters; }; -inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } -inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } -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)]; -} - // A global pointer referring to the unique AbstractStream object extern AbstractStream *can; diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc new file mode 100644 index 0000000000..0684d3c59a --- /dev/null +++ b/tools/cabana/util.cc @@ -0,0 +1,99 @@ +#include "tools/cabana/util.h" + +#include +#include + +static QColor blend(QColor a, QColor b) { + return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); +} + +const QVector &HexColors::compute(const QByteArray &dat, double ts, uint32_t freq) { + if (prev_dat.size() != dat.size()) { + colors.resize(dat.size()); + last_change_t.resize(dat.size()); + std::fill(colors.begin(), colors.end(), QColor(0, 0, 0, 0)); + std::fill(last_change_t.begin(), last_change_t.end(), ts); + } else { + for (int i = 0; i < dat.size(); ++i) { + const uint8_t last = prev_dat[i]; + const uint8_t cur = dat[i]; + + if (last != cur) { + double delta_t = ts - last_change_t[i]; + if (delta_t * freq > periodic_threshold) { + // Last change was while ago, choose color based on delta up or down + if (cur > last) { + colors[i] = QColor(0, 187, 255, start_alpha); // Cyan + } else { + colors[i] = QColor(255, 0, 0, start_alpha); // Red + } + } else { + // Periodic changes + colors[i] = blend(colors[i], QColor(102, 86, 169, start_alpha / 2)); // Greyish/Blue + } + + last_change_t[i] = ts; + } else { + // Fade out + float alpha_delta = 1.0 / (freq + 1) / fade_time; + colors[i].setAlphaF(std::max(0.0, colors[i].alphaF() - alpha_delta)); + } + } + } + + prev_dat = dat; + return colors; +} + +void HexColors::clear() { + prev_dat.clear(); + last_change_t.clear(); + colors.clear(); +} + +QList HexColors::toVariantList(const QVector &colors) { + QList ret; + ret.reserve(colors.size()); + for (auto &c : colors) ret.append(c); + return ret; +} + +// MessageBytesDelegate + +MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { + fixed_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); +} + +void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + QList colors = index.data(Qt::UserRole).toList(); + if (colors.empty()) { + QStyledItemDelegate::paint(painter, option, index); + return; + } + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { + painter->setPen(option.palette.color(QPalette::HighlightedText)); + } else { + painter->setPen(option.palette.color(QPalette::Text)); + } + + painter->setFont(fixed_font); + QRect space = painter->boundingRect(opt.rect, opt.displayAlignment, " "); + QRect pos = painter->boundingRect(opt.rect, opt.displayAlignment, "00"); + pos.moveLeft(pos.x() + space.width()); + + int m = space.width() / 2; + const QMargins margins(m + 1, m, m, m); + + int i = 0; + for (auto &byte : opt.text.split(" ")) { + if (i < colors.size()) { + painter->fillRect(pos.marginsAdded(margins), colors[i].value()); + } + painter->drawText(pos, opt.displayAlignment, byte); + pos.moveLeft(pos.right() + space.width()); + i++; + } +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h new file mode 100644 index 0000000000..146410d7c6 --- /dev/null +++ b/tools/cabana/util.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include + +class HexColors { +public: + const QVector &compute(const QByteArray &dat, double ts, uint32_t freq); + static QList toVariantList(const QVector &colors); + void clear(); + +private: + const int periodic_threshold = 10; + const int start_alpha = 128; + const float fade_time = 2.0; + QByteArray prev_dat; + QVector last_change_t; + QVector colors; +}; + +class MessageBytesDelegate : public QStyledItemDelegate { + Q_OBJECT +public: + MessageBytesDelegate(QObject *parent); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QFont fixed_font; +}; + +inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } +inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } +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)]; +} From 690999a2a6138368a93e818cbcebc984c7e58b91 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 24 Jan 2023 11:42:32 -0800 Subject: [PATCH 0704/1179] CI: increase submodule fetch depth --- release/check-submodules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/check-submodules.sh b/release/check-submodules.sh index 182042e6b4..bc85a43c57 100755 --- a/release/check-submodules.sh +++ b/release/check-submodules.sh @@ -1,7 +1,7 @@ #!/bin/bash while read hash submodule ref; do - git -C $submodule fetch --depth 100 origin master + git -C $submodule fetch --depth 200 origin master git -C $submodule branch -r --contains $hash | grep "origin/master" if [ "$?" -eq 0 ]; then echo "$submodule ok" From 64ed44e3b51524ee3412600f647223dc9e7d6f87 Mon Sep 17 00:00:00 2001 From: George Hotz <72895+geohot@users.noreply.github.com> Date: Tue, 24 Jan 2023 14:06:56 -0800 Subject: [PATCH 0705/1179] tinygrad: update to new version (#27067) * tinygrad: bump and retain OPENCL behavior * add graph.py to release, bump tiny * update files_common and read from it in scons * bump with typo fix * switch tinygrad backend to GPU * update ref commit Co-authored-by: Comma Device --- release/files_common | 14 +++----- selfdrive/modeld/SConscript | 32 +++++-------------- .../process_replay/model_replay_ref_commit | 2 +- tinygrad_repo | 2 +- 4 files changed, 15 insertions(+), 35 deletions(-) diff --git a/release/files_common b/release/files_common index edb37bc0de..547bb58144 100644 --- a/release/files_common +++ b/release/files_common @@ -580,17 +580,13 @@ opendbc/tesla_can.dbc opendbc/tesla_radar.dbc opendbc/tesla_powertrain.dbc -tinygrad_repo/openpilot/compile.py tinygrad_repo/accel/opencl/* +tinygrad_repo/tinygrad/llops/ops_opencl.py +tinygrad_repo/openpilot/compile.py tinygrad_repo/extra/onnx.py tinygrad_repo/extra/thneed.py tinygrad_repo/extra/utils.py tinygrad_repo/tinygrad/llops/ops_gpu.py -tinygrad_repo/tinygrad/llops/ops_opencl.py -tinygrad_repo/tinygrad/helpers.py -tinygrad_repo/tinygrad/mlops.py -tinygrad_repo/tinygrad/ops.py -tinygrad_repo/tinygrad/shapetracker.py -tinygrad_repo/tinygrad/tensor.py -tinygrad_repo/tinygrad/nn/__init__.py -tinygrad_repo/tinygrad/nn/optim.py +tinygrad_repo/tinygrad/shape/* +tinygrad_repo/tinygrad/nn/* +tinygrad_repo/tinygrad/*.py diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 82338e456b..7bbc1b3477 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -70,30 +70,14 @@ lenv.Program('_dmonitoringmodeld', [ if use_thneed and arch == "larch64" or GetOption('pc_thneed'): fn = File("models/supercombo").abspath - if GetOption('pc_thneed'): - cmd = f"cd {Dir('#').abspath}/tinygrad_repo && GPU=1 NATIVE_EXPLOG=1 OPTWG=1 UNSAFE_FLOAT4=1 DEBUGCL=1 python3 openpilot/compile.py {fn}.onnx {fn}.thneed" - else: - cmd = f"cd {Dir('#').abspath}/tinygrad_repo && FLOAT16=1 MATMUL=1 PYOPENCL_NO_CACHE=1 NATIVE_EXPLOG=1 OPTWG=1 UNSAFE_FLOAT4=1 DEBUGCL=1 python3 openpilot/compile.py {fn}.onnx {fn}.thneed" + tinygrad_opts = ["NATIVE_EXPLOG=1", "VALIDHACKS=1", "OPTWG=1", "IMAGE=2", "GPU=1", "CLCACHE=0"] + if not GetOption('pc_thneed'): + # use FLOAT16 on device for speed + don't cache the CL kernels for space + tinygrad_opts += ["FLOAT16=1", "PYOPENCL_NO_CACHE=1"] + cmd = f"cd {Dir('#').abspath}/tinygrad_repo && " + ' '.join(tinygrad_opts) + f" python3 openpilot/compile.py {fn}.onnx {fn}.thneed" - # is there a better way then listing all of tinygrad? - lenv.Command(fn + ".thneed", [fn + ".onnx", - "#tinygrad_repo/openpilot/compile.py", - "#tinygrad_repo/accel/opencl/conv.cl", - "#tinygrad_repo/accel/opencl/matmul.cl", - "#tinygrad_repo/accel/opencl/ops_opencl.py", - "#tinygrad_repo/accel/opencl/preprocessing.py", - "#tinygrad_repo/extra/onnx.py", - "#tinygrad_repo/extra/thneed.py", - "#tinygrad_repo/extra/utils.py", - "#tinygrad_repo/tinygrad/llops/ops_gpu.py", - "#tinygrad_repo/tinygrad/llops/ops_opencl.py", - "#tinygrad_repo/tinygrad/helpers.py", - "#tinygrad_repo/tinygrad/mlops.py", - "#tinygrad_repo/tinygrad/ops.py", - "#tinygrad_repo/tinygrad/shapetracker.py", - "#tinygrad_repo/tinygrad/tensor.py", - "#tinygrad_repo/tinygrad/nn/__init__.py" - ], cmd) + tinygrad_files = sum([lenv.Glob("#"+x) for x in open(File("#release/files_common").abspath).read().split("\n") if x.startswith("tinygrad_repo/")], []) + lenv.Command(fn + ".thneed", [fn + ".onnx"] + tinygrad_files, cmd) llenv = lenv.Clone() if GetOption('pc_thneed'): @@ -116,4 +100,4 @@ llenv.Program('_modeld', [ lenv.Program('_navmodeld', [ "navmodeld.cc", "models/nav.cc", - ]+common_model, LIBS=libs + transformations) \ No newline at end of file + ]+common_model, LIBS=libs + transformations) diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 22e021dcaf..9eefc73792 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -db587bfef2317c5a3471632ac47381457e1be853 \ No newline at end of file +8233a12f97f483645e7691b8c54552a2f861a7ad diff --git a/tinygrad_repo b/tinygrad_repo index 8e22d5ee67..2e1d47b166 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit 8e22d5ee675277181e1eff644dde9e844fc40fce +Subproject commit 2e1d47b16625ff343516287cdd9e4bcb26f5c4ef From 544ad25a0b9af70e2b22f3ec4e0fd8788929fd2d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 25 Jan 2023 07:07:11 +0800 Subject: [PATCH 0706/1179] cabana: support pause and slow motion playback in live stream mode (#27051) * support pause and slow motion playback in live stream mode * override * virtual functions * move to function fix * lock handleEvent * show speed controls in video widget * fix pause signal * set margins * cleanup --- tools/cabana/mainwin.cc | 11 +++--- tools/cabana/streams/livestream.cc | 53 ++++++++++++++++++-------- tools/cabana/streams/livestream.h | 15 ++++++-- tools/cabana/videowidget.cc | 61 +++++++++++++++++++----------- tools/cabana/videowidget.h | 1 + 5 files changed, 93 insertions(+), 48 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d2e4ff9ca7..e49148160d 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -126,15 +126,14 @@ void MainWindow::createDockWindows() { // splitter between video and charts video_splitter = new QSplitter(Qt::Vertical, this); - if (!can->liveStreaming()) { - video_widget = new VideoWidget(this); - video_splitter->addWidget(video_widget); - QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); - } + video_widget = new VideoWidget(this); + video_splitter->addWidget(video_widget); + QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::rangeChanged); + video_splitter->addWidget(charts_container); video_splitter->setStretchFactor(1, 1); video_splitter->restoreState(settings.video_splitter_state); - if (!can->liveStreaming() && video_splitter->sizes()[0] == 0) { + if (can->liveStreaming() || video_splitter->sizes()[0] == 0) { // display video at minimum size. video_splitter->setSizes({1, 1}); } diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index b0af9f3281..3edd2a7758 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -1,10 +1,6 @@ #include "tools/cabana/streams/livestream.h" LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), AbstractStream(parent, true) { - if (!zmq_address.isEmpty()) { - setenv("ZMQ", "1", 1); - } - timer = new QTimer(this); timer->callOnTimeout(this, &LiveStream::removeExpiredEvents); timer->start(3 * 1000); @@ -24,12 +20,14 @@ LiveStream::~LiveStream() { } void LiveStream::streamThread() { + if (!zmq_address.isEmpty()) { + setenv("ZMQ", "1", 1); + } std::unique_ptr context(Context::create()); std::string address = zmq_address.isEmpty() ? "127.0.0.1" : zmq_address.toStdString(); std::unique_ptr sock(SubSocket::create(context.get(), "can", address)); assert(sock != NULL); sock->setTimeout(50); - // run as fast as messages come in while (!QThread::currentThread()->isInterruptionRequested()) { Message *msg = sock->receive(true); @@ -40,22 +38,40 @@ void LiveStream::streamThread() { AlignedBuffer *buf = messages.emplace_back(new AlignedBuffer()); Event *evt = ::new Event(buf->align(msg)); delete msg; - { - std::lock_guard lk(lock); - can_events.push_back(evt); - } - if (start_ts == 0) { - start_ts = evt->mono_time; - emit streamStarted(); - } - current_ts = evt->mono_time; + handleEvent(evt); + // TODO: write stream to log file to replay it with cabana --data_dir flag. + } +} + +void LiveStream::handleEvent(Event *evt) { + std::lock_guard lk(lock); + can_events.push_back(evt); + + current_ts = evt->mono_time; + if (start_ts == 0 || current_ts < start_ts) { if (current_ts < start_ts) { qDebug() << "stream is looping back to old time stamp"; - start_ts = current_ts.load(); + } + start_ts = current_ts.load(); + emit streamStarted(); + } + + if (!pause_) { + if (speed_ < 1 && last_update_ts > 0) { + auto it = std::upper_bound(can_events.begin(), can_events.end(), last_update_event_ts, [](uint64_t ts, auto &e) { + return ts < e->mono_time; + }); + + if (it != can_events.end() && + (nanos_since_boot() - last_update_ts) < ((*it)->mono_time - last_update_event_ts) / speed_) { + return; + } + evt = (*it); } updateEvent(evt); - // TODO: write stream to log file to replay it with cabana --data_dir flag. + last_update_event_ts = evt->mono_time; + last_update_ts = nanos_since_boot(); } } @@ -80,3 +96,8 @@ const std::vector *LiveStream::events() const { std::copy(can_events.begin(), can_events.end(), std::back_inserter(events_vector)); return &events_vector; } + +void LiveStream::pause(bool pause) { + pause_ = pause; + emit paused(); +} diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index db1638d761..ba20032b67 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -8,17 +8,21 @@ class LiveStream : public AbstractStream { public: LiveStream(QObject *parent, QString address = {}); - ~LiveStream(); + virtual ~LiveStream(); inline QString routeName() const override { return QString("Live Streaming From %1").arg(zmq_address.isEmpty() ? "127.0.0.1" : zmq_address); } inline double routeStartTime() const override { return start_ts / (double)1e9; } inline double currentSec() const override { return (current_ts - start_ts) / (double)1e9; } + void setSpeed(float speed) override { speed_ = std::min(1.0, speed); } + bool isPaused() const override { return pause_; } + void pause(bool pause) override; const std::vector *events() const override; protected: - void streamThread(); - void removeExpiredEvents(); + virtual void handleEvent(Event *evt); + virtual void streamThread(); + virtual void removeExpiredEvents(); mutable std::mutex lock; mutable std::vector events_vector; @@ -26,6 +30,11 @@ protected: std::deque messages; std::atomic start_ts = 0; std::atomic current_ts = 0; + std::atomic speed_ = 1; + std::atomic pause_ = false; + uint64_t last_update_event_ts = 0; + uint64_t last_update_ts = 0; + const QString zmq_address; QThread *stream_thread; QTimer *timer; diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 729302adaa..445a21c755 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -27,8 +27,41 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(frame); QVBoxLayout *frame_layout = new QVBoxLayout(frame); + if (!can->liveStreaming()) { + frame_layout->addWidget(createCameraWidget()); + } + + // btn controls + QHBoxLayout *control_layout = new QHBoxLayout(); + play_btn = new QPushButton(); + control_layout->addWidget(play_btn); + + QButtonGroup *group = new QButtonGroup(this); + group->setExclusive(true); + for (float speed : {0.1, 0.5, 1., 2.}) { + if (can->liveStreaming() && speed > 1) continue; + + QPushButton *btn = new QPushButton(QString("%1x").arg(speed), this); + btn->setCheckable(true); + QObject::connect(btn, &QPushButton::clicked, [=]() { can->setSpeed(speed); }); + control_layout->addWidget(btn); + group->addButton(btn); + if (speed == 1.0) btn->setChecked(true); + } + frame_layout->addLayout(control_layout); + + QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); + QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); + QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState); + updatePlayBtnState(); +} + +QWidget *VideoWidget::createCameraWidget() { + QWidget *w = new QWidget(this); + QVBoxLayout *l = new QVBoxLayout(w); + l->setContentsMargins(0, 0, 0, 0); cam_widget = new CameraWidget("camerad", can->visionStreamType(), false); - frame_layout->addWidget(cam_widget); + l->addWidget(cam_widget); // slider controls slider_layout = new QHBoxLayout(); @@ -42,24 +75,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { end_time_label = new QLabel(this); slider_layout->addWidget(end_time_label); - frame_layout->addLayout(slider_layout); - - // btn controls - QHBoxLayout *control_layout = new QHBoxLayout(); - play_btn = new QPushButton(); - control_layout->addWidget(play_btn); - - QButtonGroup *group = new QButtonGroup(this); - group->setExclusive(true); - for (float speed : {0.1, 0.5, 1., 2.}) { - QPushButton *btn = new QPushButton(QString("%1x").arg(speed), this); - btn->setCheckable(true); - QObject::connect(btn, &QPushButton::clicked, [=]() { can->setSpeed(speed); }); - control_layout->addWidget(btn); - group->addButton(btn); - if (speed == 1.0) btn->setChecked(true); - } - frame_layout->addLayout(control_layout); + l->addLayout(slider_layout); cam_widget->setMinimumHeight(100); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); @@ -69,15 +85,12 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { 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, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); - QObject::connect(play_btn, &QPushButton::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); - QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); - QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState); QObject::connect(can, &AbstractStream::streamStarted, [this]() { end_time_label->setText(formatTime(can->totalSeconds())); slider->setRange(0, can->totalSeconds() * 1000); }); - updatePlayBtnState(); + return w; } void VideoWidget::timeLabelClicked() { @@ -101,6 +114,8 @@ void VideoWidget::timeLabelClicked() { } void VideoWidget::rangeChanged(double min, double max, bool is_zoomed) { + if (can->liveStreaming()) return; + if (!is_zoomed) { min = 0; max = can->totalSeconds(); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 392db23512..51197eedd6 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -49,6 +49,7 @@ protected: void updateState(); void updatePlayBtnState(); void timeLabelClicked(); + QWidget *createCameraWidget(); CameraWidget *cam_widget; QLabel *end_time_label; From 500e379b4343fb3c3bd017106683636467517cc3 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 24 Jan 2023 18:40:38 -0500 Subject: [PATCH 0707/1179] VW MQB: Add FW for 2021 Volkswagen Tiguan. (#26966) Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 51161f2972..bdb43c542a 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -710,10 +710,12 @@ FW_VERSIONS = { b'\xf1\x875N0906259 \xf1\x890002', b'\xf1\x875NA907115E \xf1\x890005', b'\xf1\x8783A907115B \xf1\x890005', + b'\xf1\x8783A907115F \xf1\x890002', b'\xf1\x8783A907115G \xf1\x890001', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158DT\xf1\x893698', + b'\xf1\x8709G927158FM\xf1\x893757', b'\xf1\x8709G927158GC\xf1\x893821', b'\xf1\x8709G927158GD\xf1\x893820', b'\xf1\x870D9300043 \xf1\x895202', From d1c87faedc3f93327aa890e2b5155df9596bb971 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Tue, 24 Jan 2023 19:11:12 -0500 Subject: [PATCH 0708/1179] Hyundai: Add FW Versions for Elantra 2023 (#27026) * Hyundai: Add FW Versions for Elantra 2023 * only short where possible * regen Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 0d4c53ac01..4a46360d4f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -57,7 +57,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| |Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|| |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| -|Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 31cbe68d13..b3cb46699a 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -145,7 +145,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Hyundai Elantra GT 2017-19", harness=Harness.hyundai_e), HyundaiCarInfo("Hyundai i30 2017-19", harness=Harness.hyundai_e), ], - CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-22", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), + CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c), @@ -1322,25 +1322,26 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', b'\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ', + b'\xf1\x00CN7_ SCC FNCUP 1.00 1.01 99110-AA000 ', b'\xf1\x8799110AA000\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ', b'\xf1\x8799110AA000\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00CN7 MDPS C 1.00 1.06 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4CNDC106', b'\xf1\x8756310/AA070\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106', - b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106', b'\xf1\x8756310AA050\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106\xf1\xa01.06', + b'\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106', ], (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-AB000 200819', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.01 99210-AB000 210205', b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111', + b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800', b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 104 \x08\x03 58910-AA800', - b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800', b'\xf1\x8758910-AA800\xf1\x00CN ESC \t 105 \x10\x03 58910-AA800', b'\xf1\x8758910-AB800\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800\xf1\xa01.01', ], @@ -1358,6 +1359,7 @@ FW_VERSIONS = { b'\xf1\x81HM6M2_0a0_FF0', b'\xf1\x82CNCVD0AMFCXCSFFB', b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_G80', + b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x81HM6M2_0a0_HC0', ], }, CAR.ELANTRA_HEV_2021: { From 81956649c8fad46beb6668009f2136b341260434 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 25 Jan 2023 08:14:08 +0800 Subject: [PATCH 0709/1179] cabana: improve layout (#27039) improve layout --- tools/cabana/binaryview.cc | 7 ++++++- tools/cabana/binaryview.h | 1 + tools/cabana/detailwidget.cc | 1 - tools/cabana/detailwidget.h | 1 + tools/cabana/mainwin.cc | 1 - 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 84c2dd2a52..eaa33724e8 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -11,6 +11,7 @@ // BinaryView const int CELL_HEIGHT = 36; +const int VERTICAL_HEADER_WIDTH = 30; inline int get_bit_index(const QModelIndex &index, bool little_endian) { return index.row() * 8 + (little_endian ? 7 - index.column() : index.column()); @@ -33,6 +34,10 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } +QSize BinaryView::minimumSizeHint() const { + return {horizontalHeader()->minimumSectionSize() * 9 + VERTICAL_HEADER_WIDTH + 2, 0}; +} + void BinaryView::highlight(const Signal *sig) { if (sig != hovered_sig) { hovered_sig = sig; @@ -215,7 +220,7 @@ QVariant BinaryViewModel::headerData(int section, Qt::Orientation orientation, i if (orientation == Qt::Vertical) { switch (role) { case Qt::DisplayRole: return section; - case Qt::SizeHintRole: return QSize(30, 0); + case Qt::SizeHintRole: return QSize(VERTICAL_HEADER_WIDTH, 0); case Qt::TextAlignmentRole: return Qt::AlignCenter; } } diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index e936efc658..55de71572e 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -60,6 +60,7 @@ public: void highlight(const Signal *sig); QSet getOverlappingSignals() const; inline void updateState() { model->updateState(); } + QSize minimumSizeHint() const override; signals: void signalClicked(const Signal *sig); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 78e5a6a6f6..7f59087643 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -16,7 +16,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { undo_stack = new QUndoStack(this); - setMinimumWidth(500); QWidget *main_widget = new QWidget(this); QVBoxLayout *main_layout = new QVBoxLayout(main_widget); main_layout->setContentsMargins(0, 0, 0, 0); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 18c58ab6bf..b07629084a 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -31,6 +31,7 @@ public: DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const QString &message_id); void dbcMsgChanged(int show_form_idx = -1); + QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } QUndoStack *undo_stack = nullptr; private: diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index e49148160d..bd32cfdfcc 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -24,7 +24,6 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const MainWindow::MainWindow() : QMainWindow() { createDockWindows(); detail_widget = new DetailWidget(charts_widget, this); - detail_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); setCentralWidget(detail_widget); createActions(); createStatusBar(); From e2e780e7c650878c2b3305531efe8239d6a99933 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Tue, 24 Jan 2023 16:34:41 -0800 Subject: [PATCH 0710/1179] ci: intra-camera timing check (#27069) * test frame time * 1 is still much tighter than 5 --- system/camerad/test/test_camerad.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index 34411e4ef1..f03c531b20 100755 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import time import unittest +import numpy as np from collections import defaultdict import cereal.messaging as messaging @@ -12,6 +13,8 @@ from system.hardware import TICI TEST_TIMESPAN = 30 LAG_FRAME_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 0.5, # ARs use synced pulses for frame starts log.FrameData.ImageSensor.ox03c10: 1.0} # OXs react to out-of-sync at next frame +FRAME_DELTA_TOLERANCE = {log.FrameData.ImageSensor.ar0231: 1.0, + log.FrameData.ImageSensor.ox03c10: 1.0} CAMERAS = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState') @@ -36,10 +39,16 @@ class TestCamerad(unittest.TestCase): managed_processes['camerad'].stop() cls.log_by_frame_id = defaultdict(list) + cls.sensor_type = None for cam, msgs in cls.logs.items(): + if cls.sensor_type is None: + cls.sensor_type = getattr(msgs[0], msgs[0].which()).sensor.raw expected_frames = service_list[cam].frequency * TEST_TIMESPAN assert expected_frames*0.95 < len(msgs) < expected_frames*1.05, f"unexpected frame count {cam}: {expected_frames=}, got {len(msgs)}" + dts = np.abs(np.diff([getattr(m, m.which()).timestampSof/1e6 for m in msgs]) - 1000/service_list[cam].frequency) + assert (dts < FRAME_DELTA_TOLERANCE[cls.sensor_type]).all(), f"{cam} dts(ms) out of spec: max diff {dts.max()}, 99 percentile {np.percentile(dts, 99)}" + for m in msgs: cls.log_by_frame_id[getattr(m, m.which()).frameId].append(m) @@ -64,17 +73,16 @@ class TestCamerad(unittest.TestCase): assert len(skips) == 0, f"Found frame skips, missing cameras for the following frames: {skips}" def test_frame_sync(self): - sensor_type = [getattr(msgs[0], msgs[0].which()).sensor for frame_id, msgs in self.log_by_frame_id.items()][0].raw frame_times = {frame_id: [getattr(m, m.which()).timestampSof for m in msgs] for frame_id, msgs in self.log_by_frame_id.items()} diffs = {frame_id: (max(ts) - min(ts))/1e6 for frame_id, ts in frame_times.items()} def get_desc(fid, diff): cam_times = [(m.which(), getattr(m, m.which()).timestampSof/1e6) for m in self.log_by_frame_id[fid]] return (diff, cam_times) - laggy_frames = {k: get_desc(k, v) for k, v in diffs.items() if v > LAG_FRAME_TOLERANCE[sensor_type]} + laggy_frames = {k: get_desc(k, v) for k, v in diffs.items() if v > LAG_FRAME_TOLERANCE[self.sensor_type]} def in_tol(diff): - return 50 - LAG_FRAME_TOLERANCE[sensor_type] < diff and diff < 50 + LAG_FRAME_TOLERANCE[sensor_type] + return 50 - LAG_FRAME_TOLERANCE[self.sensor_type] < diff and diff < 50 + LAG_FRAME_TOLERANCE[self.sensor_type] if len(laggy_frames) != 0 and all( in_tol(laggy_frames[lf][0]) for lf in laggy_frames): print("TODO: handle camera out of sync") else: From 1e9ac45221104923708a08a9198d35099a1df23d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 24 Jan 2023 18:37:00 -0800 Subject: [PATCH 0711/1179] Honda Nidec: gather available ECUs from camera (#27071) Query bus 0 for Nidec data collection --- selfdrive/car/honda/values.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 1455609226..1e0d22379c 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -155,6 +155,13 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [StdQueries.UDS_VERSION_REQUEST], [StdQueries.UDS_VERSION_RESPONSE], + bus=1, + ), + # Query Nidec PT bus from camera for data collection + Request( + [StdQueries.UDS_VERSION_REQUEST], + [StdQueries.UDS_VERSION_RESPONSE], + bus=0, ), ], ) From 7ba8e56e877e8d0332def1fb4fedc09945776132 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 24 Jan 2023 19:22:13 -0800 Subject: [PATCH 0712/1179] [RAM 1500 5TH GEN] Update offline torque parameters and enable torqued (#27072) * make run torque learnable * update ram offline values * add ram 1500 to torqued * update refs --- selfdrive/car/torque_data/override.yaml | 1 - selfdrive/car/torque_data/params.yaml | 1 + selfdrive/locationd/torqued.py | 18 +++++++++++++----- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 3a9f92c046..6238c6ff99 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -21,7 +21,6 @@ FORD FOCUS 4TH GEN: [.nan, 1.5, .nan] COMMA BODY: [.nan, 1000, .nan] # Totally new cars -RAM 1500 5TH GEN: [2.0, 2.0, 0.0] RAM HD 5TH GEN: [1.4, 1.4, 0.0] SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] CHEVROLET BOLT EV 2022: [2.0, 2.0, 0.05] diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 397b29525d..6a607f3a8a 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -56,6 +56,7 @@ LEXUS RX 2020: [1.5228812994274734, 1.431102486563665, 0.164117] LEXUS RX HYBRID 2017: [1.6984261557042386, 1.3211501880159107, 0.1820354534928893] LEXUS RX HYBRID 2020: [1.5522309889823778, 1.255230465866663, 0.2220954003055114] MAZDA CX-9 2021: [1.7601682915983443, 1.0889677335154337, 0.17713792194297195] +RAM 1500 5TH GEN: [1.550848, 2.0, 0.132261] SKODA SUPERB 3RD GEN: [1.166437404652981, 1.1686163012668165, 0.12194533036948708] SUBARU FORESTER 2019: [3.6617001649776793, 2.342197172531713, 0.11075960785398745] SUBARU IMPREZA LIMITED 2019: [1.0670704910352047, 0.8234374840709592, 0.20986563268614938] diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 588bca1578..cb8101bbd4 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -22,7 +22,9 @@ FIT_POINTS_TOTAL_QLOG = 600 MIN_VEL = 15 # m/s FRICTION_FACTOR = 1.5 # ~85% of data coverage FACTOR_SANITY = 0.3 +FACTOR_SANITY_QLOG = 0.5 FRICTION_SANITY = 0.5 +FRICTION_SANITY_QLOG = 0.8 STEER_MIN_THRESHOLD = 0.02 MIN_FILTER_DECAY = 50 MAX_FILTER_DECAY = 250 @@ -35,6 +37,7 @@ MIN_ENGAGE_BUFFER = 2 # secs VERSION = 1 # bump this to invalidate old parameter caches ALLOWED_CARS = ['toyota', 'hyundai'] +ALLOWED_PLATFORMS = ['RAM 1500 5TH GEN'] # for adding individual platforms from a brand without torqued def slope2rot(slope): @@ -100,15 +103,20 @@ class TorqueEstimator: self.min_bucket_points = MIN_BUCKET_POINTS / 10 self.min_points_total = MIN_POINTS_TOTAL_QLOG self.fit_points = FIT_POINTS_TOTAL_QLOG + self.factor_sanity = FACTOR_SANITY_QLOG + self.friction_sanity = FRICTION_SANITY_QLOG + else: self.min_bucket_points = MIN_BUCKET_POINTS self.min_points_total = MIN_POINTS_TOTAL self.fit_points = FIT_POINTS_TOTAL + self.factor_sanity = FACTOR_SANITY + self.friction_sanity = FRICTION_SANITY self.offline_friction = 0.0 self.offline_latAccelFactor = 0.0 self.resets = 0.0 - self.use_params = CP.carName in ALLOWED_CARS + self.use_params = (CP.carName in ALLOWED_CARS) or (CP.carFingerprint in ALLOWED_PLATFORMS) if CP.lateralTuning.which() == 'torque': self.offline_friction = CP.lateralTuning.torque.friction @@ -123,10 +131,10 @@ class TorqueEstimator: 'points': [] } self.decay = MIN_FILTER_DECAY - self.min_lataccel_factor = (1.0 - FACTOR_SANITY) * self.offline_latAccelFactor - self.max_lataccel_factor = (1.0 + FACTOR_SANITY) * self.offline_latAccelFactor - self.min_friction = (1.0 - FRICTION_SANITY) * self.offline_friction - self.max_friction = (1.0 + FRICTION_SANITY) * self.offline_friction + self.min_lataccel_factor = (1.0 - self.factor_sanity) * self.offline_latAccelFactor + self.max_lataccel_factor = (1.0 + self.factor_sanity) * self.offline_latAccelFactor + self.min_friction = (1.0 - self.friction_sanity) * self.offline_friction + self.max_friction = (1.0 + self.friction_sanity) * self.offline_friction # try to restore cached params params = Params() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1aa3aa6f1e..fb714b6f57 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -acc5655633af6ade096ad41f680fd8a28c2e3790 \ No newline at end of file +3639e42ed538ee5d94ec2572cf27af6260633fad \ No newline at end of file From a68633283f7269bb6ab2c2670cce0473512992ec Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 24 Jan 2023 20:36:44 -0800 Subject: [PATCH 0713/1179] Civic 2022: add camera versions (#27073) * Add fwdRadar for Honda Civic 2022 * remove debug cmt --- selfdrive/car/honda/values.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 1e0d22379c..e3448b31be 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1441,6 +1441,12 @@ FW_VERSIONS = { b'78108-T21-A230\x00\x00', b'78108-T22-A020\x00\x00', ], + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-T20-A070\x00\x00', + b'36161-T20-A080\x00\x00', + b'36161-T20-A060\x00\x00', + b'36161-T47-A070\x00\x00', + ], (Ecu.vsa, 0x18DA28F1, None): [ b'57114-T20-AB40\x00\x00', b'57114-T43-JB30\x00\x00', From 95d45a8d64f5e7bd54cd3e96aec83f44177a0fa7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 24 Jan 2023 21:24:33 -0800 Subject: [PATCH 0714/1179] Honda Civic 2022: gather FW versions for unknown ECU (#27074) * Add unknown civic 2022 extra ecu * Update selfdrive/car/honda/values.py --- selfdrive/car/honda/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index e3448b31be..d10ec0a7e6 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -164,6 +164,10 @@ FW_QUERY_CONFIG = FwQueryConfig( bus=0, ), ], + extra_ecus=[ + # The only other ECU on PT bus accessible by camera on radarless Civic + (Ecu.unknown, 0x18DAB3F1, None), + ], ) FW_VERSIONS = { From f2966e9ef4548c6365715f8e5bd55f4e4838dcdc Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 24 Jan 2023 22:30:29 -0800 Subject: [PATCH 0715/1179] Honda FPv2: log extra UDS identifier (#27076) * Add debugging uds ID * add comment * remove spaces * try chaining the queries (temp debug) this works * works! - Revert "try chaining the queries (temp debug)" This reverts commit c53d0f64aecdbd6224b0fd524f96637d29320cd1. --- selfdrive/car/honda/values.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index d10ec0a7e6..07eed0cfc2 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -4,9 +4,10 @@ from typing import Dict, List, Optional, Union from cereal import car from common.conversions import Conversions as CV +from panda.python import uds from selfdrive.car import dbc_dict from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness -from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries +from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 Ecu = car.CarParams.Ecu VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -150,13 +151,27 @@ CAR_INFO: Dict[str, Optional[Union[HondaCarInfo, List[HondaCarInfo]]]] = { CAR.HONDA_E: HondaCarInfo("Honda e 2020", "All", min_steer_speed=3. * CV.MPH_TO_MS), } +HONDA_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(0xF112) +HONDA_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \ + p16(0xF112) + FW_QUERY_CONFIG = FwQueryConfig( requests=[ + # Currently used to fingerprint Request( [StdQueries.UDS_VERSION_REQUEST], [StdQueries.UDS_VERSION_RESPONSE], bus=1, ), + + # Data collection requests: + # Log extra identifiers for current ECUs + Request( + [HONDA_VERSION_REQUEST], + [HONDA_VERSION_RESPONSE], + bus=1, + ), # Query Nidec PT bus from camera for data collection Request( [StdQueries.UDS_VERSION_REQUEST], From 01fa0ca69dd7d6633bab754c3122efe0bc5a330c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 24 Jan 2023 23:34:55 -0800 Subject: [PATCH 0716/1179] Hyundai: clean up fingerprint test (#27079) * Clean up Hyundai test * fine --- selfdrive/car/hyundai/tests/test_hyundai.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index a52027f448..6ecfa03796 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -2,24 +2,19 @@ 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 +from selfdrive.car.hyundai.values import CANFD_CAR, FW_QUERY_CONFIG, FW_VERSIONS 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} + whitelisted_ecus = {ecu for r in FW_QUERY_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 = {fw[0] for fw in FW_VERSIONS[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}') From 845a63d884ae30f03831e112e636c8d3b06dcaeb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 25 Jan 2023 00:10:22 -0800 Subject: [PATCH 0717/1179] Honda: test all FW is in correct format (#27078) * test honda FW is expected * fix static --- selfdrive/car/honda/tests/test_honda.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 selfdrive/car/honda/tests/test_honda.py diff --git a/selfdrive/car/honda/tests/test_honda.py b/selfdrive/car/honda/tests/test_honda.py new file mode 100755 index 0000000000..7a8c86fb0a --- /dev/null +++ b/selfdrive/car/honda/tests/test_honda.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +import re +import unittest + +from selfdrive.car.honda.values import FW_VERSIONS + +HONDA_FW_VERSION_RE = br"\d{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$" + + +class TestHondaFingerprint(unittest.TestCase): + def test_fw_version_format(self): + # Asserts all FW versions follow an expected format + for fw_by_ecu in FW_VERSIONS.values(): + for fws in fw_by_ecu.values(): + for fw in fws: + self.assertTrue(re.match(HONDA_FW_VERSION_RE, fw) is not None, fw) + + +if __name__ == "__main__": + unittest.main() From 0756c7f374d26945ae27b0cfcabdede9f2060e87 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 25 Jan 2023 10:46:06 -0800 Subject: [PATCH 0718/1179] make process replay more reliable --- selfdrive/test/process_replay/process_replay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index a7d53bf9da..06af4469f2 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -568,7 +568,7 @@ def cpp_replay_process(cfg, lr, fingerprint=None): resp_sockets = cfg.pub_sub[msg.which()] if cfg.should_recv_callback is None else cfg.should_recv_callback(msg) for s in resp_sockets: - response = messaging.recv_one(sockets[s]) + response = messaging.recv_one_retry(sockets[s]) if response is None: print(f"Warning, no response received {i}") From 892835da7ad02d109794c5dc8e79ec938eebd572 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 26 Jan 2023 02:51:31 +0800 Subject: [PATCH 0719/1179] cabana: fix a wrong settings key (#27085) fix wrong key --- tools/cabana/settings.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 8c26b265e0..e06d149831 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -28,7 +28,7 @@ void Settings::save() { void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); - max_cached_minutes = s.value("cached_minutes", 5).toInt(); + max_cached_minutes = s.value("max_cached_minutes", 5).toInt(); chart_height = s.value("chart_height", 200).toInt(); chart_range = s.value("chart_range", 3 * 60).toInt(); chart_column_count = s.value("chart_column_count", 1).toInt(); From 2de2bab2864eeaea8104ac0cbb619c5c25b8b4d6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 26 Jan 2023 02:59:05 +0800 Subject: [PATCH 0720/1179] cabana: fix divde by zero for std::log10 (#27077) fix divde by zero for std::log10 --- tools/cabana/chartswidget.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 2965ae0476..5d0e5d7a52 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -332,6 +332,9 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { } qreal ChartView::getYAsixLabelWidth() const { + if (axis_y->max() <= axis_y->min() || axis_y->tickCount() <= 1) { + return 0; + } QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((axis_y->max() - axis_y->min()) / (axis_y->tickCount() - 1)))), 0) + 1; return qMax(fm.width(QString::number(axis_y->min(), 'f', n)), fm.width(QString::number(axis_y->max(), 'f', n))) + 20; From dd2e44232cfc3028d19875e971c6feb036ae6890 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 25 Jan 2023 19:18:24 -0800 Subject: [PATCH 0721/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 687676be40..ae051c94a3 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 687676be4025d9caf9520be89cb328d6a3cc3e10 +Subproject commit ae051c94a393550ab8d70c594fc9dfb49bc9aed8 From 3cd60a47244905c069de8bf0aa7a20b38b7ccb62 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 25 Jan 2023 20:21:14 -0800 Subject: [PATCH 0722/1179] Ford cleanup (#27090) * fordcan cleanup Co-authored-by: Cameron Clough * no fordcan Co-authored-by: Cameron Clough * more Co-authored-by: Cameron Clough * these weren't even used in CS, follow rest of the brands * we won't use this * rename to more standard powertrain can bus * no arguments for lka anymore * Revert "rename to more standard powertrain can bus" This reverts commit 0bc3f79f9bad2218c48a350bbf5ec6f726e0a028. Co-authored-by: Shane Smiskol --- selfdrive/car/ford/carcontroller.py | 23 +++++----- selfdrive/car/ford/carstate.py | 2 +- selfdrive/car/ford/fordcan.py | 66 +++++++++++++++-------------- selfdrive/car/ford/interface.py | 9 ++-- selfdrive/car/ford/values.py | 3 -- 5 files changed, 50 insertions(+), 53 deletions(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 8c391bb276..8164a8a970 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -2,7 +2,7 @@ import math from cereal import car from common.numpy_fast import clip, interp from opendbc.can.packer import CANPacker -from selfdrive.car.ford import fordcan +from selfdrive.car.ford.fordcan import create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, create_lka_msg, create_lkas_ui_msg from selfdrive.car.ford.values import CANBUS, CarControllerParams VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -46,16 +46,15 @@ class CarController: ### acc buttons ### if CC.cruiseControl.cancel: - can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, cancel=True)) - can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, cancel=True, bus=CANBUS.main)) + can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, cancel=True)) + can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, cancel=True, bus=CANBUS.main)) elif CC.cruiseControl.resume and (self.frame % CarControllerParams.BUTTONS_STEP) == 0: - can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, resume=True)) - can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, resume=True, bus=CANBUS.main)) + can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, resume=True)) + can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, resume=True, bus=CANBUS.main)) # if stock lane centering isn't off, send a button press to toggle it off # the stock system checks for steering pressed, and eventually disengages cruise control elif CS.acc_tja_status_stock_values["Tja_D_Stat"] != 0 and (self.frame % CarControllerParams.ACC_UI_STEP) == 0: - can_sends.append(fordcan.create_button_command(self.packer, CS.buttons_stock_values, tja_toggle=True)) - + can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, tja_toggle=True)) ### lateral control ### if CC.latActive: @@ -84,21 +83,19 @@ class CarController: precision = 1 # 0=Comfortable, 1=Precise (the stock system always uses comfortable) self.apply_angle_last = apply_angle - can_sends.append(fordcan.create_lka_command(self.packer, 0, 0)) - can_sends.append(fordcan.create_tja_command(self.packer, lca_rq, ramp_type, precision, - 0, path_angle, 0, 0)) - + can_sends.append(create_lka_msg(self.packer)) + can_sends.append(create_lat_ctl_msg(self.packer, lca_rq, ramp_type, precision, 0, path_angle, 0, 0)) ### ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) # send lkas ui command at 1Hz or if ui state changes if (self.frame % CarControllerParams.LKAS_UI_STEP) == 0 or send_ui: - can_sends.append(fordcan.create_lkas_ui_command(self.packer, main_on, CC.latActive, steer_alert, hud_control, CS.lkas_status_stock_values)) + can_sends.append(create_lkas_ui_msg(self.packer, main_on, CC.latActive, steer_alert, hud_control, CS.lkas_status_stock_values)) # send acc ui command at 20Hz or if ui state changes if (self.frame % CarControllerParams.ACC_UI_STEP) == 0 or send_ui: - can_sends.append(fordcan.create_acc_ui_command(self.packer, main_on, CC.latActive, hud_control, CS.acc_tja_status_stock_values)) + can_sends.append(create_acc_ui_msg(self.packer, main_on, CC.latActive, hud_control, CS.acc_tja_status_stock_values)) self.main_on_last = main_on self.lkas_enabled_last = CC.latActive diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 2276b1208a..215900fef6 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -118,7 +118,7 @@ class CarState(CarStateBase): ("DrStatRl_B_Actl", "BodyInfo_3_FD1"), # BCM Door open, rear left ("DrStatRr_B_Actl", "BodyInfo_3_FD1"), # BCM Door open, rear right ("FirstRowBuckleDriver", "RCMStatusMessage2_FD1"), # RCM Seatbelt status, driver - ("HeadLghtHiFlash_D_Stat", "Steering_Data_FD1"), # SCCM Passthru the remaining buttons + ("HeadLghtHiFlash_D_Stat", "Steering_Data_FD1"), # SCCM Passthrough the remaining buttons ("WiprFront_D_Stat", "Steering_Data_FD1"), ("LghtAmb_D_Sns", "Steering_Data_FD1"), ("AccButtnGapDecPress", "Steering_Data_FD1"), diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index 373ce096c6..af80894ff8 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -4,9 +4,9 @@ from selfdrive.car.ford.values import CANBUS HUDControl = car.CarControl.HUDControl -def create_lka_command(packer, angle_deg: float, curvature: float): +def create_lka_msg(packer): """ - Creates a CAN message for the Ford LKAS Command. + Creates a CAN message for the Ford LKA Command. This command can apply "Lane Keeping Aid" manoeuvres, which are subject to the PSCM lockout. @@ -16,52 +16,54 @@ def create_lka_command(packer, angle_deg: float, curvature: float): values = { "LkaDrvOvrrd_D_Rq": 0, # driver override level? [0|3] "LkaActvStats_D2_Req": 0, # action [0|7] - "LaRefAng_No_Req": angle_deg, # angle [-102.4|102.3] degrees + "LaRefAng_No_Req": 0, # angle [-102.4|102.3] degrees "LaRampType_B_Req": 0, # Ramp speed: 0=Smooth, 1=Quick - "LaCurvature_No_Calc": curvature, # curvature [-0.01024|0.01023] 1/meter + "LaCurvature_No_Calc": 0, # curvature [-0.01024|0.01023] 1/meter "LdwActvStats_D_Req": 0, # LDW status [0|7] "LdwActvIntns_D_Req": 0, # LDW intensity [0|3], shake alert strength } return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, values) -def create_tja_command(packer, lca_rq: int, ramp_type: int, precision: int, path_offset: float, path_angle: float, curvature_rate: float, curvature: float): +def create_lat_ctl_msg(packer, lca_rq: int, ramp_type: int, precision: int, path_offset: float, path_angle: float, + curvature: float, curvature_rate: float): """ Creates a CAN message for the Ford TJA/LCA Command. - This command can apply "Lane Centering" manoeuvres: continuous lane centering for traffic jam - assist and highway driving. It is not subject to the PSCM lockout. + This command can apply "Lane Centering" manoeuvres: continuous lane centering for traffic jam assist and highway + driving. It is not subject to the PSCM lockout. - Ford lane centering command uses a third order polynomial to describe the road centerline. The - polynomial is defined by the following coefficients: - c0: lateral offset between the vehicle and the centerline - c1: heading angle between the vehicle and the centerline - c2: curvature of the centerline + Ford lane centering command uses a third order polynomial to describe the road centerline. The polynomial is defined + by the following coefficients: + c0: lateral offset between the vehicle and the centerline (positive is right) + c1: heading angle between the vehicle and the centerline (positive is right) + c2: curvature of the centerline (positive is left) c3: rate of change of curvature of the centerline - As the PSCM combines this information with other sensor data, such as the vehicle's yaw rate and - speed, the steering angle cannot be easily controlled. + As the PSCM combines this information with other sensor data, such as the vehicle's yaw rate and speed, the steering + angle cannot be easily controlled. - The PSCM should be configured to accept TJA/LCA commands before these commands will be processed. - This can be done using tools such as Forscan. + The PSCM should be configured to accept TJA/LCA commands before these commands will be processed. This can be done + using tools such as Forscan. Frequency is 20Hz. """ values = { - "LatCtlRng_L_Max": 0, # Unknown [0|126] meter - "HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1] - "LatCtl_D_Rq": lca_rq, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft, 3=InterventionRight, 4-7=NotUsed [0|7] - "LatCtlRampType_D_Rq": ramp_type, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] - "LatCtlPrecision_D_Rq": precision, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] - "LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter - "LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians - "LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2 - "LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter + "LatCtlRng_L_Max": 0, # Unknown [0|126] meter + "HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1] + "LatCtl_D_Rq": lca_rq, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft, + # 3=InterventionRight, 4-7=NotUsed [0|7] + "LatCtlRampType_D_Rq": ramp_type, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] + "LatCtlPrecision_D_Rq": precision, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] + "LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter + "LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians + "LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2 + "LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter } return packer.make_can_msg("LateralMotionControl", CANBUS.main, values) -def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bool, hud_control, stock_values: dict): +def create_lkas_ui_msg(packer, main_on: bool, enabled: bool, steer_alert: bool, hud_control, stock_values: dict): """ Creates a CAN message for the Ford IPC IPMA/LKAS status. @@ -107,16 +109,15 @@ def create_lkas_ui_command(packer, main_on: bool, enabled: bool, steer_alert: bo values = { **stock_values, - "LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31] - "LaHandsOff_D_Dsply": hands_on_wheel_dsply, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed + "LaActvStats_D_Dsply": lines, # LKAS status (lines) [0|31] + "LaHandsOff_D_Dsply": hands_on_wheel_dsply, # 0=HandsOn, 1=Level1 (w/o chime), 2=Level2 (w/ chime), 3=Suppressed } return packer.make_can_msg("IPMA_Data", CANBUS.main, values) -def create_acc_ui_command(packer, main_on: bool, enabled: bool, hud_control, stock_values: dict): +def create_acc_ui_msg(packer, main_on: bool, enabled: bool, hud_control, stock_values: dict): """ - Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam - assist status. + Creates a CAN message for the Ford IPC adaptive cruise, forward collision warning and traffic jam assist status. Stock functionality is maintained by passing through unmodified signals. @@ -148,7 +149,8 @@ def create_acc_ui_command(packer, main_on: bool, enabled: bool, hud_control, sto return packer.make_can_msg("ACCDATA_3", CANBUS.main, values) -def create_button_command(packer, stock_values: dict, cancel = False, resume = False, tja_toggle = False, bus: int = CANBUS.camera): +def create_button_msg(packer, stock_values: dict, cancel=False, resume=False, tja_toggle=False, + bus: int = CANBUS.camera): """ Creates a CAN message for the Ford SCCM buttons/switches. diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index f3d77bc05a..b0e97677b5 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -2,10 +2,11 @@ from cereal import car from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, get_safety_config -from selfdrive.car.ford.values import CAR, Ecu, TransmissionType, GearShifter +from selfdrive.car.ford.values import CAR, Ecu from selfdrive.car.interfaces import CarInterfaceBase -CarParams = car.CarParams +TransmissionType = car.CarParams.TransmissionType +GearShifter = car.CarState.GearShifter class CarInterface(CarInterfaceBase): @@ -13,10 +14,10 @@ class CarInterface(CarInterfaceBase): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "ford" ret.dashcamOnly = True - ret.safetyConfigs = [get_safety_config(CarParams.SafetyModel.ford)] + ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.ford)] # Angle-based steering - ret.steerControlType = CarParams.SteerControlType.angle + ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerActuatorDelay = 0.4 ret.steerLimitTimer = 1.0 diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 0e6ef464b3..87cb98878d 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -9,9 +9,6 @@ from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu -TransmissionType = car.CarParams.TransmissionType -GearShifter = car.CarState.GearShifter - AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_points']) From d410206f14fc7a0207464905a1ff2f684bd3ed39 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 25 Jan 2023 20:56:03 -0800 Subject: [PATCH 0723/1179] Ford: add Bronco Sport 2021-22 (#27092) * cleanup * add Ford Bronco Sport 2021 fw VIN: 3FMCR9B61MRA17853 62241b0c7fea4589|2022-10-25--13-40-05--0 * add test route * add Ford Bronco Sport 2022 fw VIN: 3FMCR9B69NRD15990 54827bf84c38b14f|2023-01-23--14-58-23--0 --- selfdrive/car/ford/interface.py | 12 +++++++++--- selfdrive/car/ford/values.py | 26 +++++++++++++++++++++++++ selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index b0e97677b5..3139aec9b1 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -13,15 +13,21 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "ford" - ret.dashcamOnly = True ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.ford)] - # Angle-based steering + # These cars are dashcam only until the port is finished + ret.dashcamOnly = True + ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerActuatorDelay = 0.4 ret.steerLimitTimer = 1.0 - if candidate == CAR.ESCAPE_MK4: + if candidate == CAR.BRONCO_SPORT_MK1: + ret.wheelbase = 2.67 + ret.steerRatio = 17.7 # learned + ret.mass = 1625 + STD_CARGO_KG + + elif candidate == CAR.ESCAPE_MK4: ret.wheelbase = 2.71 ret.steerRatio = 14.3 # Copied from Focus ret.mass = 1750 + STD_CARGO_KG diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 87cb98878d..0124a9134f 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -40,6 +40,7 @@ class CANBUS: class CAR: + BRONCO_SPORT_MK1 = "FORD BRONCO SPORT 1ST GEN" ESCAPE_MK4 = "FORD ESCAPE 4TH GEN" EXPLORER_MK6 = "FORD EXPLORER 6TH GEN" FOCUS_MK4 = "FORD FOCUS 4TH GEN" @@ -60,6 +61,7 @@ class FordCarInfo(CarInfo): CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { + CAR.BRONCO_SPORT_MK1: FordCarInfo("Ford Bronco Sport 2021-22"), CAR.ESCAPE_MK4: [ FordCarInfo("Ford Escape 2020-21"), FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"), @@ -85,6 +87,30 @@ FW_QUERY_CONFIG = FwQueryConfig( ) FW_VERSIONS = { + CAR.BRONCO_SPORT_MK1: { + (Ecu.eps, 0x730, None): [ + b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6C-14D003-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.abs, 0x760, None): [ + b'LX6C-2D053-RD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6C-2D053-RE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x764, None): [ + b'LB5T-14D049-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x706, None): [ + b'M1PT-14F397-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x7E0, None): [ + b'M1PA-14C204-GF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'N1PA-14C204-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.shiftByWire, 0x732, None): [ + b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'PZ1P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + }, CAR.ESCAPE_MK4: { (Ecu.eps, 0x730, None): [ b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 29cea9c030..3e0a95a38f 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -42,6 +42,7 @@ routes = [ CarTestRoute("221c253375af4ee9|2022-06-15--18-38-24", CHRYSLER.RAM_1500), CarTestRoute("8fb5eabf914632ae|2022-08-04--17-28-53", CHRYSLER.RAM_HD, segment=6), + CarTestRoute("54827bf84c38b14f|2023-01-25--14-14-11", FORD.BRONCO_SPORT_MK1), CarTestRoute("62241b0c7fea4589|2022-09-01--15-32-49", FORD.EXPLORER_MK6), #TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 6238c6ff99..1506b4176f 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -12,6 +12,7 @@ TESLA AP1 MODEL S: [.nan, 2.5, .nan] TESLA AP2 MODEL S: [.nan, 2.5, .nan] # Guess +FORD BRONCO SPORT 1ST GEN: [.nan, 1.5, .nan] FORD ESCAPE 4TH GEN: [.nan, 1.5, .nan] FORD EXPLORER 6TH GEN: [.nan, 1.5, .nan] FORD FOCUS 4TH GEN: [.nan, 1.5, .nan] From 23298615561b5c8d41df009ba27ac01845c2abe5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 25 Jan 2023 21:01:32 -0800 Subject: [PATCH 0724/1179] Ford: send empty LKA message (#27094) Eradication --- selfdrive/car/ford/fordcan.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index af80894ff8..c3f6e74651 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -6,23 +6,14 @@ HUDControl = car.CarControl.HUDControl def create_lka_msg(packer): """ - Creates a CAN message for the Ford LKA Command. + Creates an empty CAN message for the Ford LKA Command. This command can apply "Lane Keeping Aid" manoeuvres, which are subject to the PSCM lockout. Frequency is 20Hz. """ - values = { - "LkaDrvOvrrd_D_Rq": 0, # driver override level? [0|3] - "LkaActvStats_D2_Req": 0, # action [0|7] - "LaRefAng_No_Req": 0, # angle [-102.4|102.3] degrees - "LaRampType_B_Req": 0, # Ramp speed: 0=Smooth, 1=Quick - "LaCurvature_No_Calc": 0, # curvature [-0.01024|0.01023] 1/meter - "LdwActvStats_D_Req": 0, # LDW status [0|7] - "LdwActvIntns_D_Req": 0, # LDW intensity [0|3], shake alert strength - } - return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, values) + return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {}) def create_lat_ctl_msg(packer, lca_rq: int, ramp_type: int, precision: int, path_offset: float, path_angle: float, From cf69653440a308c6e7abb7d56847b389b64c819f Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 25 Jan 2023 21:18:35 -0800 Subject: [PATCH 0725/1179] Ford: add Maverick 2022 (#27093) * Ford: add Maverick 2022 VIN: 3FTTW8E36NRA74219 a6427650bff6b419|2022-09-19--10-51-30 * Ford: add missing Maverick 2022 FW VIN: 3FTTW8F98NRA75889 c845bd8c366e6f3d|2022-12-03--18-57-00--0 * steer ratio --- selfdrive/car/ford/interface.py | 5 +++++ selfdrive/car/ford/values.py | 23 +++++++++++++++++++++++ selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 4 files changed, 30 insertions(+) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 3139aec9b1..ce4e3e30aa 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -42,6 +42,11 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 13.8 # learned ret.mass = 1350 + STD_CARGO_KG + elif candidate == CAR.MAVERICK_MK1: + ret.wheelbase = 3.076 + ret.steerRatio = 17.0 + ret.mass = 1650 + STD_CARGO_KG + else: raise ValueError(f"Unsupported car: {candidate}") diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 0124a9134f..1348073801 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -44,6 +44,7 @@ class CAR: ESCAPE_MK4 = "FORD ESCAPE 4TH GEN" EXPLORER_MK6 = "FORD EXPLORER 6TH GEN" FOCUS_MK4 = "FORD FOCUS 4TH GEN" + MAVERICK_MK1 = "FORD MAVERICK 1ST GEN" class RADAR: @@ -68,6 +69,7 @@ CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { ], CAR.EXPLORER_MK6: FordCarInfo("Ford Explorer 2020-22"), CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2019", "Driver Assistance Pack"), + CAR.MAVERICK_MK1: FordCarInfo("Ford Maverick 2022", "Co-Pilot360 Assist"), } FW_QUERY_CONFIG = FwQueryConfig( @@ -186,4 +188,25 @@ FW_VERSIONS = { (Ecu.shiftByWire, 0x732, None): [ ], }, + CAR.MAVERICK_MK1: { + (Ecu.eps, 0x730, None): [ + b'NZ6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.abs, 0x760, None): [ + b'NZ6C-2D053-AG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x764, None): [ + b'NZ6T-14D049-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x706, None): [ + b'NZ6T-14F397-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x7E0, None): [ + b'NZ6A-14C204-PA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'NZ6A-14C204-ZA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.shiftByWire, 0x732, None): [ + b'NZ6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + }, } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 3e0a95a38f..d1b73afcf6 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -18,6 +18,7 @@ from selfdrive.car.body.values import CAR as COMMA non_tested_cars = [ FORD.ESCAPE_MK4, FORD.FOCUS_MK4, + FORD.MAVERICK_MK1, GM.CADILLAC_ATS, GM.HOLDEN_ASTRA, GM.MALIBU, diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 1506b4176f..733aa34343 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -16,6 +16,7 @@ FORD BRONCO SPORT 1ST GEN: [.nan, 1.5, .nan] FORD ESCAPE 4TH GEN: [.nan, 1.5, .nan] FORD EXPLORER 6TH GEN: [.nan, 1.5, .nan] FORD FOCUS 4TH GEN: [.nan, 1.5, .nan] +FORD MAVERICK 1ST GEN: [.nan, 1.5, .nan] ### # No steering wheel From 2bdce2d92ec859398aaa749037d1fa58d3b5eec7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 25 Jan 2023 21:39:46 -0800 Subject: [PATCH 0726/1179] Ford: use curvature signal for lateral control (#27091) * do carcontroller Co-authored-by: Cameron Clough * values done * just send latActive in, cleaner * Update selfdrive/car/ford/values.py * fix a crash * adjust ramp as well Co-authored-by: Cameron Clough --- selfdrive/car/ford/carcontroller.py | 49 ++++++++++------------------- selfdrive/car/ford/fordcan.py | 4 +-- selfdrive/car/ford/values.py | 13 ++++---- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 8164a8a970..99a6648ff9 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -1,28 +1,14 @@ import math from cereal import car -from common.numpy_fast import clip, interp +from common.numpy_fast import clip from opendbc.can.packer import CANPacker +from selfdrive.car import apply_std_steer_angle_limits from selfdrive.car.ford.fordcan import create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, create_lka_msg, create_lkas_ui_msg from selfdrive.car.ford.values import CANBUS, CarControllerParams VisualAlert = car.CarControl.HUDControl.VisualAlert -def apply_ford_steer_angle_limits(apply_angle, apply_angle_last, vEgo): - # rate limit - steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last) - rate_limit = CarControllerParams.RATE_LIMIT_UP if steer_up else CarControllerParams.RATE_LIMIT_DOWN - max_angle_diff = interp(vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points) - apply_angle = clip(apply_angle, (apply_angle_last - max_angle_diff), (apply_angle_last + max_angle_diff)) - - # absolute limit (LatCtlPath_An_Actl) - apply_path_angle = math.radians(apply_angle) / CarControllerParams.LKAS_STEER_RATIO - apply_path_angle = clip(apply_path_angle, -0.5, 0.5235) - apply_angle = math.degrees(apply_path_angle) * CarControllerParams.LKAS_STEER_RATIO - - return apply_angle - - class CarController: def __init__(self, dbc_name, CP, VM): self.CP = CP @@ -30,7 +16,7 @@ class CarController: self.packer = CANPacker(dbc_name) self.frame = 0 - self.apply_angle_last = 0 + self.apply_curvature_last = 0 self.main_on_last = False self.lkas_enabled_last = False self.steer_alert_last = False @@ -57,34 +43,33 @@ class CarController: can_sends.append(create_button_msg(self.packer, CS.buttons_stock_values, tja_toggle=True)) ### lateral control ### - if CC.latActive: - lca_rq = 1 - apply_angle = apply_ford_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo) - else: - lca_rq = 0 - apply_angle = 0. - # send steering commands at 20Hz if (self.frame % CarControllerParams.STEER_STEP) == 0: - # use LatCtlPath_An_Actl to actuate steering - path_angle = math.radians(apply_angle) / CarControllerParams.LKAS_STEER_RATIO + if CC.latActive: + # apply limits to curvature + apply_curvature = -self.VM.calc_curvature(math.radians(actuators.steeringAngleDeg), CS.out.vEgo, 0.0) + apply_curvature = apply_std_steer_angle_limits(apply_curvature, self.apply_curvature_last, CS.out.vEgo, CarControllerParams) + # clip to signal range + apply_curvature = clip(apply_curvature, -CarControllerParams.CURVATURE_MAX, CarControllerParams.CURVATURE_MAX) + else: + apply_curvature = 0. # set slower ramp type when small steering angle change # 0=Slow, 1=Medium, 2=Fast, 3=Immediately steer_change = abs(CS.out.steeringAngleDeg - actuators.steeringAngleDeg) - if steer_change < 2.0: + if steer_change < 2.5: ramp_type = 0 - elif steer_change < 4.0: + elif steer_change < 5.0: ramp_type = 1 - elif steer_change < 6.0: + elif steer_change < 7.5: ramp_type = 2 else: ramp_type = 3 precision = 1 # 0=Comfortable, 1=Precise (the stock system always uses comfortable) - self.apply_angle_last = apply_angle + self.apply_curvature_last = apply_curvature can_sends.append(create_lka_msg(self.packer)) - can_sends.append(create_lat_ctl_msg(self.packer, lca_rq, ramp_type, precision, 0, path_angle, 0, 0)) + can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, ramp_type, precision, 0., 0., -apply_curvature, 0.)) ### ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) @@ -102,7 +87,7 @@ class CarController: self.steer_alert_last = steer_alert new_actuators = actuators.copy() - new_actuators.steeringAngleDeg = self.apply_angle_last + new_actuators.curvature = self.apply_curvature_last self.frame += 1 return new_actuators, can_sends diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index c3f6e74651..dcda59bce2 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -16,7 +16,7 @@ def create_lka_msg(packer): return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {}) -def create_lat_ctl_msg(packer, lca_rq: int, ramp_type: int, precision: int, path_offset: float, path_angle: float, +def create_lat_ctl_msg(packer, lat_active: bool, ramp_type: int, precision: int, path_offset: float, path_angle: float, curvature: float, curvature_rate: float): """ Creates a CAN message for the Ford TJA/LCA Command. @@ -42,7 +42,7 @@ def create_lat_ctl_msg(packer, lca_rq: int, ramp_type: int, precision: int, path values = { "LatCtlRng_L_Max": 0, # Unknown [0|126] meter "HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1] - "LatCtl_D_Rq": lca_rq, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft, + "LatCtl_D_Rq": 1 if lat_active else 0, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft, # 3=InterventionRight, 4-7=NotUsed [0|7] "LatCtlRampType_D_Rq": ramp_type, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] "LatCtlPrecision_D_Rq": precision, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 1348073801..550224e791 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -9,7 +9,7 @@ from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu -AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_points']) +CurvatureLimit = namedtuple('CurvatureLimit', ['speed_points', 'max_angle_diff_points']) class CarControllerParams: @@ -22,12 +22,13 @@ class CarControllerParams: # Message: Steering_Data_FD1, but send twice as fast BUTTONS_STEP = 10 / 2 - LKAS_STEER_RATIO = 2.75 # Approximate ratio between LatCtlPath_An_Actl and steering angle in radians - # TODO: remove this once we understand how the EPS calculates the steering angle better - STEER_DRIVER_ALLOWANCE = 0.8 # Driver intervention threshold in Nm + CURVATURE_MAX = 0.02 # Max curvature for steering command, m^-1 + STEER_DRIVER_ALLOWANCE = 0.8 # Driver intervention threshold, Nm - RATE_LIMIT_UP = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., .8, .15]) - RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) + # Curvature rate limits + # TODO: unify field names used by curvature and angle control cars + ANGLE_RATE_LIMIT_UP = CurvatureLimit(speed_points=[5, 15, 25], max_angle_diff_points=[0.005, 0.00056, 0.0002]) + ANGLE_RATE_LIMIT_DOWN = CurvatureLimit(speed_points=[5, 15, 25], max_angle_diff_points=[0.008, 0.00089, 0.00032]) def __init__(self, CP): pass From e90571eea1c4be8de848b043ada7f9812a9754a7 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 25 Jan 2023 21:42:24 -0800 Subject: [PATCH 0727/1179] Ford: disable radar parser (#27096) The radar parser caused many false positive FCWs. --- selfdrive/car/ford/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 550224e791..2ae0d3643e 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -53,7 +53,7 @@ class RADAR: DELPHI_MRR = 'FORD_CADS' -DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", RADAR.DELPHI_MRR)) +DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", None)) @dataclass From c7790d0e071255ca304638877e0f45edd6a9d372 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 25 Jan 2023 22:03:00 -0800 Subject: [PATCH 0728/1179] Ford: params fixup (#27097) * reduce steer actuator delay to 0.25s * update steer ratio --- selfdrive/car/ford/interface.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index ce4e3e30aa..cea39d8b00 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -19,27 +19,27 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = True ret.steerControlType = car.CarParams.SteerControlType.angle - ret.steerActuatorDelay = 0.4 + ret.steerActuatorDelay = 0.25 ret.steerLimitTimer = 1.0 if candidate == CAR.BRONCO_SPORT_MK1: ret.wheelbase = 2.67 - ret.steerRatio = 17.7 # learned + ret.steerRatio = 17.7 ret.mass = 1625 + STD_CARGO_KG elif candidate == CAR.ESCAPE_MK4: ret.wheelbase = 2.71 - ret.steerRatio = 14.3 # Copied from Focus + ret.steerRatio = 16.7 ret.mass = 1750 + STD_CARGO_KG elif candidate == CAR.EXPLORER_MK6: ret.wheelbase = 3.025 - ret.steerRatio = 16.8 # learned + ret.steerRatio = 16.8 ret.mass = 2050 + STD_CARGO_KG elif candidate == CAR.FOCUS_MK4: ret.wheelbase = 2.7 - ret.steerRatio = 13.8 # learned + ret.steerRatio = 15.0 ret.mass = 1350 + STD_CARGO_KG elif candidate == CAR.MAVERICK_MK1: From 71c21eff724c1ab6cbba955d572b916612615551 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 25 Jan 2023 22:03:41 -0800 Subject: [PATCH 0729/1179] Ford: add missing Maverick 2022 XLT FW (#27098) Ford: add Maverick 2022 XLT fw VIN: `3FTTW8E39NRB00148` 933ad9d04ac82693|2023-01-04--17-31-33--0 --- selfdrive/car/ford/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 2ae0d3643e..acb625b7cc 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -203,6 +203,7 @@ FW_VERSIONS = { b'NZ6T-14F397-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7E0, None): [ + b'NZ6A-14C204-AAA\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NZ6A-14C204-PA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NZ6A-14C204-ZA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], From c7c0f1e33c46d0ffbf3f748c108b5ebca559c00d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 00:37:13 -0800 Subject: [PATCH 0730/1179] Ford: fix curvature rate limits --- selfdrive/car/ford/values.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index acb625b7cc..dc0f4bbb2e 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -4,12 +4,11 @@ from enum import Enum from typing import Dict, List, Union from cereal import car -from selfdrive.car import dbc_dict +from selfdrive.car import AngleRateLimit, dbc_dict from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries Ecu = car.CarParams.Ecu -CurvatureLimit = namedtuple('CurvatureLimit', ['speed_points', 'max_angle_diff_points']) class CarControllerParams: @@ -27,8 +26,8 @@ class CarControllerParams: # Curvature rate limits # TODO: unify field names used by curvature and angle control cars - ANGLE_RATE_LIMIT_UP = CurvatureLimit(speed_points=[5, 15, 25], max_angle_diff_points=[0.005, 0.00056, 0.0002]) - ANGLE_RATE_LIMIT_DOWN = CurvatureLimit(speed_points=[5, 15, 25], max_angle_diff_points=[0.008, 0.00089, 0.00032]) + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.005, 0.00056, 0.0002]) + ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.008, 0.00089, 0.00032]) def __init__(self, CP): pass From ad6ee2669cb41d20b691b3c139bd04beb60290ce Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 00:47:29 -0800 Subject: [PATCH 0731/1179] fix static analysis --- selfdrive/car/ford/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index dc0f4bbb2e..b93be61448 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -1,4 +1,4 @@ -from collections import defaultdict, namedtuple +from collections import defaultdict from dataclasses import dataclass from enum import Enum from typing import Dict, List, Union From 4d231a9d96a54ba0ed163e4aa487876f811a97cb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 00:48:59 -0800 Subject: [PATCH 0732/1179] Ram 1500: more generic EPS steer to zero check (#27086) more generic check --- selfdrive/car/chrysler/interface.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 2f058165ac..c8504d6fb1 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -58,9 +58,9 @@ class CarInterface(CarInterfaceBase): ret.mass = 2493. + STD_CARGO_KG CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) ret.minSteerSpeed = 14.5 - for fw in car_fw: - if fw.ecu == 'eps' and fw.fwVersion.startswith((b"68312176", b"68273275")): - ret.minSteerSpeed = 0. + # Older EPS FW allow steer to zero + if any(fw.ecu == 'eps' and fw.fwVersion[:4] <= b"6831" for fw in car_fw): + ret.minSteerSpeed = 0. elif candidate == CAR.RAM_HD: ret.steerActuatorDelay = 0.2 From 1d5d57a3847285af4bcce934dad49ffa65397fc1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 27 Jan 2023 03:02:17 +0800 Subject: [PATCH 0733/1179] cabana: fix video_splitter created twice (#27101) --- tools/cabana/mainwin.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index bd32cfdfcc..1468073017 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -121,8 +121,6 @@ void MainWindow::createDockWindows() { charts_layout->setContentsMargins(0, 0, 0, 0); charts_layout->addWidget(charts_widget); - video_splitter = new QSplitter(Qt::Vertical,this); - // splitter between video and charts video_splitter = new QSplitter(Qt::Vertical, this); video_widget = new VideoWidget(this); From e90c7a487b109aba0a0856f0c1b586ab0900bdfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Chybicki?= Date: Thu, 26 Jan 2023 21:30:46 +0100 Subject: [PATCH 0734/1179] Santa Fe HEV 2022: add missing FW versions (#27050) * Santa Fe Hev 2022 Fingerprint * Concatenated second value for transmission * fixes Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index b3cb46699a..dbac8033d8 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -766,19 +766,23 @@ FW_VERSIONS = { }, CAR.SANTA_FE_HEV_2022: { (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\x8799110CL500\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ', + b'\xf1\x00TMhe SCC FHCUP 1.00 1.00 99110-CL500 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00TM MDPS C 1.00 1.02 56310-CLAC0 4TSHC102', + b'\xf1\x00TM MDPS R 1.00 1.05 57700-CL000 4TSHP105', ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00TMH MFC AT EUR LHD 1.00 1.06 99211-S1500 220727', b'\xf1\x00TMH MFC AT USA LHD 1.00 1.03 99211-S1500 210224', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00PSBG2333 E16\x00\x00\x00\x00\x00\x00\x00TTM2H16UA3I\x94\xac\x8f', b'\xf1\x87959102T250\x00\x00\x00\x00\x00\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00PSBG2333 E14\x00\x00\x00\x00\x00\x00\x00TTM2H16SA2\x80\xd7l\xb2', ], (Ecu.engine, 0x7e0, None): [ b'\xf1\x87391312MTC1', + b'\xf1\x87391312MTE0', ], }, CAR.SANTA_FE_PHEV_2022: { From 27e8f8ff3e3336fe4d5737cf7c766d16725706bc Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 27 Jan 2023 04:32:25 +0800 Subject: [PATCH 0735/1179] cabana: improve detail view (#27099) * improve detailview * cleanup layout --- tools/cabana/detailwidget.cc | 39 ++++++++++++++++-------------------- tools/cabana/detailwidget.h | 2 +- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 7f59087643..233bc493df 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -19,7 +19,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QWidget *main_widget = new QWidget(this); QVBoxLayout *main_layout = new QVBoxLayout(main_widget); main_layout->setContentsMargins(0, 0, 0, 0); - main_layout->setSpacing(0); // tabbar tabbar = new QTabBar(this); @@ -29,10 +28,6 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tabbar->setContextMenuPolicy(Qt::CustomContextMenu); main_layout->addWidget(tabbar); - QFrame *title_frame = new QFrame(this); - QVBoxLayout *frame_layout = new QVBoxLayout(title_frame); - title_frame->setFrameShape(QFrame::StyledPanel); - // message title toolbar = new QToolBar(this); toolbar->setIconSize({16, 16}); @@ -48,21 +43,15 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart toolbar->addAction(bootstrapPixmap("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); remove_msg_act = toolbar->addAction(bootstrapPixmap("x-lg"), "", this, &DetailWidget::removeMsg); remove_msg_act->setToolTip(tr("Remove Message")); - toolbar->setVisible(false); - frame_layout->addWidget(toolbar); + main_layout->addWidget(toolbar); // warning warning_widget = new QWidget(this); QHBoxLayout *warning_hlayout = new QHBoxLayout(warning_widget); - warning_hlayout->setContentsMargins(0, 0, 0, 0); - QLabel *warning_icon = new QLabel(this); - warning_icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxWarning).scaledToWidth(24, Qt::SmoothTransformation)); - warning_hlayout->addWidget(warning_icon, 0, Qt::AlignTop); - warning_label = new QLabel(this); - warning_hlayout->addWidget(warning_label, 1, Qt::AlignLeft); + warning_hlayout->addWidget(warning_icon = new QLabel(this), 0, Qt::AlignTop); + warning_hlayout->addWidget(warning_label = new QLabel(this), 1, Qt::AlignLeft); warning_widget->hide(); - frame_layout->addWidget(warning_widget); - main_layout->addWidget(title_frame); + main_layout->addWidget(warning_widget); // msg widget QWidget *msg_widget = new QWidget(this); @@ -85,9 +74,9 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget = new QTabWidget(this); tab_widget->setTabPosition(QTabWidget::South); - tab_widget->addTab(scroll, "&Msg"); + tab_widget->addTab(scroll, bootstrapPixmap("file-earmark-ruled"), "&Msg"); history_log = new LogsWidget(this); - tab_widget->addTab(history_log, "&Logs"); + tab_widget->addTab(history_log, bootstrapPixmap("stopwatch"), "&Logs"); main_layout->addWidget(tab_widget); stacked_layout = new QStackedLayout(this); @@ -174,8 +163,14 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { form->setChartOpened(charts->hasSignal(msg_id, sig)); ++i; } - if (msg->size != can->lastMessage(msg_id).dat.size()) + if (msg->size != can->lastMessage(msg_id).dat.size()) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); + } + for (auto s : binary_view->getOverlappingSignals()) { + warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); + } + } else { + warnings.push_back(tr("Drag-Select in binary view to create new signal.")); } for (/**/; i < signal_list.size(); ++i) signal_list[i]->hide(); @@ -184,10 +179,10 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { remove_msg_act->setEnabled(msg != nullptr); name_label->setText(msgName(msg_id)); - for (auto s : binary_view->getOverlappingSignals()) - warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); - - warning_label->setText(warnings.join('\n')); + if (!warnings.isEmpty()) { + warning_label->setText(warnings.join('\n')); + warning_icon->setPixmap(bootstrapPixmap(msg ? "exclamation-triangle" : "info-circle")); + } warning_widget->setVisible(!warnings.isEmpty()); setUpdatesEnabled(true); } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index b07629084a..c59a6fca50 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -47,7 +47,7 @@ private: void updateState(const QHash * msgs = nullptr); QString msg_id; - QLabel *name_label, *time_label, *warning_label; + QLabel *name_label, *time_label, *warning_icon, *warning_label; QWidget *warning_widget; QVBoxLayout *signals_layout; QTabBar *tabbar; From 0f37ff6c0284b91881984ce5cf2d74c48bdf7e68 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 27 Jan 2023 04:37:04 +0800 Subject: [PATCH 0736/1179] cabana: cleanup historylog and fix some known issues (#27100) improve history logs --- tools/cabana/historylog.cc | 152 +++++++++++-------------------------- tools/cabana/historylog.h | 35 +++------ 2 files changed, 58 insertions(+), 129 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 4a975afc4d..970aafd342 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -1,30 +1,20 @@ #include "tools/cabana/historylog.h" -#include #include #include #include // HistoryLogModel -void HistoryLogModel::setDisplayType(HistoryLogModel::DisplayType type) { - if (display_type != type) { - display_type = type; - refresh(); - } -} - QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { - const bool display_signals = display_type == HistoryLogModel::Signals; + const bool show_signals = display_signals_mode && sigs.size() > 0; const auto &m = messages[index.row()]; if (role == Qt::DisplayRole) { if (index.column() == 0) { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } - return display_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); - } else if (role == Qt::ToolTipRole && index.column() > 0 && display_signals) { - return tr("double click to open the chart"); - } else if (role == Qt::UserRole && index.column() == 1 && !display_signals) { + return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); + } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { return HexColors::toVariantList(m.colors); } return {}; @@ -36,7 +26,6 @@ void HistoryLogModel::setMessage(const QString &message_id) { if (auto dbc_msg = dbc()->msg(msg_id)) { sigs = dbc_msg->getSignals(); } - display_type = !sigs.empty() ? HistoryLogModel::Signals : HistoryLogModel::Hex; filter_cmp = nullptr; refresh(); } @@ -51,17 +40,15 @@ void HistoryLogModel::refresh() { } QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, int role) const { - const bool display_signals = display_type == HistoryLogModel::Signals && !sigs.empty(); if (orientation == Qt::Horizontal) { + const bool show_signals = display_signals_mode && !sigs.empty(); if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { if (section == 0) { return "Time"; } - return display_signals ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; - } else if (role == Qt::BackgroundRole && section > 0 && display_signals) { + return show_signals ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; + } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { return QBrush(QColor(getColor(section - 1))); - } else if (role == Qt::ForegroundRole && section > 0 && display_signals) { - return QBrush(Qt::black); } } return {}; @@ -72,6 +59,11 @@ void HistoryLogModel::setDynamicMode(int state) { refresh(); } +void HistoryLogModel::setDisplayType(int type) { + display_signals_mode = type == 0; + refresh(); +} + void HistoryLogModel::segmentsMerged() { if (!dynamic_mode) { has_more_data = true; @@ -114,7 +106,7 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) { } void HistoryLogModel::updateColors() { - if (display_type == HistoryLogModel::Hex) { + if (!display_signals_mode || sigs.empty()) { const auto freq = can->lastMessage(msg_id).freq; if (dynamic_mode) { for (auto it = messages.rbegin(); it != messages.rend(); ++it) { @@ -162,10 +154,9 @@ template std::deque HistoryLogModel::fetchData<>(std:: std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { auto events = can->events(); if (dynamic_mode) { - auto it = std::lower_bound(events->rbegin(), events->rend(), from_time, [=](auto &e, uint64_t ts) { - return e->mono_time > ts; + auto it = std::upper_bound(events->rbegin(), events->rend(), from_time, [=](uint64_t ts, auto &e) { + return e->mono_time < ts; }); - if (it != events->rend()) ++it; return fetchData(it, events->rend(), min_time); } else { assert(min_time == 0); @@ -189,128 +180,77 @@ QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { auto bg_role = model()->headerData(logicalIndex, Qt::Horizontal, Qt::BackgroundRole); if (bg_role.isValid()) { - QPen pen(model()->headerData(logicalIndex, Qt::Horizontal, Qt::ForegroundRole).value(), 1); - painter->setPen(pen); painter->fillRect(rect, bg_role.value()); } QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString(); painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text); } -// HistoryLog - -HistoryLog::HistoryLog(QWidget *parent) : QTableView(parent) { - setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); - horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); - horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - verticalHeader()->setVisible(false); - setItemDelegateForColumn(1, new MessageBytesDelegate(this)); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); -} - // LogsWidget LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); QHBoxLayout *h = new QHBoxLayout(); + filters_widget = new QWidget(this); + QHBoxLayout *filter_layout = new QHBoxLayout(filters_widget); + filter_layout->setContentsMargins(0, 0, 0, 0); + filter_layout->addWidget(display_type_cb = new QComboBox(this)); + filter_layout->addWidget(signals_cb = new QComboBox(this)); + filter_layout->addWidget(comp_box = new QComboBox(this)); + filter_layout->addWidget(value_edit = new QLineEdit(this)); + h->addWidget(filters_widget); + h->addStretch(0); + h->addWidget(dynamic_mode = new QCheckBox(tr("Dynamic")), 0, Qt::AlignRight); - display_type_cb = new QComboBox(); - display_type_cb->addItems({"Signal value", "Hex value"}); - h->addWidget(display_type_cb); - - signals_cb = new QComboBox(this); - signals_cb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - h->addWidget(signals_cb); - comp_box = new QComboBox(); + display_type_cb->addItems({"Signal Value", "Hex Value"}); comp_box->addItems({">", "=", "!=", "<"}); - h->addWidget(comp_box); - value_edit = new QLineEdit(this); value_edit->setClearButtonEnabled(true); value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); - h->addWidget(value_edit); - dynamic_mode = new QCheckBox(tr("Dynamic")); - h->addWidget(dynamic_mode, 0, Qt::AlignRight); + dynamic_mode->setChecked(true); + dynamic_mode->setEnabled(!can->liveStreaming()); + main_layout->addLayout(h); + main_layout->addWidget(logs = new QTableView(this)); + logs->setModel(model = new HistoryLogModel(this)); + logs->setItemDelegateForColumn(1, new MessageBytesDelegate(this)); + logs->setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); + logs->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); + logs->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + logs->verticalHeader()->setVisible(false); - model = new HistoryLogModel(this); - logs = new HistoryLog(this); - logs->setModel(model); - main_layout->addWidget(logs); - - QObject::connect(logs, &QTableView::doubleClicked, this, &LogsWidget::doubleClicked); - QObject::connect(display_type_cb, SIGNAL(activated(int)), this, SLOT(displayTypeChanged())); + QObject::connect(display_type_cb, SIGNAL(activated(int)), model, SLOT(setDisplayType(int))); + QObject::connect(dynamic_mode, &QCheckBox::stateChanged, model, &HistoryLogModel::setDynamicMode); QObject::connect(signals_cb, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(comp_box, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); - QObject::connect(dynamic_mode, &QCheckBox::stateChanged, model, &HistoryLogModel::setDynamicMode); QObject::connect(can, &AbstractStream::seekedTo, model, &HistoryLogModel::refresh); QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged); - - dynamic_mode->setChecked(true); - if (can->liveStreaming()) { - dynamic_mode->setEnabled(false); - } } void LogsWidget::setMessage(const QString &message_id) { model->setMessage(message_id); - cur_filter_text = ""; - value_edit->setText(""); - signals_cb->clear(); - comp_box->setCurrentIndex(0); - bool has_signals = model->sigs.size() > 0; - if (has_signals) { + bool has_signal = model->sigs.size(); + if (has_signal) { + signals_cb->clear(); for (auto s : model->sigs) { signals_cb->addItem(s->name.c_str()); } } - display_type_cb->setCurrentIndex(has_signals ? 0 : 1); - display_type_cb->setVisible(has_signals); - comp_box->setVisible(has_signals); - value_edit->setVisible(has_signals); - signals_cb->setVisible(has_signals); + value_edit->clear(); + comp_box->setCurrentIndex(0); + filters_widget->setVisible(has_signal); } -static bool not_equal(double l, double r) { return l != r; } - void LogsWidget::setFilter() { - if (cur_filter_text.isEmpty() && value_edit->text().isEmpty()) { - return; - } + if (value_edit->text().isEmpty() && !value_edit->isModified()) return; - std::function cmp; + std::function cmp = nullptr; switch (comp_box->currentIndex()) { case 0: cmp = std::greater{}; break; case 1: cmp = std::equal_to{}; break; - case 2: cmp = not_equal; break; + case 2: cmp = [](double l, double r) { return l != r; }; break; // not equal case 3: cmp = std::less{}; break; } model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); - cur_filter_text = value_edit->text(); -} - -void LogsWidget::displayTypeChanged() { - model->setDisplayType(display_type_cb->currentIndex() == 0 ? HistoryLogModel::Signals : HistoryLogModel::Hex); -} - -void LogsWidget::showEvent(QShowEvent *event) { - if (dynamic_mode->isChecked()) { - model->refresh(); - } -} - -void LogsWidget::updateState() { - if (dynamic_mode->isChecked()) { - model->updateState(); - } -} - -void LogsWidget::doubleClicked(const QModelIndex &index) { - if (index.isValid()) { - if (model->display_type == HistoryLogModel::Signals && model->sigs.size() > 0 && index.column() > 0) { - emit openChart(model->msg_id, model->sigs[index.column()-1]); - } - can->seekTo(model->messages[index.row()].mono_time / (double)1e9 - can->routeStartTime()); - } } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 34af713fd3..83b5f623ea 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -21,29 +21,27 @@ class HistoryLogModel : public QAbstractTableModel { Q_OBJECT public: - enum DisplayType { - Signals, - Hex - }; - HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} void setMessage(const QString &message_id); void updateState(); void setFilter(int sig_idx, const QString &value, std::function cmp); - void setDisplayType(DisplayType type); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void fetchMore(const QModelIndex &parent) override; inline bool canFetchMore(const QModelIndex &parent) const override { return has_more_data; } int rowCount(const QModelIndex &parent = QModelIndex()) const override { return messages.size(); } int columnCount(const QModelIndex &parent = QModelIndex()) const override { - return display_type == HistoryLogModel::Hex ? 2 : std::max(1ul, sigs.size()) + 1; + return display_signals_mode && !sigs.empty() ? sigs.size() + 1 : 2; } - void setDynamicMode(int state); - void segmentsMerged(); void updateColors(); void refresh(); +public slots: + void setDisplayType(int type); + void setDynamicMode(int state); + void segmentsMerged(); + +public: struct Message { uint64_t mono_time = 0; QVector sig_values; @@ -66,13 +64,7 @@ public: std::deque messages; std::vector sigs; bool dynamic_mode = true; - DisplayType display_type = HistoryLogModel::Signals; -}; - -class HistoryLog : public QTableView { -public: - HistoryLog(QWidget *parent); - int sizeHintForColumn(int column) const override { return -1; }; + bool display_signals_mode = true; }; class LogsWidget : public QWidget { @@ -81,23 +73,20 @@ class LogsWidget : public QWidget { public: LogsWidget(QWidget *parent); void setMessage(const QString &message_id); - void updateState(); + void updateState() {if (dynamic_mode->isChecked()) model->updateState(); } + void showEvent(QShowEvent *event) override { if (dynamic_mode->isChecked()) model->refresh(); } signals: void openChart(const QString &msg_id, const Signal *sig); private slots: void setFilter(); - void displayTypeChanged(); private: - void doubleClicked(const QModelIndex &index); - void showEvent(QShowEvent *event) override; - - HistoryLog *logs; + QTableView *logs; HistoryLogModel *model; QCheckBox *dynamic_mode; QComboBox *signals_cb, *comp_box, *display_type_cb; QLineEdit *value_edit; - QString cur_filter_text; + QWidget *filters_widget; }; From de5f792b3e893711a47c8f4db04162ab259ef286 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 27 Jan 2023 04:41:17 +0800 Subject: [PATCH 0737/1179] cabana: only repaint changed cells in BinaryView::highlight (#27046) dont update all cells on highlight --- tools/cabana/binaryview.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index eaa33724e8..010fe0fc88 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -40,8 +40,14 @@ QSize BinaryView::minimumSizeHint() const { void BinaryView::highlight(const Signal *sig) { if (sig != hovered_sig) { + for (int i = 0; i < model->items.size(); ++i) { + auto &item_sigs = model->items[i].sigs; + if ((sig && item_sigs.contains(sig)) || (hovered_sig && item_sigs.contains(hovered_sig))) { + auto index = model->index(i / model->columnCount(), i % model->columnCount()); + emit model->dataChanged(index, index, {Qt::DisplayRole}); + } + } hovered_sig = sig; - model->dataChanged(model->index(0, 0), model->index(model->rowCount() - 1, model->columnCount() - 1)); emit signalHovered(hovered_sig); } } From 752b4edb928f9c9efb4d00429cdb7213c940159b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 12:54:53 -0800 Subject: [PATCH 0738/1179] HKG: Update Genesis GV60 harnesses (#27033) * Update values.py * generate --- docs/CARS.md | 5 +++-- selfdrive/car/hyundai/values.py | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 4a46360d4f..390d2bf349 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 223 Supported Cars +# 224 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -32,7 +32,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| -|Genesis|GV60 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| |GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index dbac8033d8..c0cf23b50d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -225,7 +225,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { ], # Genesis - CAR.GENESIS_GV60_EV_1ST_GEN: HyundaiCarInfo("Genesis GV60 2023", "All", harness=Harness.hyundai_k), + CAR.GENESIS_GV60_EV_1ST_GEN: [ + HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", harness=Harness.hyundai_a), + HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", harness=Harness.hyundai_k), + ], CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f), CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l), From 08060e42c4bab39b85a64707f8eb801580ed2245 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 27 Jan 2023 04:56:38 +0800 Subject: [PATCH 0739/1179] cabana: saving & restoring columns widths (#27080) saving & restoring columns widths --- tools/cabana/mainwin.cc | 4 ++++ tools/cabana/messageswidget.cc | 1 - tools/cabana/messageswidget.h | 3 +++ tools/cabana/settings.cc | 2 ++ tools/cabana/settings.h | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 1468073017..517d0b1b73 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -29,11 +29,13 @@ MainWindow::MainWindow() : QMainWindow() { createStatusBar(); createShortcuts(); + // restore states restoreGeometry(settings.geometry); if (isMaximized()) { setGeometry(QApplication::desktop()->availableGeometry(this)); } restoreState(settings.window_state); + messages_widget->restoreHeaderState(settings.message_header_state); qRegisterMetaType("uint64_t"); qRegisterMetaType("ReplyMsgType"); @@ -285,11 +287,13 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (floating_window) floating_window->deleteLater(); + // save states settings.geometry = saveGeometry(); settings.window_state = saveState(); if (!can->liveStreaming()) { settings.video_splitter_state = video_splitter->saveState(); } + settings.message_header_state = messages_widget->saveHeaderState(); settings.save(); QWidget::closeEvent(event); } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 353fe26340..69c6d298c0 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -1,7 +1,6 @@ #include "tools/cabana/messageswidget.h" #include -#include #include #include #include diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 49f57b78e6..69fdd26170 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,8 @@ class MessagesWidget : public QWidget { public: MessagesWidget(QWidget *parent); void selectMessage(const QString &message_id); + QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); } + bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); } signals: void msgSelectionChanged(const QString &message_id); diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index e06d149831..7d34d5dec0 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -23,6 +23,7 @@ void Settings::save() { s.setValue("window_state", window_state); s.setValue("geometry", geometry); s.setValue("video_splitter_state", video_splitter_state); + s.setValue("message_header_state", message_header_state); } void Settings::load() { @@ -36,6 +37,7 @@ void Settings::load() { window_state = s.value("window_state").toByteArray(); geometry = s.value("geometry").toByteArray(); video_splitter_state = s.value("video_splitter_state").toByteArray(); + message_header_state = s.value("message_header_state").toByteArray(); } // SettingsDlg diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 86ebd73113..7b0cbc9f5d 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -22,6 +22,7 @@ public: QByteArray geometry; QByteArray video_splitter_state; QByteArray window_state; + QByteArray message_header_state; signals: void changed(); From 9201267fb7ba0080a3c508a6a258f76cbc265079 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Thu, 26 Jan 2023 14:48:46 -0800 Subject: [PATCH 0740/1179] torqued: Update reset logic (#27103) * update reset logic * bugfix --- selfdrive/locationd/torqued.py | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index cb8101bbd4..5449152686 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -31,8 +31,6 @@ MAX_FILTER_DECAY = 250 LAT_ACC_THRESHOLD = 1 STEER_BUCKET_BOUNDS = [(-0.5, -0.3), (-0.3, -0.2), (-0.2, -0.1), (-0.1, 0), (0, 0.1), (0.1, 0.2), (0.2, 0.3), (0.3, 0.5)] MIN_BUCKET_POINTS = np.array([100, 300, 500, 500, 500, 500, 300, 100]) -MAX_RESETS = 5.0 -MAX_INVALID_THRESHOLD = 10 MIN_ENGAGE_BUFFER = 2 # secs VERSION = 1 # bump this to invalidate old parameter caches @@ -173,7 +171,6 @@ class TorqueEstimator: def reset(self): self.resets += 1.0 - self.invalid_values_tracker = 0.0 self.decay = MIN_FILTER_DECAY self.raw_points = defaultdict(lambda: deque(maxlen=self.hist_len)) self.filtered_points = PointBuckets(x_bounds=STEER_BUCKET_BOUNDS, min_points=self.min_bucket_points, min_points_total=self.min_points_total) @@ -198,12 +195,6 @@ class TorqueEstimator: self.filtered_params[param].update(value) self.filtered_params[param].update_alpha(self.decay) - def is_sane(self, latAccelFactor, latAccelOffset, friction): - if any([val is None or np.isnan(val) for val in [latAccelFactor, latAccelOffset, friction]]): - return False - return (self.max_friction >= friction >= self.min_friction) and\ - (self.max_lataccel_factor >= latAccelFactor >= self.min_lataccel_factor) - def handle_log(self, t, which, msg): if which == "carControl": self.raw_points["carControl_t"].append(t + self.lag) @@ -233,23 +224,20 @@ class TorqueEstimator: liveTorqueParameters.useParams = self.use_params if self.filtered_points.is_valid(): - latAccelFactor, latAccelOffset, friction_coeff = self.estimate_params() + latAccelFactor, latAccelOffset, frictionCoeff = self.estimate_params() liveTorqueParameters.latAccelFactorRaw = float(latAccelFactor) liveTorqueParameters.latAccelOffsetRaw = float(latAccelOffset) - liveTorqueParameters.frictionCoefficientRaw = float(friction_coeff) + liveTorqueParameters.frictionCoefficientRaw = float(frictionCoeff) - if self.is_sane(latAccelFactor, latAccelOffset, friction_coeff): - liveTorqueParameters.liveValid = True - self.update_params({'latAccelFactor': latAccelFactor, 'latAccelOffset': latAccelOffset, 'frictionCoefficient': friction_coeff}) - self.invalid_values_tracker = max(0.0, self.invalid_values_tracker - 0.5) - else: - cloudlog.exception("Live torque parameters are outside acceptable bounds.") + if any([val is None or np.isnan(val) for val in [latAccelFactor, latAccelOffset, frictionCoeff]]): + cloudlog.exception("Live torque parameters are invalid.") liveTorqueParameters.liveValid = False - self.invalid_values_tracker += 1.0 - # Reset when ~10 invalid over 5 secs - if self.invalid_values_tracker > MAX_INVALID_THRESHOLD: - # Do not reset the filter as it may cause a drastic jump, just reset points - self.reset() + self.reset() + else: + liveTorqueParameters.liveValid = True + latAccelFactor = np.clip(latAccelFactor, self.min_lataccel_factor, self.max_lataccel_factor) + frictionCoeff = np.clip(frictionCoeff, self.min_friction, self.max_friction) + self.update_params({'latAccelFactor': latAccelFactor, 'latAccelOffset': latAccelOffset, 'frictionCoefficient': frictionCoeff}) else: liveTorqueParameters.liveValid = False From 6f0d35a09f54866ff2c7a76993c2f11e96fdf869 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Thu, 26 Jan 2023 18:25:15 -0700 Subject: [PATCH 0741/1179] Glonass ephemeris support (#27088) * add glonass kaitai parsing * add kaita generated files * remove glonass from build * add string non immediate type * fix kaitai bug * add patch file * fix scons order * Update selfdrive/locationd/SConscript Co-authored-by: Adeeb Shihadeh Co-authored-by: Kurt Nistelberger Co-authored-by: Adeeb Shihadeh --- selfdrive/locationd/SConscript | 5 + selfdrive/locationd/generated/glonass.cpp | 201 +++++++++++++++++++ selfdrive/locationd/generated/glonass.h | 232 ++++++++++++++++++++++ selfdrive/locationd/generated/gps.cpp | 6 +- selfdrive/locationd/generated/gps.h | 4 +- selfdrive/locationd/generated/ubx.cpp | 8 +- selfdrive/locationd/glonass.ksy | 107 ++++++++++ selfdrive/locationd/glonass_fix.patch | 13 ++ selfdrive/locationd/gps.ksy | 2 +- 9 files changed, 566 insertions(+), 12 deletions(-) create mode 100644 selfdrive/locationd/generated/glonass.cpp create mode 100644 selfdrive/locationd/generated/glonass.h create mode 100644 selfdrive/locationd/glonass.ksy create mode 100644 selfdrive/locationd/glonass_fix.patch diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index 4b7fba19b6..7024196efd 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -7,6 +7,11 @@ if GetOption('kaitai'): cmd = f"kaitai-struct-compiler --target cpp_stl --outdir {generated} $SOURCES" env.Command(['generated/ubx.cpp', 'generated/ubx.h'], 'ubx.ksy', cmd) env.Command(['generated/gps.cpp', 'generated/gps.h'], 'gps.ksy', cmd) + glonass = env.Command(['generated/glonass.cpp', 'generated/glonass.h'], 'glonass.ksy', cmd) + + # kaitai issue: https://github.com/kaitai-io/kaitai_struct/issues/910 + patch = env.Command(None, 'glonass_fix.patch', 'git apply $SOURCES') + env.Depends(patch, glonass) env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "generated/ubx.cpp", "generated/gps.cpp"], LIBS=loc_libs) diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp new file mode 100644 index 0000000000..149134fbb5 --- /dev/null +++ b/selfdrive/locationd/generated/glonass.cpp @@ -0,0 +1,201 @@ +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "glonass.h" + +glonass_t::glonass_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = this; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::_read() { + m_idle_chip = m__io->read_bits_int_be(1); + m_string_number = m__io->read_bits_int_be(4); + //m__io->align_to_byte(); + switch (string_number()) { + case 4: { + m_data = new string_4_t(m__io, this, m__root); + break; + } + case 1: { + m_data = new string_1_t(m__io, this, m__root); + break; + } + case 3: { + m_data = new string_3_t(m__io, this, m__root); + break; + } + case 2: { + m_data = new string_2_t(m__io, this, m__root); + break; + } + default: { + m_data = new string_non_immediate_t(m__io, this, m__root); + break; + } + } + m_hamming_code = m__io->read_bits_int_be(8); + m_pad_1 = m__io->read_bits_int_be(11); + m_superframe_number = m__io->read_bits_int_be(16); + m_pad_2 = m__io->read_bits_int_be(8); + m_frame_number = m__io->read_bits_int_be(8); +} + +glonass_t::~glonass_t() { + _clean_up(); +} + +void glonass_t::_clean_up() { + if (m_data) { + delete m_data; m_data = 0; + } +} + +glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_4_t::_read() { + m_tau_n = m__io->read_bits_int_be(22); + m_delta_tau_n = m__io->read_bits_int_be(5); + m_e_n = m__io->read_bits_int_be(5); + m_not_used_1 = m__io->read_bits_int_be(14); + m_p4 = m__io->read_bits_int_be(1); + m_f_t = m__io->read_bits_int_be(4); + m_not_used_2 = m__io->read_bits_int_be(3); + m_n_t = m__io->read_bits_int_be(11); + m_n = m__io->read_bits_int_be(5); + m_m = m__io->read_bits_int_be(2); +} + +glonass_t::string_4_t::~string_4_t() { + _clean_up(); +} + +void glonass_t::string_4_t::_clean_up() { +} + +glonass_t::string_non_immediate_t::string_non_immediate_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_non_immediate_t::_read() { + m_data_1 = m__io->read_bits_int_be(64); + m_data_2 = m__io->read_bits_int_be(8); +} + +glonass_t::string_non_immediate_t::~string_non_immediate_t() { + _clean_up(); +} + +void glonass_t::string_non_immediate_t::_clean_up() { +} + +glonass_t::string_1_t::string_1_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_1_t::_read() { + m_not_used = m__io->read_bits_int_be(2); + m_p1 = m__io->read_bits_int_be(2); + m_t_k = m__io->read_bits_int_be(12); + m_x_vel = m__io->read_bits_int_be(24); + m_x_speedup = m__io->read_bits_int_be(5); + m_x = m__io->read_bits_int_be(27); +} + +glonass_t::string_1_t::~string_1_t() { + _clean_up(); +} + +void glonass_t::string_1_t::_clean_up() { +} + +glonass_t::string_2_t::string_2_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_2_t::_read() { + m_b_n = m__io->read_bits_int_be(3); + m_p2 = m__io->read_bits_int_be(1); + m_t_b = m__io->read_bits_int_be(7); + m_not_used = m__io->read_bits_int_be(5); + m_y_vel = m__io->read_bits_int_be(24); + m_y_speedup = m__io->read_bits_int_be(5); + m_y = m__io->read_bits_int_be(27); +} + +glonass_t::string_2_t::~string_2_t() { + _clean_up(); +} + +void glonass_t::string_2_t::_clean_up() { +} + +glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_3_t::_read() { + m_p3 = m__io->read_bits_int_be(1); + m_gamma_n = m__io->read_bits_int_be(11); + m_not_used = m__io->read_bits_int_be(1); + m_p = m__io->read_bits_int_be(2); + m_l_n = m__io->read_bits_int_be(1); + m_z_vel = m__io->read_bits_int_be(24); + m_z_speedup = m__io->read_bits_int_be(5); + m_z = m__io->read_bits_int_be(27); +} + +glonass_t::string_3_t::~string_3_t() { + _clean_up(); +} + +void glonass_t::string_3_t::_clean_up() { +} diff --git a/selfdrive/locationd/generated/glonass.h b/selfdrive/locationd/generated/glonass.h new file mode 100644 index 0000000000..48bdabfe96 --- /dev/null +++ b/selfdrive/locationd/generated/glonass.h @@ -0,0 +1,232 @@ +#ifndef GLONASS_H_ +#define GLONASS_H_ + +// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild + +#include "kaitai/kaitaistruct.h" +#include + +#if KAITAI_STRUCT_VERSION < 9000L +#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required" +#endif + +class glonass_t : public kaitai::kstruct { + +public: + class string_4_t; + class string_non_immediate_t; + class string_1_t; + class string_2_t; + class string_3_t; + + glonass_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, glonass_t* p__root = 0); + +private: + void _read(); + void _clean_up(); + +public: + ~glonass_t(); + + class string_4_t : public kaitai::kstruct { + + public: + + string_4_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_4_t(); + + private: + uint64_t m_tau_n; + uint64_t m_delta_tau_n; + uint64_t m_e_n; + uint64_t m_not_used_1; + bool m_p4; + uint64_t m_f_t; + uint64_t m_not_used_2; + uint64_t m_n_t; + uint64_t m_n; + uint64_t m_m; + glonass_t* m__root; + glonass_t* m__parent; + + public: + uint64_t tau_n() const { return m_tau_n; } + uint64_t delta_tau_n() const { return m_delta_tau_n; } + uint64_t e_n() const { return m_e_n; } + uint64_t not_used_1() const { return m_not_used_1; } + bool p4() const { return m_p4; } + uint64_t f_t() const { return m_f_t; } + uint64_t not_used_2() const { return m_not_used_2; } + uint64_t n_t() const { return m_n_t; } + uint64_t n() const { return m_n; } + uint64_t m() const { return m_m; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + + class string_non_immediate_t : public kaitai::kstruct { + + public: + + string_non_immediate_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_non_immediate_t(); + + private: + uint64_t m_data_1; + uint64_t m_data_2; + glonass_t* m__root; + glonass_t* m__parent; + + public: + uint64_t data_1() const { return m_data_1; } + uint64_t data_2() const { return m_data_2; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + + class string_1_t : public kaitai::kstruct { + + public: + + string_1_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_1_t(); + + private: + uint64_t m_not_used; + uint64_t m_p1; + uint64_t m_t_k; + uint64_t m_x_vel; + uint64_t m_x_speedup; + uint64_t m_x; + glonass_t* m__root; + glonass_t* m__parent; + + public: + uint64_t not_used() const { return m_not_used; } + uint64_t p1() const { return m_p1; } + uint64_t t_k() const { return m_t_k; } + uint64_t x_vel() const { return m_x_vel; } + uint64_t x_speedup() const { return m_x_speedup; } + uint64_t x() const { return m_x; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + + class string_2_t : public kaitai::kstruct { + + public: + + string_2_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_2_t(); + + private: + uint64_t m_b_n; + bool m_p2; + uint64_t m_t_b; + uint64_t m_not_used; + uint64_t m_y_vel; + uint64_t m_y_speedup; + uint64_t m_y; + glonass_t* m__root; + glonass_t* m__parent; + + public: + uint64_t b_n() const { return m_b_n; } + bool p2() const { return m_p2; } + uint64_t t_b() const { return m_t_b; } + uint64_t not_used() const { return m_not_used; } + uint64_t y_vel() const { return m_y_vel; } + uint64_t y_speedup() const { return m_y_speedup; } + uint64_t y() const { return m_y; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + + class string_3_t : public kaitai::kstruct { + + public: + + string_3_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_3_t(); + + private: + bool m_p3; + uint64_t m_gamma_n; + bool m_not_used; + uint64_t m_p; + bool m_l_n; + uint64_t m_z_vel; + uint64_t m_z_speedup; + uint64_t m_z; + glonass_t* m__root; + glonass_t* m__parent; + + public: + bool p3() const { return m_p3; } + uint64_t gamma_n() const { return m_gamma_n; } + bool not_used() const { return m_not_used; } + uint64_t p() const { return m_p; } + bool l_n() const { return m_l_n; } + uint64_t z_vel() const { return m_z_vel; } + uint64_t z_speedup() const { return m_z_speedup; } + uint64_t z() const { return m_z; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + +private: + bool m_idle_chip; + uint64_t m_string_number; + kaitai::kstruct* m_data; + uint64_t m_hamming_code; + uint64_t m_pad_1; + uint64_t m_superframe_number; + uint64_t m_pad_2; + uint64_t m_frame_number; + glonass_t* m__root; + kaitai::kstruct* m__parent; + +public: + bool idle_chip() const { return m_idle_chip; } + uint64_t string_number() const { return m_string_number; } + kaitai::kstruct* data() const { return m_data; } + uint64_t hamming_code() const { return m_hamming_code; } + uint64_t pad_1() const { return m_pad_1; } + uint64_t superframe_number() const { return m_superframe_number; } + uint64_t pad_2() const { return m_pad_2; } + uint64_t frame_number() const { return m_frame_number; } + glonass_t* _root() const { return m__root; } + kaitai::kstruct* _parent() const { return m__parent; } +}; + +#endif // GLONASS_H_ diff --git a/selfdrive/locationd/generated/gps.cpp b/selfdrive/locationd/generated/gps.cpp index 9b020735bb..8e1cb85b95 100644 --- a/selfdrive/locationd/generated/gps.cpp +++ b/selfdrive/locationd/generated/gps.cpp @@ -274,9 +274,9 @@ gps_t::tlm_t::tlm_t(kaitai::kstream* p__io, gps_t* p__parent, gps_t* p__root) : } void gps_t::tlm_t::_read() { - m_magic = m__io->read_bytes(1); - if (!(magic() == std::string("\x8B", 1))) { - throw kaitai::validation_not_equal_error(std::string("\x8B", 1), magic(), _io(), std::string("/types/tlm/seq/0")); + m_preamble = m__io->read_bytes(1); + if (!(preamble() == std::string("\x8B", 1))) { + throw kaitai::validation_not_equal_error(std::string("\x8B", 1), preamble(), _io(), std::string("/types/tlm/seq/0")); } m_tlm = m__io->read_bits_int_be(14); m_integrity_status = m__io->read_bits_int_be(1); diff --git a/selfdrive/locationd/generated/gps.h b/selfdrive/locationd/generated/gps.h index 293e2e4a05..9dfc5031f5 100644 --- a/selfdrive/locationd/generated/gps.h +++ b/selfdrive/locationd/generated/gps.h @@ -273,7 +273,7 @@ public: ~tlm_t(); private: - std::string m_magic; + std::string m_preamble; uint64_t m_tlm; bool m_integrity_status; bool m_reserved; @@ -281,7 +281,7 @@ public: gps_t* m__parent; public: - std::string magic() const { return m_magic; } + std::string preamble() const { return m_preamble; } uint64_t tlm() const { return m_tlm; } bool integrity_status() const { return m_integrity_status; } bool reserved() const { return m_reserved; } diff --git a/selfdrive/locationd/generated/ubx.cpp b/selfdrive/locationd/generated/ubx.cpp index 5e743e1ee7..34fe1e52ca 100644 --- a/selfdrive/locationd/generated/ubx.cpp +++ b/selfdrive/locationd/generated/ubx.cpp @@ -89,13 +89,10 @@ void ubx_t::rxm_rawx_t::_read() { m_num_meas = m__io->read_u1(); m_rec_stat = m__io->read_u1(); m_reserved1 = m__io->read_bytes(3); - int l_measurements = num_meas(); m__raw_measurements = new std::vector(); - m__raw_measurements->reserve(l_measurements); m__io__raw_measurements = new std::vector(); - m__io__raw_measurements->reserve(l_measurements); m_measurements = new std::vector(); - m_measurements->reserve(l_measurements); + const int l_measurements = num_meas(); for (int i = 0; i < l_measurements; i++) { m__raw_measurements->push_back(m__io->read_bytes(32)); kaitai::kstream* io__raw_measurements = new kaitai::kstream(m__raw_measurements->at(m__raw_measurements->size() - 1)); @@ -184,9 +181,8 @@ void ubx_t::rxm_sfrbx_t::_read() { m_reserved2 = m__io->read_bytes(1); m_version = m__io->read_u1(); m_reserved3 = m__io->read_bytes(1); - int l_body = num_words(); m_body = new std::vector(); - m_body->reserve(l_body); + const int l_body = num_words(); for (int i = 0; i < l_body; i++) { m_body->push_back(m__io->read_u4le()); } diff --git a/selfdrive/locationd/glonass.ksy b/selfdrive/locationd/glonass.ksy new file mode 100644 index 0000000000..95ca78c16f --- /dev/null +++ b/selfdrive/locationd/glonass.ksy @@ -0,0 +1,107 @@ +# http://gauss.gge.unb.ca/GLONASS.ICD.pdf +meta: + id: glonass + endian: be + bit-endian: be +seq: + - id: idle_chip + type: b1 + - id: string_number + type: b4 + - id: data + type: + switch-on: string_number + cases: + 1: string_1 + 2: string_2 + 3: string_3 + 4: string_4 + _: string_non_immediate + - id: hamming_code + type: b8 + - id: pad_1 + type: b11 + - id: superframe_number + type: b16 + - id: pad_2 + type: b8 + - id: frame_number + type: b8 + +types: + string_1: + seq: + - id: not_used + type: b2 + - id: p1 + type: b2 + - id: t_k + type: b12 + - id: x_vel + type: b24 + - id: x_speedup + type: b5 + - id: x + type: b27 + string_2: + seq: + - id: b_n + type: b3 + - id: p2 + type: b1 + - id: t_b + type: b7 + - id: not_used + type: b5 + - id: y_vel + type: b24 + - id: y_speedup + type: b5 + - id: y + type: b27 + string_3: + seq: + - id: p3 + type: b1 + - id: gamma_n + type: b11 + - id: not_used + type: b1 + - id: p + type: b2 + - id: l_n + type: b1 + - id: z_vel + type: b24 + - id: z_speedup + type: b5 + - id: z + type: b27 + string_4: + seq: + - id: tau_n + type: b22 + - id: delta_tau_n + type: b5 + - id: e_n + type: b5 + - id: not_used_1 + type: b14 + - id: p4 + type: b1 + - id: f_t + type: b4 + - id: not_used_2 + type: b3 + - id: n_t + type: b11 + - id: n + type: b5 + - id: m + type: b2 + string_non_immediate: + seq: + - id: data_1 + type: b64 + - id: data_2 + type: b8 \ No newline at end of file diff --git a/selfdrive/locationd/glonass_fix.patch b/selfdrive/locationd/glonass_fix.patch new file mode 100644 index 0000000000..2f99e93637 --- /dev/null +++ b/selfdrive/locationd/glonass_fix.patch @@ -0,0 +1,13 @@ +diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp +index 6a48fe62c..149134fbb 100644 +--- a/selfdrive/locationd/generated/glonass.cpp ++++ b/selfdrive/locationd/generated/glonass.cpp +@@ -17,7 +17,7 @@ glonass_t::glonass_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, glonass + void glonass_t::_read() { + m_idle_chip = m__io->read_bits_int_be(1); + m_string_number = m__io->read_bits_int_be(4); +- m__io->align_to_byte(); ++ //m__io->align_to_byte(); + switch (string_number()) { + case 4: { + m_data = new string_4_t(m__io, this, m__root); diff --git a/selfdrive/locationd/gps.ksy b/selfdrive/locationd/gps.ksy index 6f5cde316b..893ad1b25b 100644 --- a/selfdrive/locationd/gps.ksy +++ b/selfdrive/locationd/gps.ksy @@ -19,7 +19,7 @@ seq: types: tlm: seq: - - id: magic + - id: preamble contents: [0x8b] - id: tlm type: b14 From 7316cd03fb71be3e27588cb7a6b9cffafbebe34f Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 26 Jan 2023 19:09:12 -0800 Subject: [PATCH 0742/1179] new model: fixed weight decay logic (#27068) * 07a3a2b2-6dbe-43c3-9bb9-a8023932e054/449 cdfa9e3c-2807-49fc-bdc7-a985f8ff1644/700 * update refs --- 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 8805b3dce8..2daf01ea14 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 -size 45962473 +oid sha256:3d8f2f9d53908e7a5496412956548dab1aa08ed0b5fb9d1c685f275369f07a57 +size 45962515 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index 9eefc73792..fa4fa9540d 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -8233a12f97f483645e7691b8c54552a2f861a7ad +2a255ecea3665a3d295210195fd8ef0791ab49a0 From 4f4f4afe8a9bca7fdaf70c2b05ef6e90263aaac8 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 19:11:44 -0800 Subject: [PATCH 0743/1179] Ford: set lateral ramp type to 0 (#27106) set ramp type always to 0 --- selfdrive/car/ford/carcontroller.py | 15 +-------------- selfdrive/car/ford/fordcan.py | 9 +++++---- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 99a6648ff9..ab5cf267e0 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -54,22 +54,9 @@ class CarController: else: apply_curvature = 0. - # set slower ramp type when small steering angle change - # 0=Slow, 1=Medium, 2=Fast, 3=Immediately - steer_change = abs(CS.out.steeringAngleDeg - actuators.steeringAngleDeg) - if steer_change < 2.5: - ramp_type = 0 - elif steer_change < 5.0: - ramp_type = 1 - elif steer_change < 7.5: - ramp_type = 2 - else: - ramp_type = 3 - precision = 1 # 0=Comfortable, 1=Precise (the stock system always uses comfortable) - self.apply_curvature_last = apply_curvature can_sends.append(create_lka_msg(self.packer)) - can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, ramp_type, precision, 0., 0., -apply_curvature, 0.)) + can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.)) ### ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index dcda59bce2..9ddde80f87 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -16,8 +16,7 @@ def create_lka_msg(packer): return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {}) -def create_lat_ctl_msg(packer, lat_active: bool, ramp_type: int, precision: int, path_offset: float, path_angle: float, - curvature: float, curvature_rate: float): +def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float, curvature_rate: float): """ Creates a CAN message for the Ford TJA/LCA Command. @@ -44,8 +43,10 @@ def create_lat_ctl_msg(packer, lat_active: bool, ramp_type: int, precision: int, "HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1] "LatCtl_D_Rq": 1 if lat_active else 0, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft, # 3=InterventionRight, 4-7=NotUsed [0|7] - "LatCtlRampType_D_Rq": ramp_type, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] - "LatCtlPrecision_D_Rq": precision, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] + "LatCtlRampType_D_Rq": 0, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] + # Makes no difference with curvature control + "LatCtlPrecision_D_Rq": 1, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] + # The stock system always uses comfortable "LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter "LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians "LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2 From ad5b3ea410425d8d5d929e626a626c8d868ecdff Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 20:02:23 -0800 Subject: [PATCH 0744/1179] controls: add curvature to actuators (#27108) * Add curvature to actuators * Use it in CC * revert ford stuff * Update ref_commit --- selfdrive/controls/controlsd.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index c0b01bfc99..21d8fe2d66 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -606,6 +606,7 @@ class Controls: actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp, self.last_actuators, self.steer_limited, self.desired_curvature, self.desired_curvature_rate, self.sm['liveLocationKalman']) + actuators.curvature = self.desired_curvature else: lac_log = log.ControlsState.LateralDebugState.new_message() if self.sm.rcv_frame['testJoystick'] > 0: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index fb714b6f57..63db584c87 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3639e42ed538ee5d94ec2572cf27af6260633fad \ No newline at end of file +634d4ff195345a4a2508e497744aa08addec9237 From 50fc560b43bb24570400834edcaaa84d7270f38c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 27 Jan 2023 12:29:28 +0800 Subject: [PATCH 0745/1179] cabana: improve mainwin (#27053) * open recent * improve mainwin * move to submenu * new file & remind save before load dd --- tools/cabana/cabana.cc | 1 + tools/cabana/mainwin.cc | 155 +++++++++++++++++++++++++++++---------- tools/cabana/mainwin.h | 18 ++++- tools/cabana/settings.cc | 2 + tools/cabana/settings.h | 1 + 5 files changed, 133 insertions(+), 44 deletions(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index fc6c37fb72..d9b6b5948b 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -12,6 +12,7 @@ int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); initApp(argc, argv); QApplication app(argc, argv); + app.setApplicationDisplayName("Cabana"); QCommandLineParser cmd_parser; cmd_parser.addHelpOption(); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 517d0b1b73..7d99b698bb 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -61,22 +61,33 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); - QObject::connect(detail_widget->undo_stack, &QUndoStack::indexChanged, [this](int index) { - setWindowTitle(tr("%1%2 - Cabana").arg(index > 0 ? "* " : "").arg(dbc()->name())); - }); + QObject::connect(detail_widget->undo_stack, &QUndoStack::cleanChanged, [this](bool clean) { setWindowModified(!clean); }); } void MainWindow::createActions() { QMenu *file_menu = menuBar()->addMenu(tr("&File")); - file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::loadDBCFromFile)->setShortcuts(QKeySequence::Open); + file_menu->addAction(tr("New DBC File"), this, &MainWindow::newFile)->setShortcuts(QKeySequence::New); + file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::openFile)->setShortcuts(QKeySequence::Open); file_menu->addAction(tr("Load DBC From Clipboard"), this, &MainWindow::loadDBCFromClipboard); + open_recent_menu = file_menu->addMenu(tr("Open &Recent")); + for (int i = 0; i < MAX_RECENT_FILES; ++i) { + recent_files_acts[i] = new QAction(this); + recent_files_acts[i]->setVisible(false); + QObject::connect(recent_files_acts[i], &QAction::triggered, this, &MainWindow::openRecentFile); + open_recent_menu->addAction(recent_files_acts[i]); + } + updateRecentFileActions(); + file_menu->addSeparator(); - file_menu->addAction(tr("Save DBC..."), this, &MainWindow::saveDBCToFile)->setShortcuts(QKeySequence::Save); - file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAsDBCToFile)->setShortcuts(QKeySequence::SaveAs); + file_menu->addAction(tr("Save DBC..."), this, &MainWindow::save)->setShortcuts(QKeySequence::Save); + file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAs)->setShortcuts(QKeySequence::SaveAs); file_menu->addAction(tr("Copy DBC To Clipboard"), this, &MainWindow::saveDBCToClipboard); file_menu->addSeparator(); file_menu->addAction(tr("Settings..."), this, &MainWindow::setOption)->setShortcuts(QKeySequence::Preferences); + file_menu->addSeparator(); + file_menu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows)->setShortcuts(QKeySequence::Quit); + QMenu *edit_menu = menuBar()->addMenu(tr("&Edit")); auto undo_act = detail_widget->undo_stack->createUndoAction(this, tr("&Undo")); undo_act->setShortcuts(QKeySequence::Undo); @@ -181,34 +192,57 @@ void MainWindow::DBCFileChanged() { detail_widget->undo_stack->clear(); int index = dbc_combo->findText(QFileInfo(dbc()->name()).baseName()); dbc_combo->setCurrentIndex(index); - setWindowTitle(tr("%1 - Cabana").arg(dbc()->name())); + setWindowFilePath(QString("%1").arg(dbc()->name())); } -void MainWindow::loadDBCFromName(const QString &name) { - if (name != dbc()->name()) { - dbc()->open(name); +void MainWindow::newFile() { + remindSaveChanges(); + dbc()->open("untitled.dbc", ""); +} + +void MainWindow::openFile() { + remindSaveChanges(); + QString fn = QFileDialog::getOpenFileName(this, tr("Open File"), settings.last_dir, "DBC (*.dbc)"); + if (!fn.isEmpty()) { + loadFile(fn); } } -void MainWindow::loadDBCFromFile() { - file_name = QFileDialog::getOpenFileName(this, tr("Open File"), settings.last_dir, "DBC (*.dbc)"); - if (!file_name.isEmpty()) { - settings.last_dir = QFileInfo(file_name).absolutePath(); - QFile file(file_name); +void MainWindow::loadFile(const QString &fn) { + if (!fn.isEmpty()) { + QFile file(fn); if (file.open(QIODevice::ReadOnly)) { - auto dbc_name = QFileInfo(file_name).baseName(); + auto dbc_name = QFileInfo(fn).baseName(); dbc()->open(dbc_name, file.readAll()); + setCurrentFile(fn); + statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); } } } +void MainWindow::openRecentFile() { + if (auto action = qobject_cast(sender())) { + remindSaveChanges(); + loadFile(action->data().toString()); + } +} + +void MainWindow::loadDBCFromName(const QString &name) { + if (name != dbc()->name()) { + remindSaveChanges(); + dbc()->open(name); + } +} + void MainWindow::loadDBCFromClipboard() { + remindSaveChanges(); QString dbc_str = QGuiApplication::clipboard()->text(); - dbc()->open("From Clipboard", dbc_str); + dbc()->open("from_clipboard.dbc", dbc_str); QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); } void MainWindow::loadDBCFromFingerprint() { + remindSaveChanges(); auto fingerprint = can->carFingerprint(); video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); if (!fingerprint.isEmpty()) { @@ -218,25 +252,31 @@ void MainWindow::loadDBCFromFingerprint() { return; } } - dbc()->open("New_DBC", ""); + newFile(); } -void MainWindow::saveDBCToFile() { - if (file_name.isEmpty()) { - saveAsDBCToFile(); +void MainWindow::save() { + if (current_file.isEmpty()) { + saveAs(); } else { - settings.last_dir = QFileInfo(file_name).absolutePath(); - QFile file(file_name); - if (file.open(QIODevice::WriteOnly)) { - file.write(dbc()->generateDBC().toUtf8()); - } + saveFile(current_file); } } -void MainWindow::saveAsDBCToFile() { - file_name = QFileDialog::getSaveFileName(this, tr("Save File"), QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); - if (!file_name.isEmpty()) { - saveDBCToFile(); +void MainWindow::saveFile(const QString &fn) { + QFile file(fn); + if (file.open(QIODevice::WriteOnly)) { + file.write(dbc()->generateDBC().toUtf8()); + detail_widget->undo_stack->setClean(); + setCurrentFile(fn); + statusBar()->showMessage(tr("File saved"), 2000); + } +} + +void MainWindow::saveAs() { + QString fn = QFileDialog::getSaveFileName(this, tr("Save File"), QDir::cleanPath(settings.last_dir + "/untitled.dbc"), tr("DBC (*.dbc)")); + if (!fn.isEmpty()) { + saveFile(fn); } } @@ -245,6 +285,49 @@ void MainWindow::saveDBCToClipboard() { QMessageBox::information(this, tr("Copy To Clipboard"), tr("DBC Successfully copied!")); } +void MainWindow::setCurrentFile(const QString &fn) { + current_file = fn; + setWindowFilePath(QString("%1").arg(fn)); + settings.recent_files.removeAll(fn); + settings.recent_files.prepend(fn); + while (settings.recent_files.size() > MAX_RECENT_FILES) { + settings.recent_files.removeLast(); + } + settings.last_dir = QFileInfo(fn).absolutePath(); + updateRecentFileActions(); +} + +void MainWindow::updateRecentFileActions() { + int num_recent_files = std::min(settings.recent_files.size(), MAX_RECENT_FILES); + + for (int i = 0; i < num_recent_files; ++i) { + QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(settings.recent_files[i]).fileName()); + recent_files_acts[i]->setText(text); + recent_files_acts[i]->setData(settings.recent_files[i]); + recent_files_acts[i]->setVisible(true); + } + for (int i = num_recent_files; i < MAX_RECENT_FILES; ++i) { + recent_files_acts[i]->setVisible(false); + } + open_recent_menu->setEnabled(num_recent_files > 0); +} + +void MainWindow::remindSaveChanges() { + bool discard_changes = false; + while (!detail_widget->undo_stack->isClean() && !discard_changes) { + int ret = (QMessageBox::question(this, tr("Unsaved Changes"), + tr("You have unsaved changes. Press ok to save them, cancel to discard."), + QMessageBox::Ok | QMessageBox::Cancel)); + if (ret == QMessageBox::Ok) { + save(); + } else { + discard_changes = true; + } + } + detail_widget->undo_stack->clear(); + current_file = ""; +} + void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool success) { if (success && cur < total) { progress_bar->setValue((cur / (double)total) * 100); @@ -264,7 +347,7 @@ void MainWindow::dockCharts(bool dock) { } else if (!dock && !floating_window) { floating_window = new QWidget(this); floating_window->setWindowFlags(Qt::Window); - floating_window->setWindowTitle("Charts - Cabana"); + floating_window->setWindowTitle("Charts"); floating_window->setLayout(new QVBoxLayout()); floating_window->layout()->addWidget(charts_widget); floating_window->installEventFilter(charts_widget); @@ -273,15 +356,7 @@ void MainWindow::dockCharts(bool dock) { } void MainWindow::closeEvent(QCloseEvent *event) { - if (detail_widget->undo_stack->index() > 0) { - auto ret = QMessageBox::question(this, tr("Unsaved Changes"), - tr("Are you sure you want to exit without saving?\nAny unsaved changes will be lost."), - QMessageBox::Yes | QMessageBox::No); - if (ret == QMessageBox::No) { - event->ignore(); - return; - } - } + remindSaveChanges(); main_win = nullptr; if (floating_window) diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index a38834b997..4e65fa01cf 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -23,12 +23,14 @@ public: void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); } public slots: + void newFile(); + void openFile(); + void openRecentFile(); void loadDBCFromName(const QString &name); void loadDBCFromFingerprint(); - void loadDBCFromFile(); void loadDBCFromClipboard(); - void saveDBCToFile(); - void saveAsDBCToFile(); + void save(); + void saveAs(); void saveDBCToClipboard(); signals: @@ -36,6 +38,11 @@ signals: void updateProgressBar(uint64_t cur, uint64_t total, bool success); protected: + void remindSaveChanges(); + void saveFile(const QString &fn); + void loadFile(const QString &fn); + void setCurrentFile(const QString &fn); + void updateRecentFileActions(); void createActions(); void createDockWindows(); QComboBox *createDBCSelector(); @@ -58,5 +65,8 @@ protected: QJsonDocument fingerprint_to_dbc; QComboBox *dbc_combo; QSplitter *video_splitter;; - QString file_name = ""; + QString current_file = ""; + enum { MAX_RECENT_FILES = 15 }; + QAction *recent_files_acts[MAX_RECENT_FILES] = {}; + QMenu *open_recent_menu = nullptr; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 7d34d5dec0..78969c76c3 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -23,6 +23,7 @@ void Settings::save() { s.setValue("window_state", window_state); s.setValue("geometry", geometry); s.setValue("video_splitter_state", video_splitter_state); + s.setValue("recent_files", recent_files); s.setValue("message_header_state", message_header_state); } @@ -37,6 +38,7 @@ void Settings::load() { window_state = s.value("window_state").toByteArray(); geometry = s.value("geometry").toByteArray(); video_splitter_state = s.value("video_splitter_state").toByteArray(); + recent_files = s.value("recent_files").toStringList(); message_header_state = s.value("message_header_state").toByteArray(); } diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 7b0cbc9f5d..56c6a992ae 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -22,6 +22,7 @@ public: QByteArray geometry; QByteArray video_splitter_state; QByteArray window_state; + QStringList recent_files; QByteArray message_header_state; signals: From 1d9b4c2248f2e4b575e37b6b134880086f1ba0b4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 26 Jan 2023 21:05:39 -0800 Subject: [PATCH 0746/1179] cleanup panda mcu definitions (#27104) * cleanup panda mcu definitions * cleanup panda mcu definitions * bump * panda master --- panda | 2 +- selfdrive/boardd/pandad.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/panda b/panda index ae051c94a3..76d0459182 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit ae051c94a393550ab8d70c594fc9dfb49bc9aed8 +Subproject commit 76d0459182d544d17c86d8b352e9cc1c26035f4d diff --git a/selfdrive/boardd/pandad.py b/selfdrive/boardd/pandad.py index 971756002b..f61d9ee1a6 100755 --- a/selfdrive/boardd/pandad.py +++ b/selfdrive/boardd/pandad.py @@ -7,7 +7,7 @@ import subprocess from typing import List, NoReturn from functools import cmp_to_key -from panda import DEFAULT_FW_FN, DEFAULT_H7_FW_FN, MCU_TYPE_H7, Panda, PandaDFU +from panda import Panda, PandaDFU from common.basedir import BASEDIR from common.params import Params from system.hardware import HARDWARE @@ -15,10 +15,8 @@ from system.swaglog import cloudlog def get_expected_signature(panda: Panda) -> bytes: - fn = DEFAULT_H7_FW_FN if (panda.get_mcu_type() == MCU_TYPE_H7) else DEFAULT_FW_FN - try: - return Panda.get_signature_from_firmware(fn) + return Panda.get_signature_from_firmware(panda.get_mcu_type().config.app_path) except Exception: cloudlog.exception("Error computing expected signature") return b"" From 701b7d89b65b6cf936ed6893de09c45f6c982ca4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 22:29:01 -0800 Subject: [PATCH 0747/1179] Ford: use curvature without roll compensation (#27110) * Ford: use actuators.curvature * ford is mathless --- selfdrive/car/ford/carcontroller.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index ab5cf267e0..06da87bf34 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -1,4 +1,3 @@ -import math from cereal import car from common.numpy_fast import clip from opendbc.can.packer import CANPacker @@ -46,10 +45,8 @@ class CarController: # send steering commands at 20Hz if (self.frame % CarControllerParams.STEER_STEP) == 0: if CC.latActive: - # apply limits to curvature - apply_curvature = -self.VM.calc_curvature(math.radians(actuators.steeringAngleDeg), CS.out.vEgo, 0.0) - apply_curvature = apply_std_steer_angle_limits(apply_curvature, self.apply_curvature_last, CS.out.vEgo, CarControllerParams) - # clip to signal range + # apply limits to curvature and clip to signal range + apply_curvature = apply_std_steer_angle_limits(actuators.curvature, self.apply_curvature_last, CS.out.vEgo, CarControllerParams) apply_curvature = clip(apply_curvature, -CarControllerParams.CURVATURE_MAX, CarControllerParams.CURVATURE_MAX) else: apply_curvature = 0. From 226d80964d4586392266fd2e711e6b6c003602de Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 26 Jan 2023 23:14:05 -0800 Subject: [PATCH 0748/1179] Ford: lower lateral actuator delay (#27113) Update interface.py --- selfdrive/car/ford/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index cea39d8b00..14592a5f68 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -19,7 +19,7 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = True ret.steerControlType = car.CarParams.SteerControlType.angle - ret.steerActuatorDelay = 0.25 + ret.steerActuatorDelay = 0.2 ret.steerLimitTimer = 1.0 if candidate == CAR.BRONCO_SPORT_MK1: From 0eed31f1a68315121a3319464869cc622947ebba Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 27 Jan 2023 11:27:07 -0800 Subject: [PATCH 0749/1179] process replay: show process name in timeout error --- selfdrive/test/process_replay/process_replay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 06af4469f2..7172c112aa 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -554,7 +554,7 @@ def cpp_replay_process(cfg, lr, fingerprint=None): managed_processes[cfg.proc_name].start() try: - with Timeout(TIMEOUT): + with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}"): while not all(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): time.sleep(0) From f0078eafac20ac5af7e9683e61045bfb524f82cf Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 28 Jan 2023 03:33:52 +0800 Subject: [PATCH 0750/1179] cabana: set time column to fixed width (#27117) improve column width --- tools/cabana/historylog.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 970aafd342..a2a90e4f0c 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -170,11 +170,16 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti // HeaderView QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { - int default_size = qMax(100, rect().width() / model()->columnCount()); - const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); - const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text); - QSize size = rect.size() + QSize{10, 6}; - return {qMax(size.width(), default_size), size.height()}; + static QSize time_col_size = fontMetrics().boundingRect({0, 0, 200, 200}, defaultAlignment(), "000000.000").size() + QSize(10, 6); + if (logicalIndex == 0) { + return time_col_size; + } else { + int default_size = qMax(100, (rect().width() - time_col_size.width()) / (model()->columnCount() - 1)); + const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); + const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text); + QSize size = rect.size() + QSize{10, 6}; + return QSize{qMax(size.width(), default_size), size.height()}; + } } void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { From e1e043231720712d7c1e2d7342f13756d68efcde Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 28 Jan 2023 03:34:17 +0800 Subject: [PATCH 0751/1179] cabana: display warning if failed to load dbc from clipboard (#27115) display warning if failed to load from clipboard --- tools/cabana/mainwin.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 7d99b698bb..d674ec9059 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -238,7 +238,11 @@ void MainWindow::loadDBCFromClipboard() { remindSaveChanges(); QString dbc_str = QGuiApplication::clipboard()->text(); dbc()->open("from_clipboard.dbc", dbc_str); - QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); + if (dbc()->messages().size() > 0) { + QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); + } else { + QMessageBox::warning(this, tr("Load From Clipboard"), tr("Failed to parse dbc from clipboard!\nMake sure that you paste the text with correct format.")); + } } void MainWindow::loadDBCFromFingerprint() { From 4f25bd05f29c81d622ad57a8d608006ab1baf5e6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 27 Jan 2023 13:06:33 -0800 Subject: [PATCH 0752/1179] process replay: test routes in dashcam (#27118) * fix routes with dashcam override param * move to bottom --- selfdrive/test/process_replay/process_replay.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 7172c112aa..606dcad9c4 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -448,6 +448,9 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): if CP.openpilotLongitudinalControl: params.put_bool("ExperimentalLongitudinalEnabled", True) + # controlsd process configuration assume all routes are out of dashcam + params.put_bool("DashcamOverride", True) + def python_replay_process(cfg, lr, fingerprint=None): sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] From 60f73657def5aefdae7e1ceb6d32ae9b0cc3b880 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 27 Jan 2023 13:44:37 -0800 Subject: [PATCH 0753/1179] Ford: set radarOffCan (#27120) Fix --- selfdrive/car/ford/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 14592a5f68..7c6a8ecbe4 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -18,6 +18,7 @@ class CarInterface(CarInterfaceBase): # These cars are dashcam only until the port is finished ret.dashcamOnly = True + ret.radarOffCan = True ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerActuatorDelay = 0.2 ret.steerLimitTimer = 1.0 From cb62a5397e1a0d9603308e143339bf6e31c3d2e4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 27 Jan 2023 14:14:04 -0800 Subject: [PATCH 0754/1179] process replay: add Ford Bronco Sport segment (#27112) * Add Ford segment to process replay * fix dashcam cars * clean up * fix NotImplementedError * Update refs --- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/test_processes.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 63db584c87..dcd2f7b224 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -634d4ff195345a4a2508e497744aa08addec9237 +ec92fe65806256cb5180cfd5ec60895efcc08da2 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index c58909bf7f..569090f606 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -29,6 +29,7 @@ source_segments = [ ("SUBARU", "341dccd5359e3c97|2022-09-12--10-35-33--3"), # SUBARU.OUTBACK ("GM", "0c58b6a25109da2b|2021-02-23--16-35-50--11"), # GM.VOLT ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), # GM.BOLT_EUV + ("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), # FORD.BRONCO_SPORT_MK1 ("NISSAN", "35336926920f3571|2021-02-12--18-38-48--46"), # NISSAN.XTRAIL ("VOLKSWAGEN", "de9592456ad7d144|2021-06-29--11-00-15--6"), # VOLKSWAGEN.GOLF ("MAZDA", "bd6a637565e91581|2021-10-30--15-14-53--4"), # MAZDA.CX9_2021 @@ -52,6 +53,7 @@ segments = [ ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"), ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), + ("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), ("NISSAN", "regenC19D899B46D|2022-09-27--15-59-13--0"), ("VOLKSWAGEN", "regenD8F7AC4BD0D|2022-09-27--16-41-45--0"), ("MAZDA", "regenFC3F9ECBB64|2022-09-27--16-03-09--0"), From 8d447e8a081e878a55707cc2840a6d08d88102ca Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Fri, 27 Jan 2023 15:20:59 -0800 Subject: [PATCH 0755/1179] [RAM 1500 5TH GEN] Disable Live Torque (#27121) * revert ram on live torque * update refs * update refs --- selfdrive/car/torque_data/override.yaml | 1 + selfdrive/car/torque_data/params.yaml | 1 - selfdrive/locationd/torqued.py | 3 +-- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 733aa34343..0a49d39914 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -23,6 +23,7 @@ FORD MAVERICK 1ST GEN: [.nan, 1.5, .nan] COMMA BODY: [.nan, 1000, .nan] # Totally new cars +RAM 1500 5TH GEN: [2.0, 2.0, 0.0] RAM HD 5TH GEN: [1.4, 1.4, 0.0] SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] CHEVROLET BOLT EV 2022: [2.0, 2.0, 0.05] diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 6a607f3a8a..397b29525d 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -56,7 +56,6 @@ LEXUS RX 2020: [1.5228812994274734, 1.431102486563665, 0.164117] LEXUS RX HYBRID 2017: [1.6984261557042386, 1.3211501880159107, 0.1820354534928893] LEXUS RX HYBRID 2020: [1.5522309889823778, 1.255230465866663, 0.2220954003055114] MAZDA CX-9 2021: [1.7601682915983443, 1.0889677335154337, 0.17713792194297195] -RAM 1500 5TH GEN: [1.550848, 2.0, 0.132261] SKODA SUPERB 3RD GEN: [1.166437404652981, 1.1686163012668165, 0.12194533036948708] SUBARU FORESTER 2019: [3.6617001649776793, 2.342197172531713, 0.11075960785398745] SUBARU IMPREZA LIMITED 2019: [1.0670704910352047, 0.8234374840709592, 0.20986563268614938] diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index 5449152686..fcc068d34e 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -35,7 +35,6 @@ MIN_ENGAGE_BUFFER = 2 # secs VERSION = 1 # bump this to invalidate old parameter caches ALLOWED_CARS = ['toyota', 'hyundai'] -ALLOWED_PLATFORMS = ['RAM 1500 5TH GEN'] # for adding individual platforms from a brand without torqued def slope2rot(slope): @@ -114,7 +113,7 @@ class TorqueEstimator: self.offline_friction = 0.0 self.offline_latAccelFactor = 0.0 self.resets = 0.0 - self.use_params = (CP.carName in ALLOWED_CARS) or (CP.carFingerprint in ALLOWED_PLATFORMS) + self.use_params = CP.carName in ALLOWED_CARS if CP.lateralTuning.which() == 'torque': self.offline_friction = CP.lateralTuning.torque.friction diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dcd2f7b224..51de0f0013 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -ec92fe65806256cb5180cfd5ec60895efcc08da2 \ No newline at end of file +844c84eae269e74b246b039d2b33fd44e98a5b68 \ No newline at end of file From 07b32750c16fe4e71abbf81e07aa839ac60b5343 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 29 Jan 2023 04:03:59 +0800 Subject: [PATCH 0756/1179] cabana: remove extra frame border in logs (#27133) remove extra frame border --- tools/cabana/historylog.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index a2a90e4f0c..ccc2c5533d 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -195,8 +195,13 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); + + QWidget *toolbar = new QWidget(this); + toolbar->setAutoFillBackground(true); + QHBoxLayout *h = new QHBoxLayout(toolbar); - QHBoxLayout *h = new QHBoxLayout(); filters_widget = new QWidget(this); QHBoxLayout *filter_layout = new QHBoxLayout(filters_widget); filter_layout->setContentsMargins(0, 0, 0, 0); @@ -215,7 +220,11 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { dynamic_mode->setChecked(true); dynamic_mode->setEnabled(!can->liveStreaming()); - main_layout->addLayout(h); + main_layout->addWidget(toolbar); + QFrame *line = new QFrame(this); + line->setFrameStyle(QFrame::HLine | QFrame::Sunken); + main_layout->addWidget(line);; + main_layout->addWidget(logs = new QTableView(this)); logs->setModel(model = new HistoryLogModel(this)); logs->setItemDelegateForColumn(1, new MessageBytesDelegate(this)); @@ -223,6 +232,7 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { logs->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); logs->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); logs->verticalHeader()->setVisible(false); + logs->setFrameShape(QFrame::NoFrame); QObject::connect(display_type_cb, SIGNAL(activated(int)), model, SLOT(setDisplayType(int))); QObject::connect(dynamic_mode, &QCheckBox::stateChanged, model, &HistoryLogModel::setDynamicMode); From 68c0012bf62bcbe9a273d8d4caca0c1ce0d8e9bb Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sat, 28 Jan 2023 21:05:51 +0100 Subject: [PATCH 0757/1179] cabana: DoubleValidator fix locale (#27129) --- tools/cabana/signaledit.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index cc57cf0f3e..112c2807f9 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -12,6 +12,8 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { auto double_validator = new QDoubleValidator(this); + double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system + QVBoxLayout *main_layout = new QVBoxLayout(this); QFormLayout *form_layout = new QFormLayout(); main_layout->addLayout(form_layout); From ba5c6715a8099eb5850382a5b7918da33a6c13dd Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sat, 28 Jan 2023 21:06:04 +0100 Subject: [PATCH 0758/1179] cabana: fix crash when combining graphs on MacOS (#27128) --- tools/cabana/chartswidget.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5d0e5d7a52..3ecdbb08bd 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -578,8 +578,9 @@ void ChartView::mousePressEvent(QMouseEvent *event) { if (dropAction == Qt::MoveAction) { return; } + } else { + QChartView::mousePressEvent(event); } - QChartView::mousePressEvent(event); } void ChartView::mouseReleaseEvent(QMouseEvent *event) { From 7f853819767bb92488b9614b8a7b3e0210f9ecb5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 28 Jan 2023 15:00:27 -0800 Subject: [PATCH 0759/1179] bump panda (#27136) * bump panda * bump --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 76d0459182..e7f36a2992 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 76d0459182d544d17c86d8b352e9cc1c26035f4d +Subproject commit e7f36a2992b353d7d66fbb697d166d4de8718c99 From aa71947ebc9c286a13f86458ea0e970ca0d7a0c7 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 28 Jan 2023 16:47:26 -0800 Subject: [PATCH 0760/1179] add signs to glonass ksy --- selfdrive/locationd/generated/glonass.cpp | 176 ++++++++++++++++++-- selfdrive/locationd/generated/glonass.h | 191 +++++++++++++++++++--- selfdrive/locationd/glonass.ksy | 119 +++++++++++--- 3 files changed, 425 insertions(+), 61 deletions(-) diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp index 149134fbb5..a342bdff22 100644 --- a/selfdrive/locationd/generated/glonass.cpp +++ b/selfdrive/locationd/generated/glonass.cpp @@ -31,6 +31,10 @@ void glonass_t::_read() { m_data = new string_3_t(m__io, this, m__root); break; } + case 5: { + m_data = new string_5_t(m__io, this, m__root); + break; + } case 2: { m_data = new string_2_t(m__io, this, m__root); break; @@ -60,6 +64,8 @@ void glonass_t::_clean_up() { glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_tau_n = false; + f_delta_tau_n = false; try { _read(); @@ -70,8 +76,10 @@ glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, } void glonass_t::string_4_t::_read() { - m_tau_n = m__io->read_bits_int_be(22); - m_delta_tau_n = m__io->read_bits_int_be(5); + m_tau_n_sign = m__io->read_bits_int_be(1); + m_tau_n_value = m__io->read_bits_int_be(21); + m_delta_tau_n_sign = m__io->read_bits_int_be(1); + m_delta_tau_n_value = m__io->read_bits_int_be(4); m_e_n = m__io->read_bits_int_be(5); m_not_used_1 = m__io->read_bits_int_be(14); m_p4 = m__io->read_bits_int_be(1); @@ -89,6 +97,22 @@ glonass_t::string_4_t::~string_4_t() { void glonass_t::string_4_t::_clean_up() { } +int32_t glonass_t::string_4_t::tau_n() { + if (f_tau_n) + return m_tau_n; + m_tau_n = ((tau_n_sign()) ? ((tau_n_value() - (1 << 21))) : (tau_n_value())); + f_tau_n = true; + return m_tau_n; +} + +int32_t glonass_t::string_4_t::delta_tau_n() { + if (f_delta_tau_n) + return m_delta_tau_n; + m_delta_tau_n = ((delta_tau_n_sign()) ? ((delta_tau_n_value() - (1 << 4))) : (delta_tau_n_value())); + f_delta_tau_n = true; + return m_delta_tau_n; +} + glonass_t::string_non_immediate_t::string_non_immediate_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; @@ -113,9 +137,40 @@ glonass_t::string_non_immediate_t::~string_non_immediate_t() { void glonass_t::string_non_immediate_t::_clean_up() { } +glonass_t::string_5_t::string_5_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_5_t::_read() { + m_n_a = m__io->read_bits_int_be(11); + m_tau_e = m__io->read_bits_int_be(32); + m_not_used = m__io->read_bits_int_be(1); + m_n_4 = m__io->read_bits_int_be(5); + m_tau_gps = m__io->read_bits_int_be(22); + m_l_n = m__io->read_bits_int_be(1); +} + +glonass_t::string_5_t::~string_5_t() { + _clean_up(); +} + +void glonass_t::string_5_t::_clean_up() { +} + glonass_t::string_1_t::string_1_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_x_vel = false; + f_x_accel = false; + f_x = false; try { _read(); @@ -129,9 +184,12 @@ void glonass_t::string_1_t::_read() { m_not_used = m__io->read_bits_int_be(2); m_p1 = m__io->read_bits_int_be(2); m_t_k = m__io->read_bits_int_be(12); - m_x_vel = m__io->read_bits_int_be(24); - m_x_speedup = m__io->read_bits_int_be(5); - m_x = m__io->read_bits_int_be(27); + m_x_vel_sign = m__io->read_bits_int_be(1); + m_x_vel_value = m__io->read_bits_int_be(23); + m_x_accel_sign = m__io->read_bits_int_be(1); + m_x_accel_value = m__io->read_bits_int_be(4); + m_x_sign = m__io->read_bits_int_be(1); + m_x_value = m__io->read_bits_int_be(26); } glonass_t::string_1_t::~string_1_t() { @@ -141,9 +199,36 @@ glonass_t::string_1_t::~string_1_t() { void glonass_t::string_1_t::_clean_up() { } +int32_t glonass_t::string_1_t::x_vel() { + if (f_x_vel) + return m_x_vel; + m_x_vel = ((x_vel_sign()) ? ((x_vel_value() - (1 << 23))) : (x_vel_value())); + f_x_vel = true; + return m_x_vel; +} + +int32_t glonass_t::string_1_t::x_accel() { + if (f_x_accel) + return m_x_accel; + m_x_accel = ((x_accel_sign()) ? ((x_accel_value() - (1 << 4))) : (x_accel_value())); + f_x_accel = true; + return m_x_accel; +} + +int32_t glonass_t::string_1_t::x() { + if (f_x) + return m_x; + m_x = ((x_sign()) ? ((x_value() - (1 << 26))) : (x_value())); + f_x = true; + return m_x; +} + glonass_t::string_2_t::string_2_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_y_vel = false; + f_y_accel = false; + f_y = false; try { _read(); @@ -158,9 +243,12 @@ void glonass_t::string_2_t::_read() { m_p2 = m__io->read_bits_int_be(1); m_t_b = m__io->read_bits_int_be(7); m_not_used = m__io->read_bits_int_be(5); - m_y_vel = m__io->read_bits_int_be(24); - m_y_speedup = m__io->read_bits_int_be(5); - m_y = m__io->read_bits_int_be(27); + m_y_vel_sign = m__io->read_bits_int_be(1); + m_y_vel_value = m__io->read_bits_int_be(23); + m_y_accel_sign = m__io->read_bits_int_be(1); + m_y_accel_value = m__io->read_bits_int_be(4); + m_y_sign = m__io->read_bits_int_be(1); + m_y_value = m__io->read_bits_int_be(26); } glonass_t::string_2_t::~string_2_t() { @@ -170,9 +258,37 @@ glonass_t::string_2_t::~string_2_t() { void glonass_t::string_2_t::_clean_up() { } +int32_t glonass_t::string_2_t::y_vel() { + if (f_y_vel) + return m_y_vel; + m_y_vel = ((y_vel_sign()) ? ((y_vel_value() - (1 << 23))) : (y_vel_value())); + f_y_vel = true; + return m_y_vel; +} + +int32_t glonass_t::string_2_t::y_accel() { + if (f_y_accel) + return m_y_accel; + m_y_accel = ((y_accel_sign()) ? ((y_accel_value() - (1 << 4))) : (y_accel_value())); + f_y_accel = true; + return m_y_accel; +} + +int32_t glonass_t::string_2_t::y() { + if (f_y) + return m_y; + m_y = ((y_sign()) ? ((y_value() - (1 << 26))) : (y_value())); + f_y = true; + return m_y; +} + glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_gamma_n = false; + f_z_vel = false; + f_z_accel = false; + f_z = false; try { _read(); @@ -184,13 +300,17 @@ glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, void glonass_t::string_3_t::_read() { m_p3 = m__io->read_bits_int_be(1); - m_gamma_n = m__io->read_bits_int_be(11); + m_gamma_n_sign = m__io->read_bits_int_be(1); + m_gamma_n_value = m__io->read_bits_int_be(10); m_not_used = m__io->read_bits_int_be(1); m_p = m__io->read_bits_int_be(2); m_l_n = m__io->read_bits_int_be(1); - m_z_vel = m__io->read_bits_int_be(24); - m_z_speedup = m__io->read_bits_int_be(5); - m_z = m__io->read_bits_int_be(27); + m_z_vel_sign = m__io->read_bits_int_be(1); + m_z_vel_value = m__io->read_bits_int_be(23); + m_z_accel_sign = m__io->read_bits_int_be(1); + m_z_accel_value = m__io->read_bits_int_be(4); + m_z_sign = m__io->read_bits_int_be(1); + m_z_value = m__io->read_bits_int_be(26); } glonass_t::string_3_t::~string_3_t() { @@ -199,3 +319,35 @@ glonass_t::string_3_t::~string_3_t() { void glonass_t::string_3_t::_clean_up() { } + +int32_t glonass_t::string_3_t::gamma_n() { + if (f_gamma_n) + return m_gamma_n; + m_gamma_n = ((gamma_n_sign()) ? ((gamma_n_value() - (1 << 10))) : (gamma_n_value())); + f_gamma_n = true; + return m_gamma_n; +} + +int32_t glonass_t::string_3_t::z_vel() { + if (f_z_vel) + return m_z_vel; + m_z_vel = ((z_vel_sign()) ? ((z_vel_value() - (1 << 23))) : (z_vel_value())); + f_z_vel = true; + return m_z_vel; +} + +int32_t glonass_t::string_3_t::z_accel() { + if (f_z_accel) + return m_z_accel; + m_z_accel = ((z_accel_sign()) ? ((z_accel_value() - (1 << 4))) : (z_accel_value())); + f_z_accel = true; + return m_z_accel; +} + +int32_t glonass_t::string_3_t::z() { + if (f_z) + return m_z; + m_z = ((z_sign()) ? ((z_value() - (1 << 26))) : (z_value())); + f_z = true; + return m_z; +} diff --git a/selfdrive/locationd/generated/glonass.h b/selfdrive/locationd/generated/glonass.h index 48bdabfe96..3b7917ef4b 100644 --- a/selfdrive/locationd/generated/glonass.h +++ b/selfdrive/locationd/generated/glonass.h @@ -15,6 +15,7 @@ class glonass_t : public kaitai::kstruct { public: class string_4_t; class string_non_immediate_t; + class string_5_t; class string_1_t; class string_2_t; class string_3_t; @@ -42,8 +43,24 @@ public: ~string_4_t(); private: - uint64_t m_tau_n; - uint64_t m_delta_tau_n; + bool f_tau_n; + int32_t m_tau_n; + + public: + int32_t tau_n(); + + private: + bool f_delta_tau_n; + int32_t m_delta_tau_n; + + public: + int32_t delta_tau_n(); + + private: + bool m_tau_n_sign; + uint64_t m_tau_n_value; + bool m_delta_tau_n_sign; + uint64_t m_delta_tau_n_value; uint64_t m_e_n; uint64_t m_not_used_1; bool m_p4; @@ -56,8 +73,10 @@ public: glonass_t* m__parent; public: - uint64_t tau_n() const { return m_tau_n; } - uint64_t delta_tau_n() const { return m_delta_tau_n; } + bool tau_n_sign() const { return m_tau_n_sign; } + uint64_t tau_n_value() const { return m_tau_n_value; } + bool delta_tau_n_sign() const { return m_delta_tau_n_sign; } + uint64_t delta_tau_n_value() const { return m_delta_tau_n_value; } uint64_t e_n() const { return m_e_n; } uint64_t not_used_1() const { return m_not_used_1; } bool p4() const { return m_p4; } @@ -96,6 +115,40 @@ public: glonass_t* _parent() const { return m__parent; } }; + class string_5_t : public kaitai::kstruct { + + public: + + string_5_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_5_t(); + + private: + uint64_t m_n_a; + uint64_t m_tau_e; + bool m_not_used; + uint64_t m_n_4; + uint64_t m_tau_gps; + bool m_l_n; + glonass_t* m__root; + glonass_t* m__parent; + + public: + uint64_t n_a() const { return m_n_a; } + uint64_t tau_e() const { return m_tau_e; } + bool not_used() const { return m_not_used; } + uint64_t n_4() const { return m_n_4; } + uint64_t tau_gps() const { return m_tau_gps; } + bool l_n() const { return m_l_n; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + class string_1_t : public kaitai::kstruct { public: @@ -109,13 +162,37 @@ public: public: ~string_1_t(); + private: + bool f_x_vel; + int32_t m_x_vel; + + public: + int32_t x_vel(); + + private: + bool f_x_accel; + int32_t m_x_accel; + + public: + int32_t x_accel(); + + private: + bool f_x; + int32_t m_x; + + public: + int32_t x(); + private: uint64_t m_not_used; uint64_t m_p1; uint64_t m_t_k; - uint64_t m_x_vel; - uint64_t m_x_speedup; - uint64_t m_x; + bool m_x_vel_sign; + uint64_t m_x_vel_value; + bool m_x_accel_sign; + uint64_t m_x_accel_value; + bool m_x_sign; + uint64_t m_x_value; glonass_t* m__root; glonass_t* m__parent; @@ -123,9 +200,12 @@ public: uint64_t not_used() const { return m_not_used; } uint64_t p1() const { return m_p1; } uint64_t t_k() const { return m_t_k; } - uint64_t x_vel() const { return m_x_vel; } - uint64_t x_speedup() const { return m_x_speedup; } - uint64_t x() const { return m_x; } + bool x_vel_sign() const { return m_x_vel_sign; } + uint64_t x_vel_value() const { return m_x_vel_value; } + bool x_accel_sign() const { return m_x_accel_sign; } + uint64_t x_accel_value() const { return m_x_accel_value; } + bool x_sign() const { return m_x_sign; } + uint64_t x_value() const { return m_x_value; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; @@ -143,14 +223,38 @@ public: public: ~string_2_t(); + private: + bool f_y_vel; + int32_t m_y_vel; + + public: + int32_t y_vel(); + + private: + bool f_y_accel; + int32_t m_y_accel; + + public: + int32_t y_accel(); + + private: + bool f_y; + int32_t m_y; + + public: + int32_t y(); + private: uint64_t m_b_n; bool m_p2; uint64_t m_t_b; uint64_t m_not_used; - uint64_t m_y_vel; - uint64_t m_y_speedup; - uint64_t m_y; + bool m_y_vel_sign; + uint64_t m_y_vel_value; + bool m_y_accel_sign; + uint64_t m_y_accel_value; + bool m_y_sign; + uint64_t m_y_value; glonass_t* m__root; glonass_t* m__parent; @@ -159,9 +263,12 @@ public: bool p2() const { return m_p2; } uint64_t t_b() const { return m_t_b; } uint64_t not_used() const { return m_not_used; } - uint64_t y_vel() const { return m_y_vel; } - uint64_t y_speedup() const { return m_y_speedup; } - uint64_t y() const { return m_y; } + bool y_vel_sign() const { return m_y_vel_sign; } + uint64_t y_vel_value() const { return m_y_vel_value; } + bool y_accel_sign() const { return m_y_accel_sign; } + uint64_t y_accel_value() const { return m_y_accel_value; } + bool y_sign() const { return m_y_sign; } + uint64_t y_value() const { return m_y_value; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; @@ -179,27 +286,63 @@ public: public: ~string_3_t(); + private: + bool f_gamma_n; + int32_t m_gamma_n; + + public: + int32_t gamma_n(); + + private: + bool f_z_vel; + int32_t m_z_vel; + + public: + int32_t z_vel(); + + private: + bool f_z_accel; + int32_t m_z_accel; + + public: + int32_t z_accel(); + + private: + bool f_z; + int32_t m_z; + + public: + int32_t z(); + private: bool m_p3; - uint64_t m_gamma_n; + bool m_gamma_n_sign; + uint64_t m_gamma_n_value; bool m_not_used; uint64_t m_p; bool m_l_n; - uint64_t m_z_vel; - uint64_t m_z_speedup; - uint64_t m_z; + bool m_z_vel_sign; + uint64_t m_z_vel_value; + bool m_z_accel_sign; + uint64_t m_z_accel_value; + bool m_z_sign; + uint64_t m_z_value; glonass_t* m__root; glonass_t* m__parent; public: bool p3() const { return m_p3; } - uint64_t gamma_n() const { return m_gamma_n; } + bool gamma_n_sign() const { return m_gamma_n_sign; } + uint64_t gamma_n_value() const { return m_gamma_n_value; } bool not_used() const { return m_not_used; } uint64_t p() const { return m_p; } bool l_n() const { return m_l_n; } - uint64_t z_vel() const { return m_z_vel; } - uint64_t z_speedup() const { return m_z_speedup; } - uint64_t z() const { return m_z; } + bool z_vel_sign() const { return m_z_vel_sign; } + uint64_t z_vel_value() const { return m_z_vel_value; } + bool z_accel_sign() const { return m_z_accel_sign; } + uint64_t z_accel_value() const { return m_z_accel_value; } + bool z_sign() const { return m_z_sign; } + uint64_t z_value() const { return m_z_value; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; diff --git a/selfdrive/locationd/glonass.ksy b/selfdrive/locationd/glonass.ksy index 95ca78c16f..36e5c91740 100644 --- a/selfdrive/locationd/glonass.ksy +++ b/selfdrive/locationd/glonass.ksy @@ -1,4 +1,6 @@ # http://gauss.gge.unb.ca/GLONASS.ICD.pdf +# some variables are misprinted but good in the old doc +# https://www.unavco.org/help/glossary/docs/ICD_GLONASS_4.0_(1998)_en.pdf meta: id: glonass endian: be @@ -16,6 +18,7 @@ seq: 2: string_2 3: string_3 4: string_4 + 5: string_5 _: string_non_immediate - id: hamming_code type: b8 @@ -37,12 +40,25 @@ types: type: b2 - id: t_k type: b12 - - id: x_vel - type: b24 - - id: x_speedup - type: b5 - - id: x - type: b27 + - id: x_vel_sign + type: b1 + - id: x_vel_value + type: b23 + - id: x_accel_sign + type: b1 + - id: x_accel_value + type: b4 + - id: x_sign + type: b1 + - id: x_value + type: b26 + instances: + x_vel: + value: 'x_vel_sign ? (x_vel_value - (1 << 23)) : x_vel_value' + x_accel: + value: 'x_accel_sign ? (x_accel_value - (1 << 4)) : x_accel_value' + x: + value: 'x_sign ? (x_value - (1 << 26)) : x_value' string_2: seq: - id: b_n @@ -53,36 +69,70 @@ types: type: b7 - id: not_used type: b5 - - id: y_vel - type: b24 - - id: y_speedup - type: b5 - - id: y - type: b27 + - id: y_vel_sign + type: b1 + - id: y_vel_value + type: b23 + - id: y_accel_sign + type: b1 + - id: y_accel_value + type: b4 + - id: y_sign + type: b1 + - id: y_value + type: b26 + instances: + y_vel: + value: 'y_vel_sign ? (y_vel_value - (1 << 23)) : y_vel_value' + y_accel: + value: 'y_accel_sign ? (y_accel_value - (1 << 4)) : y_accel_value' + y: + value: 'y_sign ? (y_value - (1 << 26)) : y_value' string_3: seq: - id: p3 type: b1 - - id: gamma_n - type: b11 + - id: gamma_n_sign + type: b1 + - id: gamma_n_value + type: b10 - id: not_used type: b1 - id: p type: b2 - id: l_n type: b1 - - id: z_vel - type: b24 - - id: z_speedup - type: b5 - - id: z - type: b27 + - id: z_vel_sign + type: b1 + - id: z_vel_value + type: b23 + - id: z_accel_sign + type: b1 + - id: z_accel_value + type: b4 + - id: z_sign + type: b1 + - id: z_value + type: b26 + instances: + gamma_n: + value: 'gamma_n_sign ? (gamma_n_value - (1 << 10)) : gamma_n_value' + z_vel: + value: 'z_vel_sign ? (z_vel_value - (1 << 23)) : z_vel_value' + z_accel: + value: 'z_accel_sign ? (z_accel_value - (1 << 4)) : z_accel_value' + z: + value: 'z_sign ? (z_value - (1 << 26)) : z_value' string_4: seq: - - id: tau_n - type: b22 - - id: delta_tau_n - type: b5 + - id: tau_n_sign + type: b1 + - id: tau_n_value + type: b21 + - id: delta_tau_n_sign + type: b1 + - id: delta_tau_n_value + type: b4 - id: e_n type: b5 - id: not_used_1 @@ -99,9 +149,28 @@ types: type: b5 - id: m type: b2 + instances: + tau_n: + value: 'tau_n_sign ? (tau_n_value - (1 << 21)) : tau_n_value' + delta_tau_n: + value: 'delta_tau_n_sign ? (delta_tau_n_value - (1 << 4)) : delta_tau_n_value' + string_5: + seq: + - id: n_a + type: b11 + - id: tau_e + type: b32 + - id: not_used + type: b1 + - id: n_4 + type: b5 + - id: tau_gps + type: b22 + - id: l_n + type: b1 string_non_immediate: seq: - id: data_1 type: b64 - id: data_2 - type: b8 \ No newline at end of file + type: b8 From 53ccec7697247a06ad64fe056dcf07e026a011af Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Sat, 28 Jan 2023 16:48:26 -0800 Subject: [PATCH 0761/1179] Revert "add signs to glonass ksy" This reverts commit aa71947ebc9c286a13f86458ea0e970ca0d7a0c7. --- selfdrive/locationd/generated/glonass.cpp | 176 ++------------------ selfdrive/locationd/generated/glonass.h | 191 +++------------------- selfdrive/locationd/glonass.ksy | 119 +++----------- 3 files changed, 61 insertions(+), 425 deletions(-) diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp index a342bdff22..149134fbb5 100644 --- a/selfdrive/locationd/generated/glonass.cpp +++ b/selfdrive/locationd/generated/glonass.cpp @@ -31,10 +31,6 @@ void glonass_t::_read() { m_data = new string_3_t(m__io, this, m__root); break; } - case 5: { - m_data = new string_5_t(m__io, this, m__root); - break; - } case 2: { m_data = new string_2_t(m__io, this, m__root); break; @@ -64,8 +60,6 @@ void glonass_t::_clean_up() { glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - f_tau_n = false; - f_delta_tau_n = false; try { _read(); @@ -76,10 +70,8 @@ glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, } void glonass_t::string_4_t::_read() { - m_tau_n_sign = m__io->read_bits_int_be(1); - m_tau_n_value = m__io->read_bits_int_be(21); - m_delta_tau_n_sign = m__io->read_bits_int_be(1); - m_delta_tau_n_value = m__io->read_bits_int_be(4); + m_tau_n = m__io->read_bits_int_be(22); + m_delta_tau_n = m__io->read_bits_int_be(5); m_e_n = m__io->read_bits_int_be(5); m_not_used_1 = m__io->read_bits_int_be(14); m_p4 = m__io->read_bits_int_be(1); @@ -97,22 +89,6 @@ glonass_t::string_4_t::~string_4_t() { void glonass_t::string_4_t::_clean_up() { } -int32_t glonass_t::string_4_t::tau_n() { - if (f_tau_n) - return m_tau_n; - m_tau_n = ((tau_n_sign()) ? ((tau_n_value() - (1 << 21))) : (tau_n_value())); - f_tau_n = true; - return m_tau_n; -} - -int32_t glonass_t::string_4_t::delta_tau_n() { - if (f_delta_tau_n) - return m_delta_tau_n; - m_delta_tau_n = ((delta_tau_n_sign()) ? ((delta_tau_n_value() - (1 << 4))) : (delta_tau_n_value())); - f_delta_tau_n = true; - return m_delta_tau_n; -} - glonass_t::string_non_immediate_t::string_non_immediate_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; @@ -137,40 +113,9 @@ glonass_t::string_non_immediate_t::~string_non_immediate_t() { void glonass_t::string_non_immediate_t::_clean_up() { } -glonass_t::string_5_t::string_5_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { - m__parent = p__parent; - m__root = p__root; - - try { - _read(); - } catch(...) { - _clean_up(); - throw; - } -} - -void glonass_t::string_5_t::_read() { - m_n_a = m__io->read_bits_int_be(11); - m_tau_e = m__io->read_bits_int_be(32); - m_not_used = m__io->read_bits_int_be(1); - m_n_4 = m__io->read_bits_int_be(5); - m_tau_gps = m__io->read_bits_int_be(22); - m_l_n = m__io->read_bits_int_be(1); -} - -glonass_t::string_5_t::~string_5_t() { - _clean_up(); -} - -void glonass_t::string_5_t::_clean_up() { -} - glonass_t::string_1_t::string_1_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - f_x_vel = false; - f_x_accel = false; - f_x = false; try { _read(); @@ -184,12 +129,9 @@ void glonass_t::string_1_t::_read() { m_not_used = m__io->read_bits_int_be(2); m_p1 = m__io->read_bits_int_be(2); m_t_k = m__io->read_bits_int_be(12); - m_x_vel_sign = m__io->read_bits_int_be(1); - m_x_vel_value = m__io->read_bits_int_be(23); - m_x_accel_sign = m__io->read_bits_int_be(1); - m_x_accel_value = m__io->read_bits_int_be(4); - m_x_sign = m__io->read_bits_int_be(1); - m_x_value = m__io->read_bits_int_be(26); + m_x_vel = m__io->read_bits_int_be(24); + m_x_speedup = m__io->read_bits_int_be(5); + m_x = m__io->read_bits_int_be(27); } glonass_t::string_1_t::~string_1_t() { @@ -199,36 +141,9 @@ glonass_t::string_1_t::~string_1_t() { void glonass_t::string_1_t::_clean_up() { } -int32_t glonass_t::string_1_t::x_vel() { - if (f_x_vel) - return m_x_vel; - m_x_vel = ((x_vel_sign()) ? ((x_vel_value() - (1 << 23))) : (x_vel_value())); - f_x_vel = true; - return m_x_vel; -} - -int32_t glonass_t::string_1_t::x_accel() { - if (f_x_accel) - return m_x_accel; - m_x_accel = ((x_accel_sign()) ? ((x_accel_value() - (1 << 4))) : (x_accel_value())); - f_x_accel = true; - return m_x_accel; -} - -int32_t glonass_t::string_1_t::x() { - if (f_x) - return m_x; - m_x = ((x_sign()) ? ((x_value() - (1 << 26))) : (x_value())); - f_x = true; - return m_x; -} - glonass_t::string_2_t::string_2_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - f_y_vel = false; - f_y_accel = false; - f_y = false; try { _read(); @@ -243,12 +158,9 @@ void glonass_t::string_2_t::_read() { m_p2 = m__io->read_bits_int_be(1); m_t_b = m__io->read_bits_int_be(7); m_not_used = m__io->read_bits_int_be(5); - m_y_vel_sign = m__io->read_bits_int_be(1); - m_y_vel_value = m__io->read_bits_int_be(23); - m_y_accel_sign = m__io->read_bits_int_be(1); - m_y_accel_value = m__io->read_bits_int_be(4); - m_y_sign = m__io->read_bits_int_be(1); - m_y_value = m__io->read_bits_int_be(26); + m_y_vel = m__io->read_bits_int_be(24); + m_y_speedup = m__io->read_bits_int_be(5); + m_y = m__io->read_bits_int_be(27); } glonass_t::string_2_t::~string_2_t() { @@ -258,37 +170,9 @@ glonass_t::string_2_t::~string_2_t() { void glonass_t::string_2_t::_clean_up() { } -int32_t glonass_t::string_2_t::y_vel() { - if (f_y_vel) - return m_y_vel; - m_y_vel = ((y_vel_sign()) ? ((y_vel_value() - (1 << 23))) : (y_vel_value())); - f_y_vel = true; - return m_y_vel; -} - -int32_t glonass_t::string_2_t::y_accel() { - if (f_y_accel) - return m_y_accel; - m_y_accel = ((y_accel_sign()) ? ((y_accel_value() - (1 << 4))) : (y_accel_value())); - f_y_accel = true; - return m_y_accel; -} - -int32_t glonass_t::string_2_t::y() { - if (f_y) - return m_y; - m_y = ((y_sign()) ? ((y_value() - (1 << 26))) : (y_value())); - f_y = true; - return m_y; -} - glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - f_gamma_n = false; - f_z_vel = false; - f_z_accel = false; - f_z = false; try { _read(); @@ -300,17 +184,13 @@ glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, void glonass_t::string_3_t::_read() { m_p3 = m__io->read_bits_int_be(1); - m_gamma_n_sign = m__io->read_bits_int_be(1); - m_gamma_n_value = m__io->read_bits_int_be(10); + m_gamma_n = m__io->read_bits_int_be(11); m_not_used = m__io->read_bits_int_be(1); m_p = m__io->read_bits_int_be(2); m_l_n = m__io->read_bits_int_be(1); - m_z_vel_sign = m__io->read_bits_int_be(1); - m_z_vel_value = m__io->read_bits_int_be(23); - m_z_accel_sign = m__io->read_bits_int_be(1); - m_z_accel_value = m__io->read_bits_int_be(4); - m_z_sign = m__io->read_bits_int_be(1); - m_z_value = m__io->read_bits_int_be(26); + m_z_vel = m__io->read_bits_int_be(24); + m_z_speedup = m__io->read_bits_int_be(5); + m_z = m__io->read_bits_int_be(27); } glonass_t::string_3_t::~string_3_t() { @@ -319,35 +199,3 @@ glonass_t::string_3_t::~string_3_t() { void glonass_t::string_3_t::_clean_up() { } - -int32_t glonass_t::string_3_t::gamma_n() { - if (f_gamma_n) - return m_gamma_n; - m_gamma_n = ((gamma_n_sign()) ? ((gamma_n_value() - (1 << 10))) : (gamma_n_value())); - f_gamma_n = true; - return m_gamma_n; -} - -int32_t glonass_t::string_3_t::z_vel() { - if (f_z_vel) - return m_z_vel; - m_z_vel = ((z_vel_sign()) ? ((z_vel_value() - (1 << 23))) : (z_vel_value())); - f_z_vel = true; - return m_z_vel; -} - -int32_t glonass_t::string_3_t::z_accel() { - if (f_z_accel) - return m_z_accel; - m_z_accel = ((z_accel_sign()) ? ((z_accel_value() - (1 << 4))) : (z_accel_value())); - f_z_accel = true; - return m_z_accel; -} - -int32_t glonass_t::string_3_t::z() { - if (f_z) - return m_z; - m_z = ((z_sign()) ? ((z_value() - (1 << 26))) : (z_value())); - f_z = true; - return m_z; -} diff --git a/selfdrive/locationd/generated/glonass.h b/selfdrive/locationd/generated/glonass.h index 3b7917ef4b..48bdabfe96 100644 --- a/selfdrive/locationd/generated/glonass.h +++ b/selfdrive/locationd/generated/glonass.h @@ -15,7 +15,6 @@ class glonass_t : public kaitai::kstruct { public: class string_4_t; class string_non_immediate_t; - class string_5_t; class string_1_t; class string_2_t; class string_3_t; @@ -43,24 +42,8 @@ public: ~string_4_t(); private: - bool f_tau_n; - int32_t m_tau_n; - - public: - int32_t tau_n(); - - private: - bool f_delta_tau_n; - int32_t m_delta_tau_n; - - public: - int32_t delta_tau_n(); - - private: - bool m_tau_n_sign; - uint64_t m_tau_n_value; - bool m_delta_tau_n_sign; - uint64_t m_delta_tau_n_value; + uint64_t m_tau_n; + uint64_t m_delta_tau_n; uint64_t m_e_n; uint64_t m_not_used_1; bool m_p4; @@ -73,10 +56,8 @@ public: glonass_t* m__parent; public: - bool tau_n_sign() const { return m_tau_n_sign; } - uint64_t tau_n_value() const { return m_tau_n_value; } - bool delta_tau_n_sign() const { return m_delta_tau_n_sign; } - uint64_t delta_tau_n_value() const { return m_delta_tau_n_value; } + uint64_t tau_n() const { return m_tau_n; } + uint64_t delta_tau_n() const { return m_delta_tau_n; } uint64_t e_n() const { return m_e_n; } uint64_t not_used_1() const { return m_not_used_1; } bool p4() const { return m_p4; } @@ -115,40 +96,6 @@ public: glonass_t* _parent() const { return m__parent; } }; - class string_5_t : public kaitai::kstruct { - - public: - - string_5_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); - - private: - void _read(); - void _clean_up(); - - public: - ~string_5_t(); - - private: - uint64_t m_n_a; - uint64_t m_tau_e; - bool m_not_used; - uint64_t m_n_4; - uint64_t m_tau_gps; - bool m_l_n; - glonass_t* m__root; - glonass_t* m__parent; - - public: - uint64_t n_a() const { return m_n_a; } - uint64_t tau_e() const { return m_tau_e; } - bool not_used() const { return m_not_used; } - uint64_t n_4() const { return m_n_4; } - uint64_t tau_gps() const { return m_tau_gps; } - bool l_n() const { return m_l_n; } - glonass_t* _root() const { return m__root; } - glonass_t* _parent() const { return m__parent; } - }; - class string_1_t : public kaitai::kstruct { public: @@ -162,37 +109,13 @@ public: public: ~string_1_t(); - private: - bool f_x_vel; - int32_t m_x_vel; - - public: - int32_t x_vel(); - - private: - bool f_x_accel; - int32_t m_x_accel; - - public: - int32_t x_accel(); - - private: - bool f_x; - int32_t m_x; - - public: - int32_t x(); - private: uint64_t m_not_used; uint64_t m_p1; uint64_t m_t_k; - bool m_x_vel_sign; - uint64_t m_x_vel_value; - bool m_x_accel_sign; - uint64_t m_x_accel_value; - bool m_x_sign; - uint64_t m_x_value; + uint64_t m_x_vel; + uint64_t m_x_speedup; + uint64_t m_x; glonass_t* m__root; glonass_t* m__parent; @@ -200,12 +123,9 @@ public: uint64_t not_used() const { return m_not_used; } uint64_t p1() const { return m_p1; } uint64_t t_k() const { return m_t_k; } - bool x_vel_sign() const { return m_x_vel_sign; } - uint64_t x_vel_value() const { return m_x_vel_value; } - bool x_accel_sign() const { return m_x_accel_sign; } - uint64_t x_accel_value() const { return m_x_accel_value; } - bool x_sign() const { return m_x_sign; } - uint64_t x_value() const { return m_x_value; } + uint64_t x_vel() const { return m_x_vel; } + uint64_t x_speedup() const { return m_x_speedup; } + uint64_t x() const { return m_x; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; @@ -223,38 +143,14 @@ public: public: ~string_2_t(); - private: - bool f_y_vel; - int32_t m_y_vel; - - public: - int32_t y_vel(); - - private: - bool f_y_accel; - int32_t m_y_accel; - - public: - int32_t y_accel(); - - private: - bool f_y; - int32_t m_y; - - public: - int32_t y(); - private: uint64_t m_b_n; bool m_p2; uint64_t m_t_b; uint64_t m_not_used; - bool m_y_vel_sign; - uint64_t m_y_vel_value; - bool m_y_accel_sign; - uint64_t m_y_accel_value; - bool m_y_sign; - uint64_t m_y_value; + uint64_t m_y_vel; + uint64_t m_y_speedup; + uint64_t m_y; glonass_t* m__root; glonass_t* m__parent; @@ -263,12 +159,9 @@ public: bool p2() const { return m_p2; } uint64_t t_b() const { return m_t_b; } uint64_t not_used() const { return m_not_used; } - bool y_vel_sign() const { return m_y_vel_sign; } - uint64_t y_vel_value() const { return m_y_vel_value; } - bool y_accel_sign() const { return m_y_accel_sign; } - uint64_t y_accel_value() const { return m_y_accel_value; } - bool y_sign() const { return m_y_sign; } - uint64_t y_value() const { return m_y_value; } + uint64_t y_vel() const { return m_y_vel; } + uint64_t y_speedup() const { return m_y_speedup; } + uint64_t y() const { return m_y; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; @@ -286,63 +179,27 @@ public: public: ~string_3_t(); - private: - bool f_gamma_n; - int32_t m_gamma_n; - - public: - int32_t gamma_n(); - - private: - bool f_z_vel; - int32_t m_z_vel; - - public: - int32_t z_vel(); - - private: - bool f_z_accel; - int32_t m_z_accel; - - public: - int32_t z_accel(); - - private: - bool f_z; - int32_t m_z; - - public: - int32_t z(); - private: bool m_p3; - bool m_gamma_n_sign; - uint64_t m_gamma_n_value; + uint64_t m_gamma_n; bool m_not_used; uint64_t m_p; bool m_l_n; - bool m_z_vel_sign; - uint64_t m_z_vel_value; - bool m_z_accel_sign; - uint64_t m_z_accel_value; - bool m_z_sign; - uint64_t m_z_value; + uint64_t m_z_vel; + uint64_t m_z_speedup; + uint64_t m_z; glonass_t* m__root; glonass_t* m__parent; public: bool p3() const { return m_p3; } - bool gamma_n_sign() const { return m_gamma_n_sign; } - uint64_t gamma_n_value() const { return m_gamma_n_value; } + uint64_t gamma_n() const { return m_gamma_n; } bool not_used() const { return m_not_used; } uint64_t p() const { return m_p; } bool l_n() const { return m_l_n; } - bool z_vel_sign() const { return m_z_vel_sign; } - uint64_t z_vel_value() const { return m_z_vel_value; } - bool z_accel_sign() const { return m_z_accel_sign; } - uint64_t z_accel_value() const { return m_z_accel_value; } - bool z_sign() const { return m_z_sign; } - uint64_t z_value() const { return m_z_value; } + uint64_t z_vel() const { return m_z_vel; } + uint64_t z_speedup() const { return m_z_speedup; } + uint64_t z() const { return m_z; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; diff --git a/selfdrive/locationd/glonass.ksy b/selfdrive/locationd/glonass.ksy index 36e5c91740..95ca78c16f 100644 --- a/selfdrive/locationd/glonass.ksy +++ b/selfdrive/locationd/glonass.ksy @@ -1,6 +1,4 @@ # http://gauss.gge.unb.ca/GLONASS.ICD.pdf -# some variables are misprinted but good in the old doc -# https://www.unavco.org/help/glossary/docs/ICD_GLONASS_4.0_(1998)_en.pdf meta: id: glonass endian: be @@ -18,7 +16,6 @@ seq: 2: string_2 3: string_3 4: string_4 - 5: string_5 _: string_non_immediate - id: hamming_code type: b8 @@ -40,25 +37,12 @@ types: type: b2 - id: t_k type: b12 - - id: x_vel_sign - type: b1 - - id: x_vel_value - type: b23 - - id: x_accel_sign - type: b1 - - id: x_accel_value - type: b4 - - id: x_sign - type: b1 - - id: x_value - type: b26 - instances: - x_vel: - value: 'x_vel_sign ? (x_vel_value - (1 << 23)) : x_vel_value' - x_accel: - value: 'x_accel_sign ? (x_accel_value - (1 << 4)) : x_accel_value' - x: - value: 'x_sign ? (x_value - (1 << 26)) : x_value' + - id: x_vel + type: b24 + - id: x_speedup + type: b5 + - id: x + type: b27 string_2: seq: - id: b_n @@ -69,70 +53,36 @@ types: type: b7 - id: not_used type: b5 - - id: y_vel_sign - type: b1 - - id: y_vel_value - type: b23 - - id: y_accel_sign - type: b1 - - id: y_accel_value - type: b4 - - id: y_sign - type: b1 - - id: y_value - type: b26 - instances: - y_vel: - value: 'y_vel_sign ? (y_vel_value - (1 << 23)) : y_vel_value' - y_accel: - value: 'y_accel_sign ? (y_accel_value - (1 << 4)) : y_accel_value' - y: - value: 'y_sign ? (y_value - (1 << 26)) : y_value' + - id: y_vel + type: b24 + - id: y_speedup + type: b5 + - id: y + type: b27 string_3: seq: - id: p3 type: b1 - - id: gamma_n_sign - type: b1 - - id: gamma_n_value - type: b10 + - id: gamma_n + type: b11 - id: not_used type: b1 - id: p type: b2 - id: l_n type: b1 - - id: z_vel_sign - type: b1 - - id: z_vel_value - type: b23 - - id: z_accel_sign - type: b1 - - id: z_accel_value - type: b4 - - id: z_sign - type: b1 - - id: z_value - type: b26 - instances: - gamma_n: - value: 'gamma_n_sign ? (gamma_n_value - (1 << 10)) : gamma_n_value' - z_vel: - value: 'z_vel_sign ? (z_vel_value - (1 << 23)) : z_vel_value' - z_accel: - value: 'z_accel_sign ? (z_accel_value - (1 << 4)) : z_accel_value' - z: - value: 'z_sign ? (z_value - (1 << 26)) : z_value' + - id: z_vel + type: b24 + - id: z_speedup + type: b5 + - id: z + type: b27 string_4: seq: - - id: tau_n_sign - type: b1 - - id: tau_n_value - type: b21 - - id: delta_tau_n_sign - type: b1 - - id: delta_tau_n_value - type: b4 + - id: tau_n + type: b22 + - id: delta_tau_n + type: b5 - id: e_n type: b5 - id: not_used_1 @@ -149,28 +99,9 @@ types: type: b5 - id: m type: b2 - instances: - tau_n: - value: 'tau_n_sign ? (tau_n_value - (1 << 21)) : tau_n_value' - delta_tau_n: - value: 'delta_tau_n_sign ? (delta_tau_n_value - (1 << 4)) : delta_tau_n_value' - string_5: - seq: - - id: n_a - type: b11 - - id: tau_e - type: b32 - - id: not_used - type: b1 - - id: n_4 - type: b5 - - id: tau_gps - type: b22 - - id: l_n - type: b1 string_non_immediate: seq: - id: data_1 type: b64 - id: data_2 - type: b8 + type: b8 \ No newline at end of file From d76012ec38ff5b996a329d35adc21ade17845d53 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sun, 29 Jan 2023 21:52:42 +0100 Subject: [PATCH 0762/1179] cabana: fix overlap in byte highlighting (#27139) --- tools/cabana/util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 0684d3c59a..7796800103 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -85,7 +85,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & pos.moveLeft(pos.x() + space.width()); int m = space.width() / 2; - const QMargins margins(m + 1, m, m, m); + const QMargins margins(m, m, m, m); int i = 0; for (auto &byte : opt.text.split(" ")) { From 3d641fa5e530bd51ec40e9f1d9b466d75d2aefdf Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sun, 29 Jan 2023 21:54:46 +0100 Subject: [PATCH 0763/1179] cabana: replace space by underscore when editing signal name (#27130) cabana: replace space by _ whene editing signal name --- tools/cabana/detailwidget.cc | 2 +- tools/cabana/signaledit.cc | 2 +- tools/cabana/util.cc | 7 +++++++ tools/cabana/util.h | 9 +++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 233bc493df..ef8a8f6290 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -288,7 +288,7 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title form_layout->addRow("ID", new QLabel(msg_id)); name_edit = new QLineEdit(title, this); - name_edit->setValidator(new QRegExpValidator(QRegExp("^(\\w+)"), name_edit)); + name_edit->setValidator(new NameValidator(name_edit)); form_layout->addRow(tr("Name"), name_edit); size_spin = new QSpinBox(this); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 112c2807f9..52ce74ae08 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -19,7 +19,7 @@ SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { main_layout->addLayout(form_layout); name = new QLineEdit(); - name->setValidator(new QRegExpValidator(QRegExp("^(\\w+)"), name)); + name->setValidator(new NameValidator(name)); form_layout->addRow(tr("Name"), name); QHBoxLayout *hl = new QHBoxLayout(this); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 7796800103..726cbbe2a1 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -97,3 +97,10 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & i++; } } + +NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) { } + +QValidator::State NameValidator::validate(QString &input, int &pos) const { + input.replace(' ', '_'); + return QRegExpValidator::validate(input, pos); +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 146410d7c6..20c85af39e 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -36,3 +37,11 @@ inline const QString &getColor(int i) { static const QString SIGNAL_COLORS[] = {"#9FE2BF", "#40E0D0", "#6495ED", "#CCCCFF", "#FF7F50", "#FFBF00"}; return SIGNAL_COLORS[i % std::size(SIGNAL_COLORS)]; } + +class NameValidator : public QRegExpValidator { + Q_OBJECT + +public: + NameValidator(QObject *parent=nullptr); + QValidator::State validate(QString &input, int &pos) const override; +}; From bdb42f7f84516279f308f95496a5f5f901c4adc1 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sun, 29 Jan 2023 21:55:10 +0100 Subject: [PATCH 0764/1179] cabana: fix occasional ellipsis on y axis ticks (#27142) --- tools/cabana/chartswidget.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3ecdbb08bd..26c05cf119 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -521,8 +521,8 @@ void ChartView::updateAxisY() { if (min_y == std::numeric_limits::max()) min_y = 0; if (max_y == std::numeric_limits::lowest()) max_y = 0; - if (max_y == min_y) { - axis_y->setRange(min_y - 1, max_y + 1); + if (std::abs(max_y - min_y) < 1e-3) { + applyNiceNumbers(min_y - 1, max_y + 1); } else { double range = max_y - min_y; applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05); @@ -539,6 +539,7 @@ void ChartView::applyNiceNumbers(qreal min, qreal max) { tick_count = int(max - min) + 1; axis_y->setRange(min * step, max * step); axis_y->setTickCount(tick_count); + axis_y->setLabelFormat("%.1f"); } // nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n From f038193f4447afc8ae7b6034dec430d08f6da331 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sun, 29 Jan 2023 21:57:01 +0100 Subject: [PATCH 0765/1179] cabana: show dots when zoomed far into a signal (#27145) * cabana: show dots when zoomed far into a signal * review comments --- tools/cabana/chartswidget.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 26c05cf119..9f5b4acbd1 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -469,6 +469,18 @@ void ChartView::updatePlot(double cur, double min, double max) { axis_x->setRange(min, max); updateAxisY(); } + + // Show points when zoomed in enough + 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; }); + auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + + int num_points = std::max(end - begin, 1); + int pixels_per_point = width() / num_points; + + s.series->setPointsVisible(pixels_per_point > 20); + } + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } From d60aca8dd28731f947153f9f5dcb26d0f92ac2ad Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 30 Jan 2023 05:01:57 +0800 Subject: [PATCH 0766/1179] cabana: only update the colors of newly fetched messages in historylog (#27144) only update new msgs color --- tools/cabana/historylog.cc | 46 ++++++++++++++++---------------------- tools/cabana/historylog.h | 1 - 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index ccc2c5533d..44f3a63b95 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -84,7 +84,6 @@ void HistoryLogModel::updateState() { if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, 0, new_msgs.size() - 1); messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); - updateColors(); endInsertRows(); } last_fetch_time = current_time; @@ -97,29 +96,11 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) { if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, messages.size(), messages.size() + new_msgs.size() - 1); messages.insert(messages.end(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); - if (!dynamic_mode) { - updateColors(); - } endInsertRows(); } } } -void HistoryLogModel::updateColors() { - if (!display_signals_mode || sigs.empty()) { - const auto freq = can->lastMessage(msg_id).freq; - if (dynamic_mode) { - for (auto it = messages.rbegin(); it != messages.rend(); ++it) { - it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); - } - } else { - for (auto it = messages.begin(); it != messages.end(); ++it) { - it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); - } - } - } -} - template std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; @@ -153,17 +134,28 @@ template std::deque HistoryLogModel::fetchData<>(std:: std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { auto events = can->events(); + const auto freq = can->lastMessage(msg_id).freq; + const bool update_colors = !display_signals_mode || sigs.empty(); + if (dynamic_mode) { - auto it = std::upper_bound(events->rbegin(), events->rend(), from_time, [=](uint64_t ts, auto &e) { - return e->mono_time < ts; - }); - return fetchData(it, events->rend(), min_time); + auto first = std::upper_bound(events->rbegin(), events->rend(), from_time, [=](uint64_t ts, auto &e) { return e->mono_time < ts; }); + auto msgs = fetchData(first, events->rend(), min_time); + if (update_colors && min_time > 0) { + for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { + it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + } + } + return msgs; } else { assert(min_time == 0); - auto it = std::upper_bound(events->begin(), events->end(), from_time, [=](uint64_t ts, auto &e) { - return ts < e->mono_time; - }); - return fetchData(it, events->end(), 0); + auto first = std::upper_bound(events->begin(), events->end(), from_time, [=](uint64_t ts, auto &e) { return ts < e->mono_time; }); + auto msgs = fetchData(first, events->end(), 0); + if (update_colors) { + for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { + it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + } + } + return msgs; } } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 83b5f623ea..c1a2c13769 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -33,7 +33,6 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override { return display_signals_mode && !sigs.empty() ? sigs.size() + 1 : 2; } - void updateColors(); void refresh(); public slots: From a84b601d4cd2dbd1494ea1dcf31e21aacd579574 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 30 Jan 2023 05:02:20 +0800 Subject: [PATCH 0767/1179] Cabana: load commaai/opendbc from menu (#27114) * load from opendbc * move load from commaai/opendbc to menu * keep margins --- tools/cabana/mainwin.cc | 53 ++++++++++++++-------------------- tools/cabana/mainwin.h | 6 ++-- tools/cabana/messageswidget.cc | 1 - 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d674ec9059..d875d079fa 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -54,7 +53,6 @@ MainWindow::MainWindow() : QMainWindow() { fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); } - QObject::connect(dbc_combo, SIGNAL(activated(const QString &)), SLOT(loadDBCFromName(const QString &))); QObject::connect(this, &MainWindow::showMessage, statusBar(), &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); @@ -68,7 +66,7 @@ void MainWindow::createActions() { QMenu *file_menu = menuBar()->addMenu(tr("&File")); file_menu->addAction(tr("New DBC File"), this, &MainWindow::newFile)->setShortcuts(QKeySequence::New); file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::openFile)->setShortcuts(QKeySequence::Open); - file_menu->addAction(tr("Load DBC From Clipboard"), this, &MainWindow::loadDBCFromClipboard); + open_recent_menu = file_menu->addMenu(tr("Open &Recent")); for (int i = 0; i < MAX_RECENT_FILES; ++i) { recent_files_acts[i] = new QAction(this); @@ -78,6 +76,17 @@ void MainWindow::createActions() { } updateRecentFileActions(); + file_menu->addSeparator(); + QMenu *load_opendbc_menu = file_menu->addMenu(tr("Load DBC from commaai/opendbc")); + // load_opendbc_menu->setStyleSheet("QMenu { menu-scrollable: true; }"); + auto dbc_names = dbc()->allDBCNames(); + std::sort(dbc_names.begin(), dbc_names.end()); + for (const auto &name : dbc_names) { + load_opendbc_menu->addAction(QString::fromStdString(name), this, &MainWindow::openOpendbcFile); + } + + file_menu->addAction(tr("Load DBC From Clipboard"), this, &MainWindow::loadDBCFromClipboard); + file_menu->addSeparator(); file_menu->addAction(tr("Save DBC..."), this, &MainWindow::save)->setShortcuts(QKeySequence::Save); file_menu->addAction(tr("Save DBC As..."), this, &MainWindow::saveAs)->setShortcuts(QKeySequence::SaveAs); @@ -113,18 +122,12 @@ void MainWindow::createActions() { void MainWindow::createDockWindows() { // left panel - QWidget *messages_container = new QWidget(this); - QVBoxLayout *messages_layout = new QVBoxLayout(messages_container); - dbc_combo = createDBCSelector(); - messages_layout->addWidget(dbc_combo); messages_widget = new MessagesWidget(this); - messages_layout->addWidget(messages_widget); - QDockWidget *dock = new QDockWidget(tr("MESSAGES"), this); dock->setObjectName("MessagesPanel"); dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); - dock->setWidget(messages_container); + dock->setWidget(messages_widget); addDockWidget(Qt::LeftDockWidgetArea, dock); // right panel @@ -156,23 +159,6 @@ void MainWindow::createDockWindows() { addDockWidget(Qt::RightDockWidgetArea, video_dock); } -QComboBox *MainWindow::createDBCSelector() { - QComboBox *c = new QComboBox(this); - c->setEditable(true); - c->lineEdit()->setPlaceholderText(tr("Select from an existing DBC file")); - c->setInsertPolicy(QComboBox::NoInsert); - c->completer()->setCompletionMode(QCompleter::PopupCompletion); - c->completer()->setFilterMode(Qt::MatchContains); - - auto dbc_names = dbc()->allDBCNames(); - std::sort(dbc_names.begin(), dbc_names.end()); - for (const auto &name : dbc_names) { - c->addItem(QString::fromStdString(name)); - } - c->setCurrentIndex(-1); - return c; -} - void MainWindow::createStatusBar() { progress_bar = new QProgressBar(); progress_bar->setRange(0, 100); @@ -190,8 +176,6 @@ void MainWindow::createShortcuts() { void MainWindow::DBCFileChanged() { detail_widget->undo_stack->clear(); - int index = dbc_combo->findText(QFileInfo(dbc()->name()).baseName()); - dbc_combo->setCurrentIndex(index); setWindowFilePath(QString("%1").arg(dbc()->name())); } @@ -220,6 +204,13 @@ void MainWindow::loadFile(const QString &fn) { } } +void MainWindow::openOpendbcFile() { + if (auto action = qobject_cast(sender())) { + remindSaveChanges(); + loadDBCFromOpendbc(action->text()); + } +} + void MainWindow::openRecentFile() { if (auto action = qobject_cast(sender())) { remindSaveChanges(); @@ -227,7 +218,7 @@ void MainWindow::openRecentFile() { } } -void MainWindow::loadDBCFromName(const QString &name) { +void MainWindow::loadDBCFromOpendbc(const QString &name) { if (name != dbc()->name()) { remindSaveChanges(); dbc()->open(name); @@ -252,7 +243,7 @@ void MainWindow::loadDBCFromFingerprint() { if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { - loadDBCFromName(dbc_name.toString()); + loadDBCFromOpendbc(dbc_name.toString()); return; } } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 4e65fa01cf..0c207528c9 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -26,7 +25,8 @@ public slots: void newFile(); void openFile(); void openRecentFile(); - void loadDBCFromName(const QString &name); + void openOpendbcFile(); + void loadDBCFromOpendbc(const QString &name); void loadDBCFromFingerprint(); void loadDBCFromClipboard(); void save(); @@ -45,7 +45,6 @@ protected: void updateRecentFileActions(); void createActions(); void createDockWindows(); - QComboBox *createDBCSelector(); void createStatusBar(); void createShortcuts(); void closeEvent(QCloseEvent *event) override; @@ -63,7 +62,6 @@ protected: QVBoxLayout *charts_layout; QProgressBar *progress_bar; QJsonDocument fingerprint_to_dbc; - QComboBox *dbc_combo; QSplitter *video_splitter;; QString current_file = ""; enum { MAX_RECENT_FILES = 15 }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 69c6d298c0..b7c3cd3401 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -10,7 +10,6 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); // message filter QLineEdit *filter = new QLineEdit(this); From fa4f37a0985802f83ec47b7fe0b29d1607ebe83c Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sun, 29 Jan 2023 22:02:32 +0100 Subject: [PATCH 0768/1179] cabana: small improvements to charts (#27140) * cabana: small improvements to charts toolbar * show column count when wide enough * call setspacing * set in same place * remove call to updateToolBar() --- tools/cabana/chartswidget.cc | 20 +++++++++++++------- tools/cabana/chartswidget.h | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 9f5b4acbd1..e653860c3d 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -30,8 +30,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { title_label->setContentsMargins(0, 0, 12, 0); columns_cb = new QComboBox(this); columns_cb->addItems({"1", "2", "3", "4"}); - toolbar->addWidget(new QLabel(tr("Columns:"))); - toolbar->addWidget(columns_cb); + columns_lb_action = toolbar->addWidget(new QLabel(tr("Columns:"))); + columns_cb_action = toolbar->addWidget(columns_cb); QLabel *stretch_label = new QLabel(this); stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -46,8 +46,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { range_slider->setPageStep(60); // 1 min toolbar->addWidget(range_slider); - toolbar->addWidget(zoom_range_lb = new QLabel()); - reset_zoom_btn = toolbar->addAction(bootstrapPixmap("arrow-counterclockwise"), ""); + reset_zoom_btn = toolbar->addAction(bootstrapPixmap("zoom-out"), ""); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); remove_all_btn = toolbar->addAction(bootstrapPixmap("x"), ""); remove_all_btn->setToolTip(tr("Remove all charts")); @@ -55,10 +54,13 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(toolbar); // charts + charts_layout = new QGridLayout(); + charts_layout->setSpacing(10); + QWidget *charts_container = new QWidget(this); QVBoxLayout *charts_main_layout = new QVBoxLayout(charts_container); charts_main_layout->setContentsMargins(0, 0, 0, 0); - charts_main_layout->addLayout(charts_layout = new QGridLayout); + charts_main_layout->addLayout(charts_layout); charts_main_layout->addStretch(0); QScrollArea *charts_scroll = new QScrollArea(this); @@ -167,7 +169,6 @@ void ChartsWidget::setMaxChartRange(int value) { void ChartsWidget::updateToolBar() { range_lb->setText(QString(" %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); - zoom_range_lb->setText(is_zoomed ? tr("Zooming: %1 - %2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); title_label->setText(tr("Charts: %1").arg(charts.size())); dock_btn->setIcon(bootstrapPixmap(docking ? "arrow-up-right" : "arrow-down-left")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); @@ -230,8 +231,13 @@ void ChartsWidget::setColumnCount(int n) { void ChartsWidget::updateLayout() { int n = column_count; for (; n > 1; --n) { - if ((n * (CHART_MIN_WIDTH + charts_layout->spacing())) < rect().width()) break; + if ((n * CHART_MIN_WIDTH + (n - 1) * charts_layout->spacing()) < charts_layout->geometry().width()) break; } + + bool show_column_cb = n > 1; + columns_lb_action->setVisible(show_column_cb); + columns_cb_action->setVisible(show_column_cb); + for (int i = 0; i < charts.size(); ++i) { charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index f134136323..229b1e9cbe 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -116,7 +116,6 @@ private: ChartView *findChart(const QString &id, const Signal *sig); QLabel *title_label; - QLabel *zoom_range_lb; QLabel *range_lb; QSlider *range_slider; bool docking = true; @@ -131,6 +130,8 @@ private: std::pair display_range; std::pair zoomed_range; bool use_dark_theme = false; + QAction *columns_lb_action; + QAction *columns_cb_action; QComboBox *columns_cb; int column_count = 1; const int CHART_MIN_WIDTH = 300; From fdc4a7f84cb68c63cc5013a052b49663ffb6881c Mon Sep 17 00:00:00 2001 From: martinl Date: Sun, 29 Jan 2023 23:55:17 +0200 Subject: [PATCH 0769/1179] MacOS: build fixes (#27143) * MacOS: exclude common/gpio.cc * MacOS: no spi for boardd * MacOS: loggerd: no v4l_encoder.cc * MacOS: update libdbc path for cabana --- common/SConscript | 4 +++- selfdrive/boardd/boardd.cc | 1 + selfdrive/boardd/panda.cc | 4 ++++ selfdrive/boardd/panda_comms.h | 4 ++++ selfdrive/boardd/spi.cc | 2 ++ selfdrive/loggerd/SConscript | 2 ++ tools/cabana/SConscript | 3 +++ 7 files changed, 19 insertions(+), 1 deletion(-) diff --git a/common/SConscript b/common/SConscript index 8aee6f42a7..5d6170611f 100644 --- a/common/SConscript +++ b/common/SConscript @@ -10,11 +10,13 @@ common_libs = [ 'statlog.cc', 'swaglog.cc', 'util.cc', - 'gpio.cc', 'i2c.cc', 'watchdog.cc', ] +if arch != "Darwin": + common_libs.append('gpio.cc') + _common = fxn('common', common_libs, LIBS="json11") files = [ diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index bc454aa54e..5ef49d4b22 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 600a46c809..4bba070eee 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -14,7 +14,9 @@ Panda::Panda(std::string serial, uint32_t bus_offset) : bus_offset(bus_offset) { try { handle = std::make_unique(serial); } catch (std::exception &e) { +#ifndef __APPLE__ handle = std::make_unique(serial); +#endif } hw_type = get_hw_type(); @@ -46,11 +48,13 @@ std::string Panda::hw_serial() { std::vector Panda::list() { std::vector serials = PandaUsbHandle::list(); +#ifndef __APPLE__ for (auto s : PandaSpiHandle::list()) { if (std::find(serials.begin(), serials.end(), s) == serials.end()) { serials.push_back(s); } } +#endif return serials; } diff --git a/selfdrive/boardd/panda_comms.h b/selfdrive/boardd/panda_comms.h index b669d77e7f..506b96b372 100644 --- a/selfdrive/boardd/panda_comms.h +++ b/selfdrive/boardd/panda_comms.h @@ -5,7 +5,9 @@ #include #include +#ifndef __APPLE__ #include +#endif #include @@ -52,6 +54,7 @@ private: void handle_usb_issue(int err, const char func[]); }; +#ifndef __APPLE__ class PandaSpiHandle : public PandaCommsHandle { public: PandaSpiHandle(std::string serial); @@ -75,3 +78,4 @@ private: int spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); int spi_transfer_retry(uint8_t endpoint, uint8_t *tx_data, uint16_t tx_len, uint8_t *rx_data, uint16_t max_rx_len); }; +#endif diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index bcc446b050..c9d4b2ea0e 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -1,3 +1,4 @@ +#ifndef __APPLE__ #include #include #include @@ -339,3 +340,4 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx transfer_fail: return ret; } +#endif diff --git a/selfdrive/loggerd/SConscript b/selfdrive/loggerd/SConscript index 92706c53ec..3b961bce6e 100644 --- a/selfdrive/loggerd/SConscript +++ b/selfdrive/loggerd/SConscript @@ -13,6 +13,8 @@ if arch == "Darwin": # fix OpenCL del libs[libs.index('OpenCL')] env['FRAMEWORKS'] = ['OpenCL'] + # exclude v4l + del src[src.index('encoder/v4l_encoder.cc')] logger_lib = env.Library('logger', src) libs.insert(0, logger_lib) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index fbf3c03d36..0c9ad14973 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -24,6 +24,9 @@ cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream 'commands.cc', 'messageswidget.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) +if arch == "Darwin": + cabana_env.Execute('install_name_tool -change opendbc/can/libdbc.dylib @loader_path/../../opendbc/can/libdbc.dylib ./_cabana') + if GetOption('test'): cabana_env.Program('tests/_test_cabana', ['tests/test_runner.cc', 'tests/test_cabana.cc', cabana_lib], LIBS=[cabana_libs]) From 7a485d4308ff263cd3432edaa27d118d264b25b5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 30 Jan 2023 11:19:50 +0800 Subject: [PATCH 0770/1179] cabana: refactor and improve signal view (#26997) * refactor and improve signal view * cleanup undostack after save * set clean * fix logswidget::refresh * fix bugs in historylog * historylog:dont reset display_type on msg changed * inline displaySignals * historylog:add stretch to header * remove sizePolicy * always show toolbar * add icon to tabwidget * create new chart on top * fix 'show plot' btn state sync issue * rename removeSeries to removeItem * historylog::fix displayRange * MessageListModeL: improve setFilterString * set as current index after expanded * disable update during setmessage * ChartWidget: fix issue in updateState * skip align charts if there only one chart * fix updateLayout * cleanup historylog * updateState before end reset model * add validator * improve sigmodel * expand new signal * add comment * reserve vector * cleanup condition * single click on row to expand signal * improve layout for canfd(64 bytes) * cleanup * return false on default * show the latest signal value next to the signal name * update sig value after setmessage.to make the value updated in pause mode. * better size policy * +1 for grid size * better palette * set autofillbg --- tools/cabana/binaryview.cc | 30 +- tools/cabana/binaryview.h | 6 +- tools/cabana/chartswidget.cc | 10 +- tools/cabana/chartswidget.h | 2 +- tools/cabana/commands.cc | 11 + tools/cabana/commands.h | 6 + tools/cabana/dbcmanager.cc | 3 +- tools/cabana/dbcmanager.h | 4 +- tools/cabana/detailwidget.cc | 174 +++-------- tools/cabana/detailwidget.h | 18 +- tools/cabana/historylog.cc | 25 +- tools/cabana/historylog.h | 5 +- tools/cabana/mainwin.cc | 22 +- tools/cabana/mainwin.h | 1 + tools/cabana/signaledit.cc | 581 ++++++++++++++++++++++++----------- tools/cabana/signaledit.h | 106 +++++-- 16 files changed, 605 insertions(+), 399 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 010fe0fc88..4d7b3148c6 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -4,8 +4,10 @@ #include #include #include +#include #include +#include "tools/cabana/commands.h" #include "tools/cabana/streams/abstractstream.h" // BinaryView @@ -30,12 +32,15 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { setFrameShape(QFrame::NoFrame); setShowGrid(false); setMouseTracking(true); - setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &BinaryView::refresh); + QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &BinaryView::refresh); } QSize BinaryView::minimumSizeHint() const { - return {horizontalHeader()->minimumSectionSize() * 9 + VERTICAL_HEADER_WIDTH + 2, 0}; + return {(horizontalHeader()->minimumSectionSize() + 1) * 9 + VERTICAL_HEADER_WIDTH, + CELL_HEIGHT * std::min(model->rowCount(), 10)}; } void BinaryView::highlight(const Signal *sig) { @@ -124,13 +129,20 @@ void BinaryView::leaveEvent(QEvent *event) { } void BinaryView::setMessage(const QString &message_id) { - model->setMessage(message_id); + model->msg_id = message_id; + verticalScrollBar()->setValue(0); + refresh(); +} + +void BinaryView::refresh() { + if (model->msg_id.isEmpty()) return; + clearSelection(); anchor_index = QModelIndex(); resize_sig = nullptr; hovered_sig = nullptr; highlightPosition(QCursor::pos()); - updateState(); + model->refresh(); } QSet BinaryView::getOverlappingSignals() const { @@ -155,9 +167,8 @@ std::tuple BinaryView::getSelection(QModelIndex index) { // BinaryViewModel -void BinaryViewModel::setMessage(const QString &message_id) { +void BinaryViewModel::refresh() { beginResetModel(); - msg_id = message_id; items.clear(); if ((dbc_msg = dbc()->msg(msg_id))) { row_count = dbc_msg->size; @@ -184,6 +195,7 @@ void BinaryViewModel::setMessage(const QString &message_id) { items.resize(row_count * column_count); } endResetModel(); + updateState(); } void BinaryViewModel::updateState() { @@ -200,7 +212,7 @@ void BinaryViewModel::updateState() { } char hex[3] = {'\0'}; for (int i = 0; i < binary.size(); ++i) { - for (int j = 0; j < column_count - 1; ++j) { + for (int j = 0; j < 8; ++j) { items[i * column_count + j].val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0'; } hex[0] = toHex(binary[i] >> 4); @@ -214,7 +226,7 @@ void BinaryViewModel::updateState() { } } - for (int i = 0; i < row_count * column_count; ++i) { + for (int i = 0; i < items.size(); ++i) { if (i >= prev_items.size() || prev_items[i].val != items[i].val || prev_items[i].bg_color != items[i].bg_color) { auto idx = index(i / column_count, i % column_count); emit dataChanged(idx, idx); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 55de71572e..f697ea28cb 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -21,7 +21,7 @@ public: class BinaryViewModel : public QAbstractTableModel { public: BinaryViewModel(QObject *parent) : QAbstractTableModel(parent) {} - void setMessage(const QString &message_id); + void refresh(); void updateState(); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return {}; } @@ -39,12 +39,11 @@ public: QColor bg_color = QApplication::style()->standardPalette().color(QPalette::Base); bool is_msb = false; bool is_lsb = false; - QString val = "0"; + QString val = "-"; QList sigs; }; std::vector items; -private: QString msg_id; const DBCMsg *dbc_msg = nullptr; int row_count = 0; @@ -69,6 +68,7 @@ signals: void resizeSignal(const Signal *sig, int from, int size); private: + void refresh(); std::tuple getSelection(QModelIndex index); void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override; void mousePressEvent(QMouseEvent *event) override; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index e653860c3d..580cce5521 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -374,7 +374,7 @@ void ChartView::addSeries(const QString &msg_id, const Signal *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); + it = removeItem(it); } } @@ -382,7 +382,7 @@ bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); } -QList::iterator ChartView::removeSeries(const QList::iterator &it) { +QList::iterator ChartView::removeItem(const QList::iterator &it) { chart()->removeSeries(it->series); it->series->deleteLater(); QString msg_id = it->msg_id; @@ -407,7 +407,7 @@ void ChartView::signalUpdated(const Signal *sig) { void ChartView::signalRemoved(const Signal *sig) { for (auto it = sigs.begin(); it != sigs.end(); /**/) { - it = (it->sig == sig) ? removeSeries(it) : ++it; + it = (it->sig == sig) ? removeItem(it) : ++it; } } @@ -418,7 +418,7 @@ void ChartView::msgUpdated(uint32_t address) { void ChartView::msgRemoved(uint32_t address) { for (auto it = sigs.begin(); it != sigs.end(); /**/) { - it = (it->address == address) ? removeSeries(it) : ++it; + it = (it->address == address) ? removeItem(it) : ++it; } } @@ -450,7 +450,7 @@ void ChartView::manageSeries() { bool exists = std::any_of(series_list.cbegin(), series_list.cend(), [&](auto &s) { return s[0] == it->msg_id && s[2] == it->sig->name.c_str(); }); - it = exists ? ++it : removeSeries(it); + it = exists ? ++it : removeItem(it); } } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 229b1e9cbe..d5572756c1 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -57,7 +57,7 @@ private slots: void manageSeries(); private: - QList::iterator removeSeries(const QList::iterator &it); + QList::iterator removeItem(const QList::iterator &it); void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index b3f5cb1c66..e4bf999062 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -1,3 +1,5 @@ +#include + #include "tools/cabana/commands.h" // EditMsgCommand @@ -73,3 +75,12 @@ EditSignalCommand::EditSignalCommand(const QString &id, const Signal *sig, const void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name.c_str(), old_signal); } void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name.c_str(), new_signal); } + +namespace UndoStack { + +QUndoStack *instance() { + static QUndoStack *undo_stack = new QUndoStack(qApp); + return undo_stack; +} + +} // namespace UndoStack diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index e46223d630..c07a00b760 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "tools/cabana/dbcmanager.h" @@ -60,3 +61,8 @@ private: Signal old_signal = {}; Signal new_signal = {}; }; + +namespace UndoStack { + QUndoStack *instance(); + inline void push(QUndoCommand *cmd) { instance()->push(cmd); } +}; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 01bdff17a1..83f5fdb74a 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -68,7 +68,7 @@ void DBCManager::addSignal(const QString &id, const Signal &sig) { if (auto m = const_cast(msg(id))) { auto &s = m->sigs[sig.name.c_str()]; s = sig; - emit signalAdded(&s); + emit signalAdded(parseId(id).second, &s); } } @@ -110,6 +110,7 @@ DBCManager *dbc() { std::vector DBCMsg::getSignals() const { std::vector ret; + ret.reserve(sigs.size()); for (auto &[_, 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; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 5db6737be8..03bd16f2a5 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -8,7 +8,9 @@ struct DBCMsg { QString name; uint32_t size; + // signal must be saved as value in map to make undo stack work properly. std::map sigs; + // return vector, sort by start_bits std::vector getSignals() const; }; @@ -39,7 +41,7 @@ public: } signals: - void signalAdded(const Signal *sig); + void signalAdded(uint32_t address, const Signal *sig); void signalRemoved(const Signal *sig); void signalUpdated(const Signal *sig); void msgUpdated(uint32_t address); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index ef8a8f6290..5e127966c1 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include #include "selfdrive/ui/qt/util.h" #include "tools/cabana/commands.h" @@ -15,7 +14,6 @@ // DetailWidget DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { - undo_stack = new QUndoStack(this); QWidget *main_widget = new QWidget(this); QVBoxLayout *main_layout = new QVBoxLayout(main_widget); main_layout->setContentsMargins(0, 0, 0, 0); @@ -29,7 +27,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart main_layout->addWidget(tabbar); // message title - toolbar = new QToolBar(this); + QToolBar *toolbar = new QToolBar(this); toolbar->setIconSize({16, 16}); toolbar->addWidget(new QLabel("time:")); time_label = new QLabel(this); @@ -54,41 +52,35 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart main_layout->addWidget(warning_widget); // msg widget - QWidget *msg_widget = new QWidget(this); - QVBoxLayout *msg_layout = new QVBoxLayout(msg_widget); - msg_layout->setContentsMargins(0, 0, 0, 0); - // binary view - binary_view = new BinaryView(this); - msg_layout->addWidget(binary_view); - // signals - signals_layout = new QVBoxLayout(); - signals_layout->setSpacing(0); - msg_layout->addLayout(signals_layout); - msg_layout->addStretch(0); - - scroll = new QScrollArea(this); - scroll->setFrameShape(QFrame::NoFrame); - scroll->setWidget(msg_widget); - scroll->setWidgetResizable(true); - scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + splitter = new QSplitter(Qt::Vertical, this); + splitter->setAutoFillBackground(true); + splitter->addWidget(binary_view = new BinaryView(this)); + splitter->addWidget(signal_view = new SignalView(charts, this)); + binary_view->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + signal_view->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + splitter->setStretchFactor(0, 0); + splitter->setStretchFactor(1, 1); tab_widget = new QTabWidget(this); tab_widget->setTabPosition(QTabWidget::South); - tab_widget->addTab(scroll, bootstrapPixmap("file-earmark-ruled"), "&Msg"); - history_log = new LogsWidget(this); - tab_widget->addTab(history_log, bootstrapPixmap("stopwatch"), "&Logs"); + tab_widget->addTab(splitter, bootstrapPixmap("file-earmark-ruled"), "&Msg"); + tab_widget->addTab(history_log = new LogsWidget(this), bootstrapPixmap("stopwatch"), "&Logs"); main_layout->addWidget(tab_widget); stacked_layout = new QStackedLayout(this); stacked_layout->addWidget(new WelcomeWidget(this)); stacked_layout->addWidget(main_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(binary_view, &BinaryView::resizeSignal, signal_view->model, &SignalModel::resizeSignal); + QObject::connect(binary_view, &BinaryView::addSignal, signal_view->model, &SignalModel::addSignal); + QObject::connect(binary_view, &BinaryView::signalHovered, signal_view, &SignalView::signalHovered); + QObject::connect(binary_view, &BinaryView::signalClicked, signal_view, &SignalView::expandSignal); + QObject::connect(signal_view, &SignalView::showChart, charts, &ChartsWidget::showChart); + QObject::connect(signal_view, &SignalView::highlight, binary_view, &BinaryView::highlight); QObject::connect(tab_widget, &QTabWidget::currentChanged, [this]() { updateState(); }); QObject::connect(can, &AbstractStream::msgsReceived, this, &DetailWidget::updateState); - QObject::connect(dbc(), &DBCManager::DBCFileChanged, [this]() { dbcMsgChanged(); }); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &DetailWidget::refresh); + QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &DetailWidget::refresh); QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { if (index != -1 && tabbar->tabText(index) != msg_id) { @@ -96,14 +88,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart } }); QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); - QObject::connect(charts, &ChartsWidget::seriesChanged, this, &DetailWidget::updateChartState); - QObject::connect(history_log, &LogsWidget::openChart, [this](const QString &id, const Signal *sig) { - this->charts->showChart(id, sig, true, false); - }); - QObject::connect(undo_stack, &QUndoStack::indexChanged, [this]() { - if (undo_stack->count() > 0) - dbcMsgChanged(); - }); + QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState); } void DetailWidget::showTabBarContextMenu(const QPoint &pt) { @@ -128,41 +113,27 @@ void DetailWidget::setMessage(const QString &message_id) { index = tabbar->addTab(message_id); tabbar->setTabToolTip(index, msgName(message_id)); } - tabbar->setCurrentIndex(index); - dbcMsgChanged(); - scroll->verticalScrollBar()->setValue(0); - stacked_layout->setCurrentIndex(1); -} - -void DetailWidget::dbcMsgChanged(int show_form_idx) { - if (msg_id.isEmpty()) return; setUpdatesEnabled(false); + signal_view->setMessage(msg_id); binary_view->setMessage(msg_id); history_log->setMessage(msg_id); - int i = 0; + stacked_layout->setCurrentIndex(1); + tabbar->setCurrentIndex(index); + refresh(); + splitter->setSizes({1, 2}); + + setUpdatesEnabled(true); +} + +void DetailWidget::refresh() { + if (msg_id.isEmpty()) return; + QStringList warnings; const DBCMsg *msg = dbc()->msg(msg_id); if (msg) { - for (auto sig : msg->getSignals()) { - SignalEdit *form = i < signal_list.size() ? signal_list[i] : nullptr; - if (!form) { - form = new SignalEdit(i, this); - QObject::connect(form, &SignalEdit::remove, this, &DetailWidget::removeSignal); - QObject::connect(form, &SignalEdit::save, this, &DetailWidget::saveSignal); - QObject::connect(form, &SignalEdit::showFormClicked, this, &DetailWidget::showForm); - QObject::connect(form, &SignalEdit::highlight, binary_view, &BinaryView::highlight); - QObject::connect(binary_view, &BinaryView::signalHovered, form, &SignalEdit::signalHovered); - QObject::connect(form, &SignalEdit::showChart, charts, &ChartsWidget::showChart); - signals_layout->addWidget(form); - signal_list.push_back(form); - } - form->setSignal(msg_id, sig); - form->setChartOpened(charts->hasSignal(msg_id, sig)); - ++i; - } if (msg->size != can->lastMessage(msg_id).dat.size()) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } @@ -172,10 +143,6 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { } else { warnings.push_back(tr("Drag-Select in binary view to create new signal.")); } - for (/**/; i < signal_list.size(); ++i) - signal_list[i]->hide(); - - toolbar->setVisible(!msg_id.isEmpty()); remove_msg_act->setEnabled(msg != nullptr); name_label->setText(msgName(msg_id)); @@ -184,10 +151,9 @@ void DetailWidget::dbcMsgChanged(int show_form_idx) { warning_icon->setPixmap(bootstrapPixmap(msg ? "exclamation-triangle" : "info-circle")); } warning_widget->setVisible(!warnings.isEmpty()); - setUpdatesEnabled(true); } -void DetailWidget::updateState(const QHash * msgs) { +void DetailWidget::updateState(const QHash *msgs) { time_label->setText(QString::number(can->currentSec(), 'f', 3)); if (msg_id.isEmpty() || (msgs && !msgs->contains(msg_id))) return; @@ -198,86 +164,18 @@ void DetailWidget::updateState(const QHash * msgs) { history_log->updateState(); } -void DetailWidget::showForm(const Signal *sig) { - setUpdatesEnabled(false); - for (auto f : signal_list) { - f->updateForm(f->sig == sig && !f->form->isVisible()); - if (f->sig == sig && f->form->isVisible()) { - QTimer::singleShot(0, [=]() { scroll->ensureWidgetVisible(f); }); - } - } - setUpdatesEnabled(true); -} - -void DetailWidget::updateChartState() { - for (auto f : signal_list) - f->setChartOpened(charts->hasSignal(f->msg_id, f->sig)); -} - void DetailWidget::editMsg() { QString id = msg_id; auto msg = dbc()->msg(id); int size = msg ? msg->size : can->lastMessage(id).dat.size(); EditMessageDialog dlg(id, msgName(id), size, this); if (dlg.exec()) { - undo_stack->push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); + UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); } } void DetailWidget::removeMsg() { - undo_stack->push(new RemoveMsgCommand(msg_id)); -} - -void DetailWidget::addSignal(int start_bit, int size, bool little_endian) { - auto msg = dbc()->msg(msg_id); - if (!msg) { - for (int i = 1; /**/; ++i) { - QString name = QString("NEW_MSG_%1").arg(i); - auto it = std::find_if(dbc()->messages().begin(), dbc()->messages().end(), [&](auto &m) { return m.second.name == name; }); - if (it == dbc()->messages().end()) { - undo_stack->push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size())); - msg = dbc()->msg(msg_id); - break; - } - } - } - 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; - } - updateSigSizeParamsFromRange(sig, start_bit, size); - undo_stack->push(new AddSigCommand(msg_id, sig)); -} - -void DetailWidget::resizeSignal(const Signal *sig, int start_bit, int size) { - Signal s = *sig; - updateSigSizeParamsFromRange(s, start_bit, size); - saveSignal(sig, s); -} - -void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) { - auto msg = dbc()->msg(msg_id); - if (new_sig.name != sig->name) { - auto it = msg->sigs.find(new_sig.name.c_str()); - if (it != msg->sigs.end()) { - QString warning_str = tr("There is already a signal with the same name '%1'").arg(new_sig.name.c_str()); - QMessageBox::warning(this, tr("Failed to save signal"), warning_str); - return; - } - } - auto [start, end] = getSignalRange(&new_sig); - if (start < 0 || end >= msg->size * 8) { - QString warning_str = tr("Signal size [%1] exceed limit").arg(new_sig.size); - QMessageBox::warning(this, tr("Failed to save signal"), warning_str); - return; - } - - undo_stack->push(new EditSignalCommand(msg_id, sig, new_sig)); -} - -void DetailWidget::removeSignal(const Signal *sig) { - undo_stack->push(new RemoveSigCommand(msg_id, sig)); + UndoStack::push(new RemoveMsgCommand(msg_id)); } // EditMessageDialog diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index c59a6fca50..3a3f3adf0e 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,10 +1,9 @@ #pragma once +#include #include -#include #include #include -#include #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" @@ -30,18 +29,11 @@ class DetailWidget : public QWidget { public: DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const QString &message_id); - void dbcMsgChanged(int show_form_idx = -1); + void refresh(); QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } - QUndoStack *undo_stack = nullptr; private: - void showForm(const Signal *sig); - void updateChartState(); void showTabBarContextMenu(const QPoint &pt); - void addSignal(int start_bit, int size, bool little_endian); - void resizeSignal(const Signal *sig, int from, int to); - void saveSignal(const Signal *sig, const Signal &new_sig); - void removeSignal(const Signal *sig); void editMsg(); void removeMsg(); void updateState(const QHash * msgs = nullptr); @@ -49,15 +41,13 @@ private: QString msg_id; QLabel *name_label, *time_label, *warning_icon, *warning_label; QWidget *warning_widget; - QVBoxLayout *signals_layout; QTabBar *tabbar; QTabWidget *tab_widget; - QToolBar *toolbar; QAction *remove_msg_act; LogsWidget *history_log; BinaryView *binary_view; - QScrollArea *scroll; + SignalView *signal_view; ChartsWidget *charts; + QSplitter *splitter; QStackedLayout *stacked_layout; - QList signal_list; }; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 44f3a63b95..830390f4a8 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -4,6 +4,8 @@ #include #include +#include "tools/cabana/commands.h" + // HistoryLogModel QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { @@ -22,17 +24,16 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { void HistoryLogModel::setMessage(const QString &message_id) { msg_id = message_id; - sigs.clear(); - if (auto dbc_msg = dbc()->msg(msg_id)) { - sigs = dbc_msg->getSignals(); - } - filter_cmp = nullptr; - refresh(); } void HistoryLogModel::refresh() { beginResetModel(); + sigs.clear(); + if (auto dbc_msg = dbc()->msg(msg_id)) { + sigs = dbc_msg->getSignals(); + } last_fetch_time = 0; + has_more_data = true; messages.clear(); hex_colors.clear(); updateState(); @@ -74,7 +75,6 @@ void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function filter_sig_idx = sig_idx; filter_value = value.toDouble(); filter_cmp = value.isEmpty() ? nullptr : cmp; - refresh(); } void HistoryLogModel::updateState() { @@ -232,11 +232,21 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(comp_box, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(value_edit, &QLineEdit::textChanged, this, &LogsWidget::setFilter); QObject::connect(can, &AbstractStream::seekedTo, model, &HistoryLogModel::refresh); + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &LogsWidget::refresh); + QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &LogsWidget::refresh); QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged); } void LogsWidget::setMessage(const QString &message_id) { model->setMessage(message_id); + refresh(); +} + +void LogsWidget::refresh() { + if (model->msg_id.isEmpty()) return; + + model->setFilter(0, "", nullptr); + model->refresh(); bool has_signal = model->sigs.size(); if (has_signal) { signals_cb->clear(); @@ -260,4 +270,5 @@ void LogsWidget::setFilter() { case 3: cmp = std::less{}; break; } model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); + model->refresh(); } diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index c1a2c13769..bc2e0e3914 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -75,13 +75,12 @@ public: void updateState() {if (dynamic_mode->isChecked()) model->updateState(); } void showEvent(QShowEvent *event) override { if (dynamic_mode->isChecked()) model->refresh(); } -signals: - void openChart(const QString &msg_id, const Signal *sig); - private slots: void setFilter(); private: + void refresh(); + QTableView *logs; HistoryLogModel *model; QCheckBox *dynamic_mode; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index d875d079fa..3c2d46cbf2 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -14,6 +14,8 @@ #include #include +#include "tools/cabana/commands.h" + static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (type == QtDebugMsg) std::cout << msg.toStdString() << std::endl; @@ -59,7 +61,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); - QObject::connect(detail_widget->undo_stack, &QUndoStack::cleanChanged, [this](bool clean) { setWindowModified(!clean); }); + QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); } void MainWindow::createActions() { @@ -98,16 +100,16 @@ void MainWindow::createActions() { file_menu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows)->setShortcuts(QKeySequence::Quit); QMenu *edit_menu = menuBar()->addMenu(tr("&Edit")); - auto undo_act = detail_widget->undo_stack->createUndoAction(this, tr("&Undo")); + auto undo_act = UndoStack::instance()->createUndoAction(this, tr("&Undo")); undo_act->setShortcuts(QKeySequence::Undo); edit_menu->addAction(undo_act); - auto redo_act = detail_widget->undo_stack->createRedoAction(this, tr("&Rndo")); + auto redo_act = UndoStack::instance()->createRedoAction(this, tr("&Rndo")); redo_act->setShortcuts(QKeySequence::Redo); edit_menu->addAction(redo_act); edit_menu->addSeparator(); QMenu *commands_menu = edit_menu->addMenu(tr("Command &List")); - auto undo_view = new QUndoView(detail_widget->undo_stack); + auto undo_view = new QUndoView(UndoStack::instance()); undo_view->setWindowTitle(tr("Command List")); QWidgetAction *commands_act = new QWidgetAction(this); commands_act->setDefaultWidget(undo_view); @@ -174,8 +176,12 @@ void MainWindow::createShortcuts() { // TODO: add more shortcuts here. } +void MainWindow::undoStackCleanChanged(bool clean) { + setWindowModified(!clean); +} + void MainWindow::DBCFileChanged() { - detail_widget->undo_stack->clear(); + UndoStack::instance()->clear(); setWindowFilePath(QString("%1").arg(dbc()->name())); } @@ -262,7 +268,7 @@ void MainWindow::saveFile(const QString &fn) { QFile file(fn); if (file.open(QIODevice::WriteOnly)) { file.write(dbc()->generateDBC().toUtf8()); - detail_widget->undo_stack->setClean(); + UndoStack::instance()->setClean(); setCurrentFile(fn); statusBar()->showMessage(tr("File saved"), 2000); } @@ -309,7 +315,7 @@ void MainWindow::updateRecentFileActions() { void MainWindow::remindSaveChanges() { bool discard_changes = false; - while (!detail_widget->undo_stack->isClean() && !discard_changes) { + while (!UndoStack::instance()->isClean() && !discard_changes) { int ret = (QMessageBox::question(this, tr("Unsaved Changes"), tr("You have unsaved changes. Press ok to save them, cancel to discard."), QMessageBox::Ok | QMessageBox::Cancel)); @@ -319,7 +325,7 @@ void MainWindow::remindSaveChanges() { discard_changes = true; } } - detail_widget->undo_stack->clear(); + UndoStack::instance()->clear(); current_file = ""; } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 0c207528c9..ba36d676e0 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -52,6 +52,7 @@ protected: void updateDownloadProgress(uint64_t cur, uint64_t total, bool success); void setOption(); void findSimilarBits(); + void undoStackCleanChanged(bool clean); VideoWidget *video_widget = nullptr; QDockWidget *video_dock; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 52ce74ae08..ceb7b7ba3f 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,174 +1,194 @@ #include "tools/cabana/signaledit.h" -#include -#include #include #include +#include +#include +#include +#include #include +#include "tools/cabana/commands.h" + #include "selfdrive/ui/qt/util.h" -// SignalForm +// SignalModel -SignalForm::SignalForm(QWidget *parent) : QWidget(parent) { - auto double_validator = new QDoubleValidator(this); - double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system - - QVBoxLayout *main_layout = new QVBoxLayout(this); - QFormLayout *form_layout = new QFormLayout(); - main_layout->addLayout(form_layout); - - name = new QLineEdit(); - name->setValidator(new NameValidator(name)); - form_layout->addRow(tr("Name"), name); - - QHBoxLayout *hl = new QHBoxLayout(this); - size = new QSpinBox(); - size->setMinimum(1); - hl->addWidget(size); - endianness = new QComboBox(); - endianness->addItems({"Little Endianness", "Big Endianness"}); - hl->addWidget(endianness); - sign = new QComboBox(); - sign->addItems({"Signed", "Unsigned"}); - hl->addWidget(sign); - form_layout->addRow(tr("Size"), hl); - - offset = new QLineEdit(); - offset->setValidator(double_validator); - form_layout->addRow(tr("Offset"), offset); - factor = new QLineEdit(); - factor->setValidator(double_validator); - form_layout->addRow(tr("Factor"), factor); - - expand_btn = new QToolButton(this); - expand_btn->setText(tr("more...")); - main_layout->addWidget(expand_btn, 0, Qt::AlignRight); - - // TODO: parse the following parameters in opendbc - QWidget *extra_container = new QWidget(this); - QFormLayout *extra_layout = new QFormLayout(extra_container); - unit = new QLineEdit(); - extra_layout->addRow(tr("Unit"), unit); - comment = new QLineEdit(); - extra_layout->addRow(tr("Comment"), comment); - min_val = new QLineEdit(); - min_val->setValidator(double_validator); - extra_layout->addRow(tr("Minimum value"), min_val); - max_val = new QLineEdit(); - max_val->setValidator(double_validator); - extra_layout->addRow(tr("Maximum value"), max_val); - val_desc = new QLineEdit(); - extra_layout->addRow(tr("Value descriptions"), val_desc); - - main_layout->addWidget(extra_container); - extra_container->setVisible(false); - - QObject::connect(name, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); - QObject::connect(factor, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); - QObject::connect(offset, &QLineEdit::editingFinished, this, &SignalForm::textBoxEditingFinished); - QObject::connect(size, &QSpinBox::editingFinished, this, &SignalForm::changed); - QObject::connect(sign, SIGNAL(activated(int)), SIGNAL(changed())); - QObject::connect(endianness, SIGNAL(activated(int)), SIGNAL(changed())); - QObject::connect(expand_btn, &QToolButton::clicked, [=]() { - extra_container->setVisible(!extra_container->isVisible()); - expand_btn->setText(extra_container->isVisible() ? tr("less...") : tr("more...")); - }); +SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(parent) { + QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &SignalModel::refresh); + QObject::connect(dbc(), &DBCManager::msgUpdated, this, &SignalModel::handleMsgChanged); + QObject::connect(dbc(), &DBCManager::msgRemoved, this, &SignalModel::handleMsgChanged); + QObject::connect(dbc(), &DBCManager::signalAdded, this, &SignalModel::handleSignalAdded); + QObject::connect(dbc(), &DBCManager::signalUpdated, this, &SignalModel::handleSignalUpdated); + QObject::connect(dbc(), &DBCManager::signalRemoved, this, &SignalModel::handleSignalRemoved); + QObject::connect(can, &AbstractStream::msgsReceived, this, &SignalModel::updateState); } -void SignalForm::textBoxEditingFinished() { - QLineEdit *edit = qobject_cast(QObject::sender()); - if (edit && edit->isModified()) { - edit->setModified(false); - emit changed(); +void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig) { + Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name.c_str(), .type = Item::Sig}; + parent_item->children.insert(pos, item); + QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum", "Maximum", "Description"}; + for (int i = 0; i < std::size(titles); ++i) { + item->children.push_back(new Item{.sig = sig, .parent = item, .title = titles[i], .type = (Item::Type)(i + Item::Name)}); } } -// SignalEdit - -SignalEdit::SignalEdit(int index, QWidget *parent) : form_idx(index), QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - main_layout->setSpacing(0); - - bg_color = QColor(getColor(form_idx)); - - // title bar - auto title_bar = new QWidget(this); - title_bar->setFixedHeight(32); - QHBoxLayout *title_layout = new QHBoxLayout(title_bar); - title_layout->setContentsMargins(0, 0, 0, 0); - title_bar->setStyleSheet("QToolButton {width:15px;height:15px;font-size:15px}"); - color_label = new QLabel(this); - color_label->setFixedWidth(25); - color_label->setContentsMargins(5, 0, 0, 0); - title_layout->addWidget(color_label); - icon = new QLabel(this); - title_layout->addWidget(icon); - title = new ElidedLabel(this); - title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - title_layout->addWidget(title); - - plot_btn = new QToolButton(this); - plot_btn->setIcon(bootstrapPixmap("graph-up")); - plot_btn->setCheckable(true); - plot_btn->setAutoRaise(true); - title_layout->addWidget(plot_btn); - auto remove_btn = new QToolButton(this); - remove_btn->setAutoRaise(true); - remove_btn->setIcon(bootstrapPixmap("x")); - remove_btn->setToolTip(tr("Remove signal")); - title_layout->addWidget(remove_btn); - main_layout->addWidget(title_bar); - - // signal form - form = new SignalForm(this); - form->setVisible(false); - main_layout->addWidget(form); - - // bottom line - QFrame *hline = new QFrame(); - hline->setFrameShape(QFrame::HLine); - hline->setFrameShadow(QFrame::Sunken); - main_layout->addWidget(hline); - - QObject::connect(title, &ElidedLabel::clicked, [this]() { emit showFormClicked(sig); }); - QObject::connect(plot_btn, &QToolButton::clicked, [this](bool checked) { - emit showChart(msg_id, sig, checked, QGuiApplication::keyboardModifiers() & Qt::ShiftModifier); - }); - QObject::connect(remove_btn, &QToolButton::clicked, [this]() { emit remove(sig); }); - QObject::connect(form, &SignalForm::changed, this, &SignalEdit::saveSignal); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); +void SignalModel::setMessage(const QString &id) { + msg_id = id; + filter_str = ""; + refresh(); + updateState(nullptr); } -void SignalEdit::setSignal(const QString &message_id, const Signal *signal) { - sig = signal; - updateForm(msg_id == message_id && form->isVisible()); - msg_id = message_id; - color_label->setText(QString::number(form_idx + 1)); - color_label->setStyleSheet(QString("color:black; background-color:%2").arg(bg_color.name())); - title->setText(sig->name.c_str()); - show(); +void SignalModel::setFilter(const QString &txt) { + filter_str = txt; + refresh(); } -void SignalEdit::saveSignal() { - Signal s = *sig; - s.name = form->name->text().toStdString(); - s.size = form->size->text().toInt(); - s.offset = form->offset->text().toDouble(); - s.factor = form->factor->text().toDouble(); - s.is_signed = form->sign->currentIndex() == 0; - bool little_endian = form->endianness->currentIndex() == 0; - if (little_endian != s.is_little_endian) { +void SignalModel::refresh() { + beginResetModel(); + root.reset(new SignalModel::Item); + if (auto msg = dbc()->msg(msg_id)) { + for (auto &s : msg->getSignals()) { + if (filter_str.isEmpty() || QString::fromStdString(s->name).contains(filter_str, Qt::CaseInsensitive)) { + insertItem(root.get(), root->children.size(), s); + } + } + } + endResetModel(); +} + +void SignalModel::updateState(const QHash *msgs) { + if (!msgs || (msgs->contains(msg_id))) { + auto &dat = can->lastMessage(msg_id).dat; + int row = 0; + for (auto item : root->children) { + double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig); + item->sig_val = QString::number(value); + emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); + ++row; + } + } +} + +int SignalModel::rowCount(const QModelIndex &parent) const { + if (parent.column() > 0) return 0; + + auto parent_item = getItem(parent); + int row_count = parent_item->children.size(); + if (parent_item->type == Item::Sig && !parent_item->extra_expanded) { + row_count -= (Item::Desc - Item::ExtraInfo); + } + return row_count; +} + +Qt::ItemFlags SignalModel::flags(const QModelIndex &index) const { + if (!index.isValid()) return Qt::NoItemFlags; + + auto item = getItem(index); + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + if (index.column() == 1 && item->type != Item::Sig && item->type != Item::ExtraInfo) { + flags |= (item->type == Item::Endian || item->type == Item::Signed) ? Qt::ItemIsUserCheckable : Qt::ItemIsEditable; + } + return flags; +} + +int SignalModel::signalRow(const Signal *sig) const { + auto &children = root->children; + for (int i = 0; i < children.size(); ++i) { + if (children[i]->sig == sig) return i; + } + return -1; +} + +QModelIndex SignalModel::index(int row, int column, const QModelIndex &parent) const { + if (!hasIndex(row, column, parent)) return {}; + return createIndex(row, column, getItem(parent)->children[row]); +} + +QModelIndex SignalModel::parent(const QModelIndex &index) const { + if (!index.isValid()) return {}; + Item *parent_item = getItem(index)->parent; + return parent_item == root.get() ? QModelIndex() : createIndex(parent_item->row(), 0, parent_item); +} + +QVariant SignalModel::data(const QModelIndex &index, int role) const { + if (index.isValid()) { + const Item *item = getItem(index); + if (role == Qt::DisplayRole || role == Qt::EditRole) { + if (index.column() == 0) { + return item->type == Item::Sig ? QString::fromStdString(item->sig->name) : item->title; + } else { + switch (item->type) { + case Item::Sig: return item->sig_val; + case Item::Name: return QString::fromStdString(item->sig->name); + case Item::Size: return item->sig->size; + case Item::Offset: return QString::number(item->sig->offset, 'f', 6); + case Item::Factor: return QString::number(item->sig->factor, 'f', 6); + default: break; + } + } + } else if (role == Qt::CheckStateRole && index.column() == 1) { + if (item->type == Item::Endian) return item->sig->is_little_endian ? Qt::Checked : Qt::Unchecked; + if (item->type == Item::Signed) return item->sig->is_signed ? Qt::Checked : Qt::Unchecked; + } else if (role == Qt::DecorationRole && index.column() == 0 && item->type == Item::ExtraInfo) { + return bootstrapPixmap(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up"); + } + } + return {}; +} + +bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int role) { + if (role != Qt::EditRole && role != Qt::CheckStateRole) return false; + + Item *item = getItem(index); + Signal s = *item->sig; + switch (item->type) { + case Item::Name: s.name = value.toString().toStdString(); break; + case Item::Size: s.size = value.toInt(); break; + case Item::Endian: s.is_little_endian = value.toBool(); break; + case Item::Signed: s.is_signed = value.toBool(); break; + case Item::Offset: s.offset = value.toDouble(); break; + case Item::Factor: s.factor = value.toDouble(); break; + default: return false; + } + bool ret = saveSignal(item->sig, s); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole}); + return ret; +} + +void SignalModel::showExtraInfo(const QModelIndex &index) { + auto item = getItem(index); + if (item->type == Item::ExtraInfo) { + if (!item->parent->extra_expanded) { + item->parent->extra_expanded = true; + beginInsertRows(index.parent(), 7, 13); + endInsertRows(); + } else { + item->parent->extra_expanded = false; + beginRemoveRows(index.parent(), 7, 13); + endRemoveRows(); + } + } +} + +bool SignalModel::saveSignal(const Signal *origin_s, Signal &s) { + auto msg = dbc()->msg(msg_id); + if (s.name != origin_s->name && msg->sigs.count(s.name.c_str()) != 0) { + QString text = tr("There is already a signal with the same name '%1'").arg(s.name.c_str()); + QMessageBox::warning(nullptr, tr("Failed to save signal"), text); + return false; + } + + if (s.is_little_endian != origin_s->is_little_endian) { int start = std::floor(s.start_bit / 8); - if (little_endian) { + if (s.is_little_endian) { int end = std::floor((s.start_bit - s.size + 1) / 8); s.start_bit = start == end ? s.start_bit - s.size + 1 : bigEndianStartBitsIndex(s.start_bit); } else { int end = std::floor((s.start_bit + s.size - 1) / 8); s.start_bit = start == end ? s.start_bit + s.size - 1 : bigEndianBitIndex(s.start_bit); } - s.is_little_endian = little_endian; } if (s.is_little_endian) { s.lsb = s.start_bit; @@ -177,43 +197,254 @@ void SignalEdit::saveSignal() { s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); s.msb = s.start_bit; } - if (s != *sig) { - emit save(this->sig, s); - } + + UndoStack::push(new EditSignalCommand(msg_id, origin_s, s)); + return true; } -void SignalEdit::setChartOpened(bool opened) { - plot_btn->setToolTip(opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened chart")); - plot_btn->setChecked(opened); -} - -void SignalEdit::updateForm(bool visible) { - if (visible && sig) { - if (form->name->text() != sig->name.c_str()) { - form->name->setText(sig->name.c_str()); +void SignalModel::addSignal(int start_bit, int size, bool little_endian) { + auto msg = dbc()->msg(msg_id); + for (int i = 1; !msg; ++i) { + QString name = QString("NEW_MSG_%1").arg(i); + if (std::none_of(dbc()->messages().begin(), dbc()->messages().end(), [&](auto &m) { return m.second.name == name; })) { + UndoStack::push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size())); + msg = dbc()->msg(msg_id); } - form->endianness->setCurrentIndex(sig->is_little_endian ? 0 : 1); - form->sign->setCurrentIndex(sig->is_signed ? 0 : 1); - form->factor->setText(QString::number(sig->factor)); - form->offset->setText(QString::number(sig->offset)); - form->size->setValue(sig->size); } - form->setVisible(visible); - icon->setText(visible ? "▼ " : "> "); + + 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; + } + updateSigSizeParamsFromRange(sig, start_bit, size); + UndoStack::push(new AddSigCommand(msg_id, sig)); } -void SignalEdit::signalHovered(const Signal *s) { - auto text_color = sig == s ? "white" : "black"; - auto _bg_color = sig == s ? bg_color.darker(125) : bg_color; // 4/5x brightness - color_label->setStyleSheet(QString("color:%1; background-color:%2").arg(text_color).arg(_bg_color.name())); +void SignalModel::resizeSignal(const Signal *sig, int start_bit, int size) { + Signal s = *sig; + updateSigSizeParamsFromRange(s, start_bit, size); + saveSignal(sig, s); } -void SignalEdit::enterEvent(QEvent *event) { - emit highlight(sig); - QWidget::enterEvent(event); +void SignalModel::removeSignal(const Signal *sig) { + UndoStack::push(new RemoveSigCommand(msg_id, sig)); } -void SignalEdit::leaveEvent(QEvent *event) { - emit highlight(nullptr); - QWidget::leaveEvent(event); +void SignalModel::handleMsgChanged(uint32_t address) { + if (address == DBCManager::parseId(msg_id).second) { + refresh(); + } +} + +void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) { + if (address == DBCManager::parseId(msg_id).second) { + int i = 0; + for (; i < root->children.size(); ++i) { + if (sig->start_bit < root->children[i]->sig->start_bit) break; + } + beginInsertRows({}, i, i); + insertItem(root.get(), i, sig); + endInsertRows(); + } +} + +void SignalModel::handleSignalUpdated(const Signal *sig) { + if (int row = signalRow(sig); row != -1) { + emit dataChanged(index(row, 0), index(row, 1), {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole}); + } +} + +void SignalModel::handleSignalRemoved(const Signal *sig) { + if (int row = signalRow(sig); row != -1) { + beginRemoveRows({}, row, row); + delete root->children.takeAt(row); + endRemoveRows(); + } +} + +// SignalItemDelegate + +SignalItemDelegate::SignalItemDelegate(QObject *parent) { + name_validator = new NameValidator(this); + double_validator = new QDoubleValidator(this); + double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system +} + +void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + auto item = (SignalModel::Item *)index.internalPointer(); + if (item && !index.parent().isValid() && index.column() == 0) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + if (option.state & QStyle::State_Selected) { + painter->fillRect(option.rect, option.palette.highlight()); + } + + // color label + auto bg_color = QColor(getColor(item->row())); + QRect rc{option.rect.left() + 3, option.rect.top(), 22, option.rect.height()}; + painter->setPen(Qt::NoPen); + painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); + painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 5, 5); + painter->setPen(item->highlight ? Qt::white : Qt::black); + painter->drawText(rc, Qt::AlignCenter, QString::number(item->row() + 1)); + + // signal name + QFont font; + font.setBold(true); + painter->setFont(font); + painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + painter->drawText(option.rect.adjusted(rc.width() + 9, 0, 0, 0), option.displayAlignment, index.data(Qt::DisplayRole).toString()); + painter->restore(); + } else { + QStyledItemDelegate::paint(painter, option, index); + } +} + +QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + auto item = (SignalModel::Item *)index.internalPointer(); + if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Offset || item->type == SignalModel::Item::Factor) { + QLineEdit *e = new QLineEdit(parent); + e->setFrame(false); + e->setValidator(index.row() == 0 ? name_validator : double_validator); + return e; + } else if (item->type == SignalModel::Item::Size) { + QSpinBox *spin = new QSpinBox(parent); + spin->setFrame(false); + spin->setRange(1, 64); + return spin; + } + return QStyledItemDelegate::createEditor(parent, option, index); +} + +// SignalView + +SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { + // title bar + QWidget *title_bar = new QWidget(this); + title_bar->setAutoFillBackground(true); + QHBoxLayout *hl = new QHBoxLayout(title_bar); + hl->addWidget(signal_count_lb = new QLabel()); + filter_edit = new QLineEdit(this); + filter_edit->setClearButtonEnabled(true); + filter_edit->setPlaceholderText(tr("filter signals by name")); + hl->addWidget(filter_edit); + hl->addStretch(1); + auto collapse_btn = new QToolButton(); + collapse_btn->setIcon(bootstrapPixmap("dash-square")); + collapse_btn->setIconSize({12, 12}); + collapse_btn->setAutoRaise(true); + collapse_btn->setToolTip(tr("Collapse All")); + hl->addWidget(collapse_btn); + + // tree view + tree = new QTreeView(this); + tree->setModel(model = new SignalModel(this)); + tree->setItemDelegate(new SignalItemDelegate(this)); + tree->setFrameShape(QFrame::NoFrame); + tree->setHeaderHidden(true); + tree->setMouseTracking(true); + tree->setExpandsOnDoubleClick(false); + tree->header()->setSectionResizeMode(QHeaderView::Stretch); + tree->setMinimumHeight(300); + tree->setStyleSheet("QSpinBox{background-color:white;border:none;} QLineEdit{background-color:white;}"); + + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); + main_layout->addWidget(title_bar); + main_layout->addWidget(tree); + + QObject::connect(filter_edit, &QLineEdit::textEdited, model, &SignalModel::setFilter); + QObject::connect(collapse_btn, &QPushButton::clicked, tree, &QTreeView::collapseAll); + QObject::connect(tree, &QAbstractItemView::clicked, this, &SignalView::rowClicked); + QObject::connect(tree, &QTreeView::viewportEntered, [this]() { emit highlight(nullptr); }); + QObject::connect(tree, &QTreeView::entered, [this](const QModelIndex &index) { emit highlight(model->getItem(index)->sig); }); + QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); + QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged); + QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); + QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { expandSignal(sig); }); +} + +void SignalView::setMessage(const QString &id) { + msg_id = id; + filter_edit->clear(); + model->setMessage(id); +} + +void SignalView::rowsChanged() { + auto create_btn = [](const QString &id, const QString &tooltip) { + auto btn = new QToolButton(); + btn->setIcon(bootstrapPixmap(id)); + btn->setToolTip(tooltip); + btn->setAutoRaise(true); + return btn; + }; + + signal_count_lb->setText(tr("Signals: %1").arg(model->rowCount())); + + for (int i = 0; i < model->rowCount(); ++i) { + auto index = model->index(i, 1); + if (!tree->indexWidget(index)) { + QWidget *w = new QWidget(this); + QHBoxLayout *h = new QHBoxLayout(w); + h->setContentsMargins(0, 2, 0, 2); + h->addStretch(1); + + auto remove_btn = create_btn("x", tr("Remove signal")); + auto plot_btn = create_btn("graph-up", ""); + plot_btn->setCheckable(true); + h->addWidget(plot_btn); + h->addWidget(remove_btn); + + tree->setIndexWidget(index, w); + auto sig = model->getItem(index)->sig; + QObject::connect(remove_btn, &QToolButton::clicked, [=]() { model->removeSignal(sig); }); + QObject::connect(plot_btn, &QToolButton::clicked, [=](bool checked) { + emit showChart(msg_id, sig, checked, QGuiApplication::keyboardModifiers() & Qt::ShiftModifier); + }); + } + } + updateChartState(); +} + +void SignalView::rowClicked(const QModelIndex &index) { + auto item = model->getItem(index); + if (item->type == SignalModel::Item::Sig) { + auto sig_index = model->index(index.row(), 0, index.parent()); + tree->setExpanded(sig_index, !tree->isExpanded(sig_index)); + } else if (item->type == SignalModel::Item::ExtraInfo) { + model->showExtraInfo(index); + } +} + +void SignalView::expandSignal(const Signal *sig) { + if (int row = model->signalRow(sig); row != -1) { + auto idx = model->index(row, 0); + bool expand = !tree->isExpanded(idx); + tree->setExpanded(idx, expand); + tree->scrollTo(idx, QAbstractItemView::PositionAtTop); + if (expand) tree->setCurrentIndex(idx); + } +} + +void SignalView::updateChartState() { + int i = 0; + for (auto item : model->root->children) { + auto plot_btn = tree->indexWidget(model->index(i, 1))->findChildren()[0]; + bool chart_opened = charts->hasSignal(msg_id, item->sig); + plot_btn->setChecked(chart_opened); + plot_btn->setToolTip(chart_opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened plot")); + ++i; + } +} + +void SignalView::signalHovered(const Signal *sig) { + auto &children = model->root->children; + for (int i = 0; i < children.size(); ++i) { + bool highlight = children[i]->sig == sig; + if (std::exchange(children[i]->highlight, highlight) != highlight) { + emit model->dataChanged(model->index(i, 0), model->index(i, 0)); + } + } } diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 90df3fd3f4..ae88a5b13a 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -1,59 +1,97 @@ #pragma once -#include +#include #include #include -#include -#include +#include +#include -#include "selfdrive/ui/qt/widgets/controls.h" +#include "tools/cabana/chartswidget.h" #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -class SignalForm : public QWidget { +class SignalModel : public QAbstractItemModel { Q_OBJECT public: - SignalForm(QWidget *parent); - void textBoxEditingFinished(); + struct Item { + enum Type {Root, Sig, Name, Size, Endian, Signed, Offset, Factor, ExtraInfo, Unit, Comment, Min, Max, Desc }; + ~Item() { qDeleteAll(children); } + inline int row() { return parent->children.indexOf(this); } - QLineEdit *name, *unit, *comment, *val_desc, *offset, *factor, *min_val, *max_val; - QSpinBox *size; - QComboBox *sign, *endianness; - QToolButton *expand_btn; + Type type = Type::Root; + Item *parent = nullptr; + QList children; -signals: - void changed(); + const Signal *sig = nullptr; + QString title; + bool highlight = false; + bool extra_expanded = false; + QString sig_val = "-"; + }; + + SignalModel(QObject *parent); + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 2; } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + void setMessage(const QString &id); + void setFilter(const QString &txt); + void addSignal(int start_bit, int size, bool little_endian); + bool saveSignal(const Signal *origin_s, Signal &s); + void resizeSignal(const Signal *sig, int start_bit, int size); + void removeSignal(const Signal *sig); + inline Item *getItem(const QModelIndex &index) const { return index.isValid() ? (Item *)index.internalPointer() : root.get(); } + int signalRow(const Signal *sig) const; + void showExtraInfo(const QModelIndex &index); + +private: + void insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig); + void handleSignalAdded(uint32_t address, const Signal *sig); + void handleSignalUpdated(const Signal *sig); + void handleSignalRemoved(const Signal *sig); + void handleMsgChanged(uint32_t address); + void refresh(); + void updateState(const QHash *msgs); + + QString msg_id; + QString filter_str; + std::unique_ptr root; + friend class SignalView; }; -class SignalEdit : public QWidget { +class SignalItemDelegate : public QStyledItemDelegate { +public: + SignalItemDelegate(QObject *parent); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QValidator *name_validator, *double_validator; +}; + +class SignalView : public QWidget { Q_OBJECT public: - SignalEdit(int index, QWidget *parent = nullptr); - void setSignal(const QString &msg_id, const Signal *sig); - void setChartOpened(bool opened); + SignalView(ChartsWidget *charts, QWidget *parent); + void setMessage(const QString &id); void signalHovered(const Signal *sig); - void updateForm(bool show); - const Signal *sig = nullptr; - SignalForm *form = nullptr; - QString msg_id; + void updateChartState(); + void expandSignal(const Signal *sig); + void rowClicked(const QModelIndex &index); + SignalModel *model = nullptr; signals: void highlight(const Signal *sig); 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(const Signal *sig); -protected: - void enterEvent(QEvent *event) override; - void leaveEvent(QEvent *event) override; - void saveSignal(); +private: + void rowsChanged(); - ElidedLabel *title; - QLabel *color_label; - QLabel *icon; - int form_idx = 0; - QColor bg_color; - QToolButton *plot_btn; + QString msg_id; + QTreeView *tree; + QLineEdit *filter_edit; + ChartsWidget *charts; + QLabel *signal_count_lb; }; From 9822f1b0b46c5d63290e3ef8b3f103d7aba13bd9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 30 Jan 2023 11:20:52 +0800 Subject: [PATCH 0771/1179] cabana: fixed the column selector is always hidden if settings.chart_column_count is 1 (#27146) fix column selector --- tools/cabana/chartswidget.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 580cce5521..8dde735a57 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -229,7 +229,7 @@ void ChartsWidget::setColumnCount(int n) { } void ChartsWidget::updateLayout() { - int n = column_count; + int n = columns_cb->count(); for (; n > 1; --n) { if ((n * CHART_MIN_WIDTH + (n - 1) * charts_layout->spacing()) < charts_layout->geometry().width()) break; } @@ -238,6 +238,7 @@ void ChartsWidget::updateLayout() { columns_lb_action->setVisible(show_column_cb); columns_cb_action->setVisible(show_column_cb); + n = std::min(column_count, n); for (int i = 0; i < charts.size(); ++i) { charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); } From 078f06dbaff2d1af57f1294095cfbd9c6e357ce1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 31 Jan 2023 02:56:03 +0800 Subject: [PATCH 0772/1179] cabana: draw message bytes at the same width (#27150) --- tools/cabana/util.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 726cbbe2a1..023e893e11 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -65,11 +65,6 @@ MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegat } void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QList colors = index.data(Qt::UserRole).toList(); - if (colors.empty()) { - QStyledItemDelegate::paint(painter, option, index); - return; - } QStyleOptionViewItemV4 opt = option; initStyleOption(&opt, index); @@ -87,6 +82,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & int m = space.width() / 2; const QMargins margins(m, m, m, m); + QList colors = index.data(Qt::UserRole).toList(); int i = 0; for (auto &byte : opt.text.split(" ")) { if (i < colors.size()) { From afa85e0256a482f046fcb89495a06ef67b5d673f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 31 Jan 2023 02:57:16 +0800 Subject: [PATCH 0773/1179] cabana: remove the margins of the legend item (#27152) --- tools/cabana/chartswidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8dde735a57..378cc52bbb 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -305,6 +305,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { axis_y = new QValueAxis(this); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); + chart->legend()->layout()->setContentsMargins(0, 0, 40, 0); chart->legend()->setShowToolTips(true); chart->layout()->setContentsMargins(0, 0, 0, 0); chart->setMargins({20, 11, 11, 11}); From 3815afbde74b69ce1057ae0162364f19f5baee0a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 31 Jan 2023 02:57:35 +0800 Subject: [PATCH 0774/1179] cabana: small improvements to MessageListModel::setFilterString (#27153) --- tools/cabana/messageswidget.cc | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index b7c3cd3401..0526ff141f 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -84,27 +84,22 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } void MessageListModel::setFilterString(const QString &string) { + auto contains = [](const QString &id, const QString &txt) { + auto cs = Qt::CaseInsensitive; + if (id.contains(txt, cs) || msgName(id).contains(txt, cs)) return true; + // Search by signal name + if (const auto msg = dbc()->msg(id)) { + for (auto &signal : msg->getSignals()) { + if (QString::fromStdString(signal->name).contains(txt, cs)) return true; + } + } + return false; + }; + filter_str = string; msgs.clear(); for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { - bool found = false; - - // Search by message id or name - if (it.key().contains(filter_str, Qt::CaseInsensitive) || msgName(it.key()).contains(filter_str, Qt::CaseInsensitive)) { - found = true; - } - - // Search by signal name - const DBCMsg *msg = dbc()->msg(it.key()); - if (msg != nullptr) { - for (auto &signal: msg->getSignals()) { - if (QString::fromStdString(signal->name).contains(filter_str, Qt::CaseInsensitive)) { - found = true; - } - } - } - - if (found) { + if (filter_str.isEmpty() || contains(it.key(), filter_str)) { msgs.push_back(it.key()); } } From fba4827a7b9c6441cf85799770503229a361667f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 31 Jan 2023 05:56:34 +0800 Subject: [PATCH 0775/1179] cabana: restrict the rubber band in plot area. (#27154) --- tools/cabana/chartswidget.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 378cc52bbb..2edc89d857 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -656,7 +656,16 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { } else { QToolTip::hideText(); } + QChartView::mouseMoveEvent(ev); + if (is_zooming) { + QRect rubber_rect = rubber->geometry(); + rubber_rect.setLeft(std::max(rubber_rect.left(), (int)plot_area.left())); + rubber_rect.setRight(std::min(rubber_rect.right(), (int)plot_area.right())); + if (rubber_rect != rubber->geometry()) { + rubber->setGeometry(rubber_rect); + } + } } void ChartView::dragMoveEvent(QDragMoveEvent *event) { From e2f5b164bd3dcffc5a11ef552f83296c34991949 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Mon, 30 Jan 2023 17:34:07 -0700 Subject: [PATCH 0776/1179] Ubloxd: glonass parsing tests (#27125) * add glonass kaitai parsing * add kaita generated files * remove glonass from build * add string non immediate type * fix kaitai bug * cleanUp * add patch file * fix scons order * make lookup const * remove comments * rename * add to release files * remove printf * add signs * add glonass parsing test * finish up glonass kaitai tests * move cereal back to master * ignore test_runner * sign is not two complement * address comments --------- Co-authored-by: Kurt Nistelberger --- .github/workflows/selfdrive_tests.yaml | 1 + release/files_common | 5 +- selfdrive/locationd/.gitignore | 1 + selfdrive/locationd/SConscript | 6 +- selfdrive/locationd/generated/glonass.cpp | 176 ++++++++- selfdrive/locationd/generated/glonass.h | 191 ++++++++-- selfdrive/locationd/glonass.ksy | 119 ++++-- selfdrive/locationd/glonass_fix.patch | 2 +- .../locationd/test/test_glonass_kaitai.cc | 360 ++++++++++++++++++ .../locationd/test/test_glonass_runner.cc | 2 + 10 files changed, 796 insertions(+), 67 deletions(-) create mode 100644 selfdrive/locationd/test/test_glonass_kaitai.cc create mode 100644 selfdrive/locationd/test/test_glonass_runner.cc diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index a4f7c68573..d5be221303 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -219,6 +219,7 @@ jobs: $UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/locationd && \ selfdrive/locationd/test/_test_locationd_lib.py && \ + ./selfdrive/locationd/test/test_glonass_runner && \ $UNIT_TEST selfdrive/athena && \ $UNIT_TEST selfdrive/thermald && \ $UNIT_TEST system/hardware/tici && \ diff --git a/release/files_common b/release/files_common index 547bb58144..5b310d5c80 100644 --- a/release/files_common +++ b/release/files_common @@ -225,10 +225,7 @@ selfdrive/locationd/SConscript selfdrive/locationd/ubloxd.cc selfdrive/locationd/ublox_msg.cc selfdrive/locationd/ublox_msg.h -selfdrive/locationd/generated/ubx.cpp -selfdrive/locationd/generated/ubx.h -selfdrive/locationd/generated/gps.cpp -selfdrive/locationd/generated/gps.h +selfdrive/locationd/generated/* selfdrive/locationd/laikad.py selfdrive/locationd/locationd.h diff --git a/selfdrive/locationd/.gitignore b/selfdrive/locationd/.gitignore index 5268902785..86a228a6ff 100644 --- a/selfdrive/locationd/.gitignore +++ b/selfdrive/locationd/.gitignore @@ -3,3 +3,4 @@ ubloxd_test params_learner paramsd locationd +test/test_glonass_runner diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index 7024196efd..61a0ed7f42 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -13,7 +13,8 @@ if GetOption('kaitai'): patch = env.Command(None, 'glonass_fix.patch', 'git apply $SOURCES') env.Depends(patch, glonass) -env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "generated/ubx.cpp", "generated/gps.cpp"], LIBS=loc_libs) +glonass_obj = env.Object('generated/glonass.cpp') +env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "generated/ubx.cpp", "generated/gps.cpp", glonass_obj], LIBS=loc_libs) ekf_sym_cc = env.SharedObject("#rednose/helpers/ekf_sym.cc") locationd_sources = ["locationd.cc", "models/live_kf.cc", ekf_sym_cc] @@ -25,3 +26,6 @@ lenv.Depends(locationd, libkf) if File("liblocationd.cc").exists(): liblocationd = lenv.SharedLibrary("liblocationd", ["liblocationd.cc"] + locationd_sources, LIBS=loc_libs + transformations) lenv.Depends(liblocationd, libkf) + +if GetOption('test'): + env.Program("test/test_glonass_runner", ['test/test_glonass_runner.cc', 'test/test_glonass_kaitai.cc', glonass_obj], LIBS=[loc_libs]) \ No newline at end of file diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp index 149134fbb5..cd0f96ab68 100644 --- a/selfdrive/locationd/generated/glonass.cpp +++ b/selfdrive/locationd/generated/glonass.cpp @@ -31,6 +31,10 @@ void glonass_t::_read() { m_data = new string_3_t(m__io, this, m__root); break; } + case 5: { + m_data = new string_5_t(m__io, this, m__root); + break; + } case 2: { m_data = new string_2_t(m__io, this, m__root); break; @@ -60,6 +64,8 @@ void glonass_t::_clean_up() { glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_tau_n = false; + f_delta_tau_n = false; try { _read(); @@ -70,8 +76,10 @@ glonass_t::string_4_t::string_4_t(kaitai::kstream* p__io, glonass_t* p__parent, } void glonass_t::string_4_t::_read() { - m_tau_n = m__io->read_bits_int_be(22); - m_delta_tau_n = m__io->read_bits_int_be(5); + m_tau_n_sign = m__io->read_bits_int_be(1); + m_tau_n_value = m__io->read_bits_int_be(21); + m_delta_tau_n_sign = m__io->read_bits_int_be(1); + m_delta_tau_n_value = m__io->read_bits_int_be(4); m_e_n = m__io->read_bits_int_be(5); m_not_used_1 = m__io->read_bits_int_be(14); m_p4 = m__io->read_bits_int_be(1); @@ -89,6 +97,22 @@ glonass_t::string_4_t::~string_4_t() { void glonass_t::string_4_t::_clean_up() { } +int32_t glonass_t::string_4_t::tau_n() { + if (f_tau_n) + return m_tau_n; + m_tau_n = ((tau_n_sign()) ? ((tau_n_value() * -1)) : (tau_n_value())); + f_tau_n = true; + return m_tau_n; +} + +int32_t glonass_t::string_4_t::delta_tau_n() { + if (f_delta_tau_n) + return m_delta_tau_n; + m_delta_tau_n = ((delta_tau_n_sign()) ? ((delta_tau_n_value() * -1)) : (delta_tau_n_value())); + f_delta_tau_n = true; + return m_delta_tau_n; +} + glonass_t::string_non_immediate_t::string_non_immediate_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; @@ -113,9 +137,40 @@ glonass_t::string_non_immediate_t::~string_non_immediate_t() { void glonass_t::string_non_immediate_t::_clean_up() { } +glonass_t::string_5_t::string_5_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void glonass_t::string_5_t::_read() { + m_n_a = m__io->read_bits_int_be(11); + m_tau_c = m__io->read_bits_int_be(32); + m_not_used = m__io->read_bits_int_be(1); + m_n_4 = m__io->read_bits_int_be(5); + m_tau_gps = m__io->read_bits_int_be(22); + m_l_n = m__io->read_bits_int_be(1); +} + +glonass_t::string_5_t::~string_5_t() { + _clean_up(); +} + +void glonass_t::string_5_t::_clean_up() { +} + glonass_t::string_1_t::string_1_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_x_vel = false; + f_x_accel = false; + f_x = false; try { _read(); @@ -129,9 +184,12 @@ void glonass_t::string_1_t::_read() { m_not_used = m__io->read_bits_int_be(2); m_p1 = m__io->read_bits_int_be(2); m_t_k = m__io->read_bits_int_be(12); - m_x_vel = m__io->read_bits_int_be(24); - m_x_speedup = m__io->read_bits_int_be(5); - m_x = m__io->read_bits_int_be(27); + m_x_vel_sign = m__io->read_bits_int_be(1); + m_x_vel_value = m__io->read_bits_int_be(23); + m_x_accel_sign = m__io->read_bits_int_be(1); + m_x_accel_value = m__io->read_bits_int_be(4); + m_x_sign = m__io->read_bits_int_be(1); + m_x_value = m__io->read_bits_int_be(26); } glonass_t::string_1_t::~string_1_t() { @@ -141,9 +199,36 @@ glonass_t::string_1_t::~string_1_t() { void glonass_t::string_1_t::_clean_up() { } +int32_t glonass_t::string_1_t::x_vel() { + if (f_x_vel) + return m_x_vel; + m_x_vel = ((x_vel_sign()) ? ((x_vel_value() * -1)) : (x_vel_value())); + f_x_vel = true; + return m_x_vel; +} + +int32_t glonass_t::string_1_t::x_accel() { + if (f_x_accel) + return m_x_accel; + m_x_accel = ((x_accel_sign()) ? ((x_accel_value() * -1)) : (x_accel_value())); + f_x_accel = true; + return m_x_accel; +} + +int32_t glonass_t::string_1_t::x() { + if (f_x) + return m_x; + m_x = ((x_sign()) ? ((x_value() * -1)) : (x_value())); + f_x = true; + return m_x; +} + glonass_t::string_2_t::string_2_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_y_vel = false; + f_y_accel = false; + f_y = false; try { _read(); @@ -158,9 +243,12 @@ void glonass_t::string_2_t::_read() { m_p2 = m__io->read_bits_int_be(1); m_t_b = m__io->read_bits_int_be(7); m_not_used = m__io->read_bits_int_be(5); - m_y_vel = m__io->read_bits_int_be(24); - m_y_speedup = m__io->read_bits_int_be(5); - m_y = m__io->read_bits_int_be(27); + m_y_vel_sign = m__io->read_bits_int_be(1); + m_y_vel_value = m__io->read_bits_int_be(23); + m_y_accel_sign = m__io->read_bits_int_be(1); + m_y_accel_value = m__io->read_bits_int_be(4); + m_y_sign = m__io->read_bits_int_be(1); + m_y_value = m__io->read_bits_int_be(26); } glonass_t::string_2_t::~string_2_t() { @@ -170,9 +258,37 @@ glonass_t::string_2_t::~string_2_t() { void glonass_t::string_2_t::_clean_up() { } +int32_t glonass_t::string_2_t::y_vel() { + if (f_y_vel) + return m_y_vel; + m_y_vel = ((y_vel_sign()) ? ((y_vel_value() * -1)) : (y_vel_value())); + f_y_vel = true; + return m_y_vel; +} + +int32_t glonass_t::string_2_t::y_accel() { + if (f_y_accel) + return m_y_accel; + m_y_accel = ((y_accel_sign()) ? ((y_accel_value() * -1)) : (y_accel_value())); + f_y_accel = true; + return m_y_accel; +} + +int32_t glonass_t::string_2_t::y() { + if (f_y) + return m_y; + m_y = ((y_sign()) ? ((y_value() * -1)) : (y_value())); + f_y = true; + return m_y; +} + glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, glonass_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; + f_gamma_n = false; + f_z_vel = false; + f_z_accel = false; + f_z = false; try { _read(); @@ -184,13 +300,17 @@ glonass_t::string_3_t::string_3_t(kaitai::kstream* p__io, glonass_t* p__parent, void glonass_t::string_3_t::_read() { m_p3 = m__io->read_bits_int_be(1); - m_gamma_n = m__io->read_bits_int_be(11); + m_gamma_n_sign = m__io->read_bits_int_be(1); + m_gamma_n_value = m__io->read_bits_int_be(10); m_not_used = m__io->read_bits_int_be(1); m_p = m__io->read_bits_int_be(2); m_l_n = m__io->read_bits_int_be(1); - m_z_vel = m__io->read_bits_int_be(24); - m_z_speedup = m__io->read_bits_int_be(5); - m_z = m__io->read_bits_int_be(27); + m_z_vel_sign = m__io->read_bits_int_be(1); + m_z_vel_value = m__io->read_bits_int_be(23); + m_z_accel_sign = m__io->read_bits_int_be(1); + m_z_accel_value = m__io->read_bits_int_be(4); + m_z_sign = m__io->read_bits_int_be(1); + m_z_value = m__io->read_bits_int_be(26); } glonass_t::string_3_t::~string_3_t() { @@ -199,3 +319,35 @@ glonass_t::string_3_t::~string_3_t() { void glonass_t::string_3_t::_clean_up() { } + +int32_t glonass_t::string_3_t::gamma_n() { + if (f_gamma_n) + return m_gamma_n; + m_gamma_n = ((gamma_n_sign()) ? ((gamma_n_value() * -1)) : (gamma_n_value())); + f_gamma_n = true; + return m_gamma_n; +} + +int32_t glonass_t::string_3_t::z_vel() { + if (f_z_vel) + return m_z_vel; + m_z_vel = ((z_vel_sign()) ? ((z_vel_value() * -1)) : (z_vel_value())); + f_z_vel = true; + return m_z_vel; +} + +int32_t glonass_t::string_3_t::z_accel() { + if (f_z_accel) + return m_z_accel; + m_z_accel = ((z_accel_sign()) ? ((z_accel_value() * -1)) : (z_accel_value())); + f_z_accel = true; + return m_z_accel; +} + +int32_t glonass_t::string_3_t::z() { + if (f_z) + return m_z; + m_z = ((z_sign()) ? ((z_value() * -1)) : (z_value())); + f_z = true; + return m_z; +} diff --git a/selfdrive/locationd/generated/glonass.h b/selfdrive/locationd/generated/glonass.h index 48bdabfe96..19867ba22b 100644 --- a/selfdrive/locationd/generated/glonass.h +++ b/selfdrive/locationd/generated/glonass.h @@ -15,6 +15,7 @@ class glonass_t : public kaitai::kstruct { public: class string_4_t; class string_non_immediate_t; + class string_5_t; class string_1_t; class string_2_t; class string_3_t; @@ -42,8 +43,24 @@ public: ~string_4_t(); private: - uint64_t m_tau_n; - uint64_t m_delta_tau_n; + bool f_tau_n; + int32_t m_tau_n; + + public: + int32_t tau_n(); + + private: + bool f_delta_tau_n; + int32_t m_delta_tau_n; + + public: + int32_t delta_tau_n(); + + private: + bool m_tau_n_sign; + uint64_t m_tau_n_value; + bool m_delta_tau_n_sign; + uint64_t m_delta_tau_n_value; uint64_t m_e_n; uint64_t m_not_used_1; bool m_p4; @@ -56,8 +73,10 @@ public: glonass_t* m__parent; public: - uint64_t tau_n() const { return m_tau_n; } - uint64_t delta_tau_n() const { return m_delta_tau_n; } + bool tau_n_sign() const { return m_tau_n_sign; } + uint64_t tau_n_value() const { return m_tau_n_value; } + bool delta_tau_n_sign() const { return m_delta_tau_n_sign; } + uint64_t delta_tau_n_value() const { return m_delta_tau_n_value; } uint64_t e_n() const { return m_e_n; } uint64_t not_used_1() const { return m_not_used_1; } bool p4() const { return m_p4; } @@ -96,6 +115,40 @@ public: glonass_t* _parent() const { return m__parent; } }; + class string_5_t : public kaitai::kstruct { + + public: + + string_5_t(kaitai::kstream* p__io, glonass_t* p__parent = 0, glonass_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~string_5_t(); + + private: + uint64_t m_n_a; + uint64_t m_tau_c; + bool m_not_used; + uint64_t m_n_4; + uint64_t m_tau_gps; + bool m_l_n; + glonass_t* m__root; + glonass_t* m__parent; + + public: + uint64_t n_a() const { return m_n_a; } + uint64_t tau_c() const { return m_tau_c; } + bool not_used() const { return m_not_used; } + uint64_t n_4() const { return m_n_4; } + uint64_t tau_gps() const { return m_tau_gps; } + bool l_n() const { return m_l_n; } + glonass_t* _root() const { return m__root; } + glonass_t* _parent() const { return m__parent; } + }; + class string_1_t : public kaitai::kstruct { public: @@ -109,13 +162,37 @@ public: public: ~string_1_t(); + private: + bool f_x_vel; + int32_t m_x_vel; + + public: + int32_t x_vel(); + + private: + bool f_x_accel; + int32_t m_x_accel; + + public: + int32_t x_accel(); + + private: + bool f_x; + int32_t m_x; + + public: + int32_t x(); + private: uint64_t m_not_used; uint64_t m_p1; uint64_t m_t_k; - uint64_t m_x_vel; - uint64_t m_x_speedup; - uint64_t m_x; + bool m_x_vel_sign; + uint64_t m_x_vel_value; + bool m_x_accel_sign; + uint64_t m_x_accel_value; + bool m_x_sign; + uint64_t m_x_value; glonass_t* m__root; glonass_t* m__parent; @@ -123,9 +200,12 @@ public: uint64_t not_used() const { return m_not_used; } uint64_t p1() const { return m_p1; } uint64_t t_k() const { return m_t_k; } - uint64_t x_vel() const { return m_x_vel; } - uint64_t x_speedup() const { return m_x_speedup; } - uint64_t x() const { return m_x; } + bool x_vel_sign() const { return m_x_vel_sign; } + uint64_t x_vel_value() const { return m_x_vel_value; } + bool x_accel_sign() const { return m_x_accel_sign; } + uint64_t x_accel_value() const { return m_x_accel_value; } + bool x_sign() const { return m_x_sign; } + uint64_t x_value() const { return m_x_value; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; @@ -143,14 +223,38 @@ public: public: ~string_2_t(); + private: + bool f_y_vel; + int32_t m_y_vel; + + public: + int32_t y_vel(); + + private: + bool f_y_accel; + int32_t m_y_accel; + + public: + int32_t y_accel(); + + private: + bool f_y; + int32_t m_y; + + public: + int32_t y(); + private: uint64_t m_b_n; bool m_p2; uint64_t m_t_b; uint64_t m_not_used; - uint64_t m_y_vel; - uint64_t m_y_speedup; - uint64_t m_y; + bool m_y_vel_sign; + uint64_t m_y_vel_value; + bool m_y_accel_sign; + uint64_t m_y_accel_value; + bool m_y_sign; + uint64_t m_y_value; glonass_t* m__root; glonass_t* m__parent; @@ -159,9 +263,12 @@ public: bool p2() const { return m_p2; } uint64_t t_b() const { return m_t_b; } uint64_t not_used() const { return m_not_used; } - uint64_t y_vel() const { return m_y_vel; } - uint64_t y_speedup() const { return m_y_speedup; } - uint64_t y() const { return m_y; } + bool y_vel_sign() const { return m_y_vel_sign; } + uint64_t y_vel_value() const { return m_y_vel_value; } + bool y_accel_sign() const { return m_y_accel_sign; } + uint64_t y_accel_value() const { return m_y_accel_value; } + bool y_sign() const { return m_y_sign; } + uint64_t y_value() const { return m_y_value; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; @@ -179,27 +286,63 @@ public: public: ~string_3_t(); + private: + bool f_gamma_n; + int32_t m_gamma_n; + + public: + int32_t gamma_n(); + + private: + bool f_z_vel; + int32_t m_z_vel; + + public: + int32_t z_vel(); + + private: + bool f_z_accel; + int32_t m_z_accel; + + public: + int32_t z_accel(); + + private: + bool f_z; + int32_t m_z; + + public: + int32_t z(); + private: bool m_p3; - uint64_t m_gamma_n; + bool m_gamma_n_sign; + uint64_t m_gamma_n_value; bool m_not_used; uint64_t m_p; bool m_l_n; - uint64_t m_z_vel; - uint64_t m_z_speedup; - uint64_t m_z; + bool m_z_vel_sign; + uint64_t m_z_vel_value; + bool m_z_accel_sign; + uint64_t m_z_accel_value; + bool m_z_sign; + uint64_t m_z_value; glonass_t* m__root; glonass_t* m__parent; public: bool p3() const { return m_p3; } - uint64_t gamma_n() const { return m_gamma_n; } + bool gamma_n_sign() const { return m_gamma_n_sign; } + uint64_t gamma_n_value() const { return m_gamma_n_value; } bool not_used() const { return m_not_used; } uint64_t p() const { return m_p; } bool l_n() const { return m_l_n; } - uint64_t z_vel() const { return m_z_vel; } - uint64_t z_speedup() const { return m_z_speedup; } - uint64_t z() const { return m_z; } + bool z_vel_sign() const { return m_z_vel_sign; } + uint64_t z_vel_value() const { return m_z_vel_value; } + bool z_accel_sign() const { return m_z_accel_sign; } + uint64_t z_accel_value() const { return m_z_accel_value; } + bool z_sign() const { return m_z_sign; } + uint64_t z_value() const { return m_z_value; } glonass_t* _root() const { return m__root; } glonass_t* _parent() const { return m__parent; } }; diff --git a/selfdrive/locationd/glonass.ksy b/selfdrive/locationd/glonass.ksy index 95ca78c16f..be99f6e497 100644 --- a/selfdrive/locationd/glonass.ksy +++ b/selfdrive/locationd/glonass.ksy @@ -1,4 +1,6 @@ # http://gauss.gge.unb.ca/GLONASS.ICD.pdf +# some variables are misprinted but good in the old doc +# https://www.unavco.org/help/glossary/docs/ICD_GLONASS_4.0_(1998)_en.pdf meta: id: glonass endian: be @@ -16,6 +18,7 @@ seq: 2: string_2 3: string_3 4: string_4 + 5: string_5 _: string_non_immediate - id: hamming_code type: b8 @@ -37,12 +40,25 @@ types: type: b2 - id: t_k type: b12 - - id: x_vel - type: b24 - - id: x_speedup - type: b5 - - id: x - type: b27 + - id: x_vel_sign + type: b1 + - id: x_vel_value + type: b23 + - id: x_accel_sign + type: b1 + - id: x_accel_value + type: b4 + - id: x_sign + type: b1 + - id: x_value + type: b26 + instances: + x_vel: + value: 'x_vel_sign ? (x_vel_value * (-1)) : x_vel_value' + x_accel: + value: 'x_accel_sign ? (x_accel_value * (-1)) : x_accel_value' + x: + value: 'x_sign ? (x_value * (-1)) : x_value' string_2: seq: - id: b_n @@ -53,36 +69,70 @@ types: type: b7 - id: not_used type: b5 - - id: y_vel - type: b24 - - id: y_speedup - type: b5 - - id: y - type: b27 + - id: y_vel_sign + type: b1 + - id: y_vel_value + type: b23 + - id: y_accel_sign + type: b1 + - id: y_accel_value + type: b4 + - id: y_sign + type: b1 + - id: y_value + type: b26 + instances: + y_vel: + value: 'y_vel_sign ? (y_vel_value * (-1)) : y_vel_value' + y_accel: + value: 'y_accel_sign ? (y_accel_value * (-1)) : y_accel_value' + y: + value: 'y_sign ? (y_value * (-1)) : y_value' string_3: seq: - id: p3 type: b1 - - id: gamma_n - type: b11 + - id: gamma_n_sign + type: b1 + - id: gamma_n_value + type: b10 - id: not_used type: b1 - id: p type: b2 - id: l_n type: b1 - - id: z_vel - type: b24 - - id: z_speedup - type: b5 - - id: z - type: b27 + - id: z_vel_sign + type: b1 + - id: z_vel_value + type: b23 + - id: z_accel_sign + type: b1 + - id: z_accel_value + type: b4 + - id: z_sign + type: b1 + - id: z_value + type: b26 + instances: + gamma_n: + value: 'gamma_n_sign ? (gamma_n_value * (-1)) : gamma_n_value' + z_vel: + value: 'z_vel_sign ? (z_vel_value * (-1)) : z_vel_value' + z_accel: + value: 'z_accel_sign ? (z_accel_value * (-1)) : z_accel_value' + z: + value: 'z_sign ? (z_value * (-1)) : z_value' string_4: seq: - - id: tau_n - type: b22 - - id: delta_tau_n - type: b5 + - id: tau_n_sign + type: b1 + - id: tau_n_value + type: b21 + - id: delta_tau_n_sign + type: b1 + - id: delta_tau_n_value + type: b4 - id: e_n type: b5 - id: not_used_1 @@ -99,9 +149,28 @@ types: type: b5 - id: m type: b2 + instances: + tau_n: + value: 'tau_n_sign ? (tau_n_value * (-1)) : tau_n_value' + delta_tau_n: + value: 'delta_tau_n_sign ? (delta_tau_n_value * (-1)) : delta_tau_n_value' + string_5: + seq: + - id: n_a + type: b11 + - id: tau_c + type: b32 + - id: not_used + type: b1 + - id: n_4 + type: b5 + - id: tau_gps + type: b22 + - id: l_n + type: b1 string_non_immediate: seq: - id: data_1 type: b64 - id: data_2 - type: b8 \ No newline at end of file + type: b8 diff --git a/selfdrive/locationd/glonass_fix.patch b/selfdrive/locationd/glonass_fix.patch index 2f99e93637..fa34a8ef15 100644 --- a/selfdrive/locationd/glonass_fix.patch +++ b/selfdrive/locationd/glonass_fix.patch @@ -1,5 +1,5 @@ diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp -index 6a48fe62c..149134fbb 100644 +index 5b17bc327..b5c6aa610 100644 --- a/selfdrive/locationd/generated/glonass.cpp +++ b/selfdrive/locationd/generated/glonass.cpp @@ -17,7 +17,7 @@ glonass_t::glonass_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, glonass diff --git a/selfdrive/locationd/test/test_glonass_kaitai.cc b/selfdrive/locationd/test/test_glonass_kaitai.cc new file mode 100644 index 0000000000..22f5202a3d --- /dev/null +++ b/selfdrive/locationd/test/test_glonass_kaitai.cc @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include + +#include "catch2/catch.hpp" +#include "selfdrive/locationd/generated/glonass.h" + +typedef std::vector> string_data; + +#define IDLE_CHIP_IDX 0 +#define STRING_NUMBER_IDX 1 +// string data 1-5 +#define HC_IDX 0 +#define PAD1_IDX 1 +#define SUPERFRAME_IDX 2 +#define PAD2_IDX 3 +#define FRAME_IDX 4 + +// Indexes for string number 1 +#define ST1_NU_IDX 2 +#define ST1_P1_IDX 3 +#define ST1_T_K_IDX 4 +#define ST1_X_VEL_S_IDX 5 +#define ST1_X_VEL_V_IDX 6 +#define ST1_X_ACCEL_S_IDX 7 +#define ST1_X_ACCEL_V_IDX 8 +#define ST1_X_S_IDX 9 +#define ST1_X_V_IDX 10 +#define ST1_HC_OFF 11 + +// Indexes for string number 2 +#define ST2_BN_IDX 2 +#define ST2_P2_IDX 3 +#define ST2_TB_IDX 4 +#define ST2_NU_IDX 5 +#define ST2_Y_VEL_S_IDX 6 +#define ST2_Y_VEL_V_IDX 7 +#define ST2_Y_ACCEL_S_IDX 8 +#define ST2_Y_ACCEL_V_IDX 9 +#define ST2_Y_S_IDX 10 +#define ST2_Y_V_IDX 11 +#define ST2_HC_OFF 12 + +// Indexes for string number 3 +#define ST3_P3_IDX 2 +#define ST3_GAMMA_N_S_IDX 3 +#define ST3_GAMMA_N_V_IDX 4 +#define ST3_NU_1_IDX 5 +#define ST3_P_IDX 6 +#define ST3_L_N_IDX 7 +#define ST3_Z_VEL_S_IDX 8 +#define ST3_Z_VEL_V_IDX 9 +#define ST3_Z_ACCEL_S_IDX 10 +#define ST3_Z_ACCEL_V_IDX 11 +#define ST3_Z_S_IDX 12 +#define ST3_Z_V_IDX 13 +#define ST3_HC_OFF 14 + +// Indexes for string number 4 +#define ST4_TAU_N_S_IDX 2 +#define ST4_TAU_N_V_IDX 3 +#define ST4_DELTA_TAU_N_S_IDX 4 +#define ST4_DELTA_TAU_N_V_IDX 5 +#define ST4_E_N_IDX 6 +#define ST4_NU_1_IDX 7 +#define ST4_P4_IDX 8 +#define ST4_F_T_IDX 9 +#define ST4_NU_2_IDX 10 +#define ST4_N_T_IDX 11 +#define ST4_N_IDX 12 +#define ST4_M_IDX 13 +#define ST4_HC_OFF 14 + +// Indexes for string number 5 +#define ST5_N_A_IDX 2 +#define ST5_TAU_C_IDX 3 +#define ST5_NU_IDX 4 +#define ST5_N_4_IDX 5 +#define ST5_TAU_GPS_IDX 6 +#define ST5_L_N_IDX 7 +#define ST5_HC_OFF 8 + +// Indexes for non immediate +#define ST6_DATA_1_IDX 2 +#define ST6_DATA_2_IDX 3 +#define ST6_HC_OFF 4 + + +std::string generate_inp_data(string_data& data) { + std::string inp_data = ""; + for (auto& [b, v] : data) { + std::string tmp = std::bitset<64>(v).to_string(); + inp_data += tmp.substr(64-b, b); + } + assert(inp_data.size() == 128); + + std::string string_data; + string_data.reserve(16); + for (int i = 0; i < 128; i+=8) { + std::string substr = inp_data.substr(i, 8); + string_data.push_back( (uint8_t)std::stoi(substr.c_str(), 0, 2)); + } + + return string_data; +} + +string_data generate_string_data(uint8_t string_number) { + + srand((unsigned)time(0)); + string_data data; // + data.push_back({1, 0}); // idle chip + data.push_back({4, string_number}); // string number + + if (string_number == 1) { + data.push_back({2, 3}); // not_used + data.push_back({2, 1}); // p1 + data.push_back({12, 113}); // t_k + data.push_back({1, rand() & 1}); // x_vel_sign + data.push_back({23, 7122}); // x_vel_value + data.push_back({1, rand() & 1}); // x_accel_sign + data.push_back({4, 3}); // x_accel_value + data.push_back({1, rand() & 1}); // x_sign + data.push_back({26, 33554431}); // x_value + } else if (string_number == 2) { + data.push_back({3, 3}); // b_n + data.push_back({1, 1}); // p2 + data.push_back({7, 123}); // t_b + data.push_back({5, 31}); // not_used + data.push_back({1, rand() & 1}); // y_vel_sign + data.push_back({23, 7422}); // y_vel_value + data.push_back({1, rand() & 1}); // y_accel_sign + data.push_back({4, 3}); // y_accel_value + data.push_back({1, rand() & 1}); // y_sign + data.push_back({26, 67108863}); // y_value + } else if (string_number == 3) { + data.push_back({1, 0}); // p3 + data.push_back({1, 1}); // gamma_n_sign + data.push_back({10, 123}); // gamma_n_value + data.push_back({1, 0}); // not_used + data.push_back({2, 2}); // p + data.push_back({1, 1}); // l_n + data.push_back({1, rand() & 1}); // z_vel_sign + data.push_back({23, 1337}); // z_vel_value + data.push_back({1, rand() & 1}); // z_accel_sign + data.push_back({4, 9}); // z_accel_value + data.push_back({1, rand() & 1}); // z_sign + data.push_back({26, 100023}); // z_value + } else if (string_number == 4) { + data.push_back({1, rand() & 1}); // tau_n_sign + data.push_back({21, 197152}); // tau_n_value + data.push_back({1, rand() & 1}); // delta_tau_n_sign + data.push_back({4, 4}); // delta_tau_n_value + data.push_back({5, 0}); // e_n + data.push_back({14, 2}); // not_used_1 + data.push_back({1, 1}); // p4 + data.push_back({4, 9}); // f_t + data.push_back({3, 3}); // not_used_2 + data.push_back({11, 2047}); // n_t + data.push_back({5, 2}); // n + data.push_back({2, 1}); // m + } else if (string_number == 5) { + data.push_back({11, 2047}); // n_a + data.push_back({32, 4294767295}); // tau_c + data.push_back({1, 0}); // not_used_1 + data.push_back({5, 2}); // n_4 + data.push_back({22, 4114304}); // tau_gps + data.push_back({1, 0}); // l_n + } else { // non-immediate data is not parsed + data.push_back({64, rand()}); // data_1 + data.push_back({8, 6}); // data_2 + } + + data.push_back({8, rand() & 0xFF}); // hamming code + data.push_back({11, rand() & 0x7FF}); // pad + data.push_back({16, rand() & 0xFFFF}); // superframe + data.push_back({8, rand() & 0xFF}); // pad + data.push_back({8, rand() & 0xFF}); // frame + return data; +} + +TEST_CASE("parse_string_number_1"){ + string_data data = generate_string_data(1); + std::string inp_data = generate_inp_data(data); + + kaitai::kstream stream(inp_data); + glonass_t gl_string(&stream); + + REQUIRE(gl_string.idle_chip() == data[IDLE_CHIP_IDX].second); + REQUIRE(gl_string.string_number() == data[STRING_NUMBER_IDX].second); + REQUIRE(gl_string.hamming_code() == data[ST1_HC_OFF + HC_IDX].second); + REQUIRE(gl_string.pad_1() == data[ST1_HC_OFF + PAD1_IDX].second); + REQUIRE(gl_string.superframe_number() == data[ST1_HC_OFF + SUPERFRAME_IDX].second); + REQUIRE(gl_string.pad_2() == data[ST1_HC_OFF + PAD2_IDX].second); + REQUIRE(gl_string.frame_number() == data[ST1_HC_OFF + FRAME_IDX].second); + + kaitai::kstream str1(inp_data); + glonass_t str1_data(&str1); + glonass_t::string_1_t* s1 = static_cast(str1_data.data()); + + REQUIRE(s1->not_used() == data[ST1_NU_IDX].second); + REQUIRE(s1->p1() == data[ST1_P1_IDX].second); + REQUIRE(s1->t_k() == data[ST1_T_K_IDX].second); + + int mul = s1->x_vel_sign() ? (-1) : 1; + REQUIRE(s1->x_vel() == (data[ST1_X_VEL_V_IDX].second * mul)); + mul = s1->x_accel_sign() ? (-1) : 1; + REQUIRE(s1->x_accel() == (data[ST1_X_ACCEL_V_IDX].second * mul)); + mul = s1->x_sign() ? (-1) : 1; + REQUIRE(s1->x() == (data[ST1_X_V_IDX].second * mul)); +} + +TEST_CASE("parse_string_number_2"){ + string_data data = generate_string_data(2); + std::string inp_data = generate_inp_data(data); + + kaitai::kstream stream(inp_data); + glonass_t gl_string(&stream); + + REQUIRE(gl_string.idle_chip() == data[IDLE_CHIP_IDX].second); + REQUIRE(gl_string.string_number() == data[STRING_NUMBER_IDX].second); + REQUIRE(gl_string.hamming_code() == data[ST2_HC_OFF + HC_IDX].second); + REQUIRE(gl_string.pad_1() == data[ST2_HC_OFF + PAD1_IDX].second); + REQUIRE(gl_string.superframe_number() == data[ST2_HC_OFF + SUPERFRAME_IDX].second); + REQUIRE(gl_string.pad_2() == data[ST2_HC_OFF + PAD2_IDX].second); + REQUIRE(gl_string.frame_number() == data[ST2_HC_OFF + FRAME_IDX].second); + + kaitai::kstream str2(inp_data); + glonass_t str2_data(&str2); + glonass_t::string_2_t* s2 = static_cast(str2_data.data()); + + REQUIRE(s2->b_n() == data[ST2_BN_IDX].second); + REQUIRE(s2->not_used() == data[ST2_NU_IDX].second); + REQUIRE(s2->p2() == data[ST2_P2_IDX].second); + REQUIRE(s2->t_b() == data[ST2_TB_IDX].second); + int mul = s2->y_vel_sign() ? (-1) : 1; + REQUIRE(s2->y_vel() == (data[ST2_Y_VEL_V_IDX].second * mul)); + mul = s2->y_accel_sign() ? (-1) : 1; + REQUIRE(s2->y_accel() == (data[ST2_Y_ACCEL_V_IDX].second * mul)); + mul = s2->y_sign() ? (-1) : 1; + REQUIRE(s2->y() == (data[ST2_Y_V_IDX].second * mul)); +} + +TEST_CASE("parse_string_number_3"){ + string_data data = generate_string_data(3); + std::string inp_data = generate_inp_data(data); + + kaitai::kstream stream(inp_data); + glonass_t gl_string(&stream); + + REQUIRE(gl_string.idle_chip() == data[IDLE_CHIP_IDX].second); + REQUIRE(gl_string.string_number() == data[STRING_NUMBER_IDX].second); + REQUIRE(gl_string.hamming_code() == data[ST3_HC_OFF + HC_IDX].second); + REQUIRE(gl_string.pad_1() == data[ST3_HC_OFF + PAD1_IDX].second); + REQUIRE(gl_string.superframe_number() == data[ST3_HC_OFF + SUPERFRAME_IDX].second); + REQUIRE(gl_string.pad_2() == data[ST3_HC_OFF + PAD2_IDX].second); + REQUIRE(gl_string.frame_number() == data[ST3_HC_OFF + FRAME_IDX].second); + + kaitai::kstream str3(inp_data); + glonass_t str3_data(&str3); + glonass_t::string_3_t* s3 = static_cast(str3_data.data()); + + REQUIRE(s3->p3() == data[ST3_P3_IDX].second); + int mul = s3->gamma_n_sign() ? (-1) : 1; + REQUIRE(s3->gamma_n() == (data[ST3_GAMMA_N_V_IDX].second * mul)); + REQUIRE(s3->not_used() == data[ST3_NU_1_IDX].second); + REQUIRE(s3->p() == data[ST3_P_IDX].second); + REQUIRE(s3->l_n() == data[ST3_L_N_IDX].second); + mul = s3->z_vel_sign() ? (-1) : 1; + REQUIRE(s3->z_vel() == (data[ST3_Z_VEL_V_IDX].second * mul)); + mul = s3->z_accel_sign() ? (-1) : 1; + REQUIRE(s3->z_accel() == (data[ST3_Z_ACCEL_V_IDX].second * mul)); + mul = s3->z_sign() ? (-1) : 1; + REQUIRE(s3->z() == (data[ST3_Z_V_IDX].second * mul)); +} + +TEST_CASE("parse_string_number_4"){ + string_data data = generate_string_data(4); + std::string inp_data = generate_inp_data(data); + + kaitai::kstream stream(inp_data); + glonass_t gl_string(&stream); + + REQUIRE(gl_string.idle_chip() == data[IDLE_CHIP_IDX].second); + REQUIRE(gl_string.string_number() == data[STRING_NUMBER_IDX].second); + REQUIRE(gl_string.hamming_code() == data[ST4_HC_OFF + HC_IDX].second); + REQUIRE(gl_string.pad_1() == data[ST4_HC_OFF + PAD1_IDX].second); + REQUIRE(gl_string.superframe_number() == data[ST4_HC_OFF + SUPERFRAME_IDX].second); + REQUIRE(gl_string.pad_2() == data[ST4_HC_OFF + PAD2_IDX].second); + REQUIRE(gl_string.frame_number() == data[ST4_HC_OFF + FRAME_IDX].second); + + kaitai::kstream str4(inp_data); + glonass_t str4_data(&str4); + glonass_t::string_4_t* s4 = static_cast(str4_data.data()); + + int mul = s4->tau_n_sign() ? (-1) : 1; + REQUIRE(s4->tau_n() == (data[ST4_TAU_N_V_IDX].second * mul)); + mul = s4->delta_tau_n_sign() ? (-1) : 1; + REQUIRE(s4->delta_tau_n() == (data[ST4_DELTA_TAU_N_V_IDX].second * mul)); + REQUIRE(s4->e_n() == data[ST4_E_N_IDX].second); + REQUIRE(s4->not_used_1() == data[ST4_NU_1_IDX].second); + REQUIRE(s4->p4() == data[ST4_P4_IDX].second); + REQUIRE(s4->f_t() == data[ST4_F_T_IDX].second); + REQUIRE(s4->not_used_2() == data[ST4_NU_2_IDX].second); + REQUIRE(s4->n_t() == data[ST4_N_T_IDX].second); + REQUIRE(s4->n() == data[ST4_N_IDX].second); + REQUIRE(s4->m() == data[ST4_M_IDX].second); +} + +TEST_CASE("parse_string_number_5"){ + string_data data = generate_string_data(5); + std::string inp_data = generate_inp_data(data); + + kaitai::kstream stream(inp_data); + glonass_t gl_string(&stream); + + REQUIRE(gl_string.idle_chip() == data[IDLE_CHIP_IDX].second); + REQUIRE(gl_string.string_number() == data[STRING_NUMBER_IDX].second); + REQUIRE(gl_string.hamming_code() == data[ST5_HC_OFF + HC_IDX].second); + REQUIRE(gl_string.pad_1() == data[ST5_HC_OFF + PAD1_IDX].second); + REQUIRE(gl_string.superframe_number() == data[ST5_HC_OFF + SUPERFRAME_IDX].second); + REQUIRE(gl_string.pad_2() == data[ST5_HC_OFF + PAD2_IDX].second); + REQUIRE(gl_string.frame_number() == data[ST5_HC_OFF + FRAME_IDX].second); + + kaitai::kstream str5(inp_data); + glonass_t str5_data(&str5); + glonass_t::string_5_t* s5 = static_cast(str5_data.data()); + + REQUIRE(s5->n_a() == data[ST5_N_A_IDX].second); + REQUIRE(s5->tau_c() == data[ST5_TAU_C_IDX].second); + REQUIRE(s5->not_used() == data[ST5_NU_IDX].second); + REQUIRE(s5->n_4() == data[ST5_N_4_IDX].second); + REQUIRE(s5->tau_gps() == data[ST5_TAU_GPS_IDX].second); + REQUIRE(s5->l_n() == data[ST5_L_N_IDX].second); +} + +TEST_CASE("parse_string_number_NI"){ + string_data data = generate_string_data((rand() % 10) + 6); + std::string inp_data = generate_inp_data(data); + + kaitai::kstream stream(inp_data); + glonass_t gl_string(&stream); + + REQUIRE(gl_string.idle_chip() == data[IDLE_CHIP_IDX].second); + REQUIRE(gl_string.string_number() == data[STRING_NUMBER_IDX].second); + REQUIRE(gl_string.hamming_code() == data[ST6_HC_OFF + HC_IDX].second); + REQUIRE(gl_string.pad_1() == data[ST6_HC_OFF + PAD1_IDX].second); + REQUIRE(gl_string.superframe_number() == data[ST6_HC_OFF + SUPERFRAME_IDX].second); + REQUIRE(gl_string.pad_2() == data[ST6_HC_OFF + PAD2_IDX].second); + REQUIRE(gl_string.frame_number() == data[ST6_HC_OFF + FRAME_IDX].second); + + kaitai::kstream strni(inp_data); + glonass_t strni_data(&strni); + glonass_t::string_non_immediate_t* sni = static_cast(strni_data.data()); + + REQUIRE(sni->data_1() == data[ST6_DATA_1_IDX].second); + REQUIRE(sni->data_2() == data[ST6_DATA_2_IDX].second); +} diff --git a/selfdrive/locationd/test/test_glonass_runner.cc b/selfdrive/locationd/test/test_glonass_runner.cc new file mode 100644 index 0000000000..62bf7476a1 --- /dev/null +++ b/selfdrive/locationd/test/test_glonass_runner.cc @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch2/catch.hpp" From 549e4d9636036af228d3d930d69e8dfd1f67dba6 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Mon, 30 Jan 2023 17:40:37 -0700 Subject: [PATCH 0777/1179] Ubloxd: move gps parsing to function (#27122) move ublox gps parsing to function Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/ublox_msg.cc | 212 ++++++++++++++++--------------- selfdrive/locationd/ublox_msg.h | 2 + 2 files changed, 111 insertions(+), 103 deletions(-) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 8bd9985170..4b31b0101e 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -147,125 +147,131 @@ kj::Array UbloxMsgParser::gen_nav_pvt(ubx_t::nav_pvt_t *msg) { return capnp::messageToFlatArray(msg_builder); } - -kj::Array UbloxMsgParser::gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg) { +kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg) { + // GPS subframes are packed into 10x 4 bytes, each containing 3 actual bytes + // We will first need to separate the data from the padding and parity auto body = *msg->body(); + assert(body.size() == 10); - if (msg->gnss_id() == ubx_t::gnss_type_t::GNSS_TYPE_GPS) { - // GPS subframes are packed into 10x 4 bytes, each containing 3 actual bytes - // We will first need to separate the data from the padding and parity - assert(body.size() == 10); + std::string subframe_data; + subframe_data.reserve(30); + for (uint32_t word : body) { + word = word >> 6; // TODO: Verify parity + subframe_data.push_back(word >> 16); + subframe_data.push_back(word >> 8); + subframe_data.push_back(word >> 0); + } - std::string subframe_data; - subframe_data.reserve(30); - for (uint32_t word : body) { - word = word >> 6; // TODO: Verify parity - subframe_data.push_back(word >> 16); - subframe_data.push_back(word >> 8); - subframe_data.push_back(word >> 0); + // Collect subframes in map and parse when we have all the parts + { + kaitai::kstream stream(subframe_data); + gps_t subframe(&stream); + int subframe_id = subframe.how()->subframe_id(); + int sv_id = msg->sv_id(); + uint64_t tow_counter = subframe.how()->tow_count(); + + bool clear_buffer = subframe_id == 1; + if (gps_sat_tow_count.count(sv_id) != 0) { + int64_t counter_diff = tow_counter - gps_sat_tow_count[sv_id]; + clear_buffer |= counter_diff != 1 && counter_diff != -100798; } + if (clear_buffer) gps_subframes[sv_id].clear(); - // Collect subframes in map and parse when we have all the parts + gps_subframes[sv_id][subframe_id] = subframe_data; + gps_sat_tow_count[sv_id] = tow_counter; + } + + if (gps_subframes[msg->sv_id()].size() == 5) { + MessageBuilder msg_builder; + auto eph = msg_builder.initEvent().initUbloxGnss().initEphemeris(); + eph.setSvId(msg->sv_id()); + + // Subframe 1 { - kaitai::kstream stream(subframe_data); + kaitai::kstream stream(gps_subframes[msg->sv_id()][1]); gps_t subframe(&stream); - int subframe_id = subframe.how()->subframe_id(); - int sv_id = msg->sv_id(); - uint64_t tow_counter = subframe.how()->tow_count(); + gps_t::subframe_1_t* subframe_1 = static_cast(subframe.body()); - bool clear_buffer = subframe_id == 1; - if (gps_sat_tow_count.count(sv_id) != 0) { - int64_t counter_diff = tow_counter - gps_sat_tow_count[sv_id]; - clear_buffer |= counter_diff != 1 && counter_diff != -100798; - } - if (clear_buffer) gps_subframes[sv_id].clear(); - - gps_subframes[sv_id][subframe_id] = subframe_data; - gps_sat_tow_count[sv_id] = tow_counter; + eph.setGpsWeek(subframe_1->week_no()); + eph.setTgd(subframe_1->t_gd() * pow(2, -31)); + eph.setToc(subframe_1->t_oc() * pow(2, 4)); + eph.setAf2(subframe_1->af_2() * pow(2, -55)); + eph.setAf1(subframe_1->af_1() * pow(2, -43)); + eph.setAf0(subframe_1->af_0() * pow(2, -31)); + eph.setSvHealth(subframe_1->sv_health()); } - if (gps_subframes[msg->sv_id()].size() == 5) { - MessageBuilder msg_builder; - auto eph = msg_builder.initEvent().initUbloxGnss().initEphemeris(); - eph.setSvId(msg->sv_id()); + // Subframe 2 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][2]); + gps_t subframe(&stream); + gps_t::subframe_2_t* subframe_2 = static_cast(subframe.body()); - // Subframe 1 - { - kaitai::kstream stream(gps_subframes[msg->sv_id()][1]); - gps_t subframe(&stream); - gps_t::subframe_1_t* subframe_1 = static_cast(subframe.body()); - - eph.setGpsWeek(subframe_1->week_no()); - eph.setTgd(subframe_1->t_gd() * pow(2, -31)); - eph.setToc(subframe_1->t_oc() * pow(2, 4)); - eph.setAf2(subframe_1->af_2() * pow(2, -55)); - eph.setAf1(subframe_1->af_1() * pow(2, -43)); - eph.setAf0(subframe_1->af_0() * pow(2, -31)); - eph.setSvHealth(subframe_1->sv_health()); - } - - // Subframe 2 - { - kaitai::kstream stream(gps_subframes[msg->sv_id()][2]); - gps_t subframe(&stream); - gps_t::subframe_2_t* subframe_2 = static_cast(subframe.body()); - - eph.setCrs(subframe_2->c_rs() * pow(2, -5)); - eph.setDeltaN(subframe_2->delta_n() * pow(2, -43) * gpsPi); - eph.setM0(subframe_2->m_0() * pow(2, -31) * gpsPi); - eph.setCuc(subframe_2->c_uc() * pow(2, -29)); - eph.setEcc(subframe_2->e() * pow(2, -33)); - eph.setCus(subframe_2->c_us() * pow(2, -29)); - eph.setA(pow(subframe_2->sqrt_a() * pow(2, -19), 2.0)); - eph.setToe(subframe_2->t_oe() * pow(2, 4)); - } - - // Subframe 3 - { - kaitai::kstream stream(gps_subframes[msg->sv_id()][3]); - gps_t subframe(&stream); - gps_t::subframe_3_t* subframe_3 = static_cast(subframe.body()); - - eph.setCic(subframe_3->c_ic() * pow(2, -29)); - eph.setOmega0(subframe_3->omega_0() * pow(2, -31) * gpsPi); - eph.setCis(subframe_3->c_is() * pow(2, -29)); - eph.setI0(subframe_3->i_0() * pow(2, -31) * gpsPi); - eph.setCrc(subframe_3->c_rc() * pow(2, -5)); - eph.setOmega(subframe_3->omega() * pow(2, -31) * gpsPi); - eph.setOmegaDot(subframe_3->omega_dot() * pow(2, -43) * gpsPi); - eph.setIode(subframe_3->iode()); - eph.setIDot(subframe_3->idot() * pow(2, -43) * gpsPi); - } - - // Subframe 4 - { - kaitai::kstream stream(gps_subframes[msg->sv_id()][4]); - gps_t subframe(&stream); - gps_t::subframe_4_t* subframe_4 = static_cast(subframe.body()); - - // This is page 18, why is the page id 56? - if (subframe_4->data_id() == 1 && subframe_4->page_id() == 56) { - auto iono = static_cast(subframe_4->body()); - double a0 = iono->a0() * pow(2, -30); - double a1 = iono->a1() * pow(2, -27); - double a2 = iono->a2() * pow(2, -24); - double a3 = iono->a3() * pow(2, -24); - eph.setIonoAlpha({a0, a1, a2, a3}); - - double b0 = iono->b0() * pow(2, 11); - double b1 = iono->b1() * pow(2, 14); - double b2 = iono->b2() * pow(2, 16); - double b3 = iono->b3() * pow(2, 16); - eph.setIonoBeta({b0, b1, b2, b3}); - } - } - - return capnp::messageToFlatArray(msg_builder); + eph.setCrs(subframe_2->c_rs() * pow(2, -5)); + eph.setDeltaN(subframe_2->delta_n() * pow(2, -43) * gpsPi); + eph.setM0(subframe_2->m_0() * pow(2, -31) * gpsPi); + eph.setCuc(subframe_2->c_uc() * pow(2, -29)); + eph.setEcc(subframe_2->e() * pow(2, -33)); + eph.setCus(subframe_2->c_us() * pow(2, -29)); + eph.setA(pow(subframe_2->sqrt_a() * pow(2, -19), 2.0)); + eph.setToe(subframe_2->t_oe() * pow(2, 4)); } + + // Subframe 3 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][3]); + gps_t subframe(&stream); + gps_t::subframe_3_t* subframe_3 = static_cast(subframe.body()); + + eph.setCic(subframe_3->c_ic() * pow(2, -29)); + eph.setOmega0(subframe_3->omega_0() * pow(2, -31) * gpsPi); + eph.setCis(subframe_3->c_is() * pow(2, -29)); + eph.setI0(subframe_3->i_0() * pow(2, -31) * gpsPi); + eph.setCrc(subframe_3->c_rc() * pow(2, -5)); + eph.setOmega(subframe_3->omega() * pow(2, -31) * gpsPi); + eph.setOmegaDot(subframe_3->omega_dot() * pow(2, -43) * gpsPi); + eph.setIode(subframe_3->iode()); + eph.setIDot(subframe_3->idot() * pow(2, -43) * gpsPi); + } + + // Subframe 4 + { + kaitai::kstream stream(gps_subframes[msg->sv_id()][4]); + gps_t subframe(&stream); + gps_t::subframe_4_t* subframe_4 = static_cast(subframe.body()); + + // This is page 18, why is the page id 56? + if (subframe_4->data_id() == 1 && subframe_4->page_id() == 56) { + auto iono = static_cast(subframe_4->body()); + double a0 = iono->a0() * pow(2, -30); + double a1 = iono->a1() * pow(2, -27); + double a2 = iono->a2() * pow(2, -24); + double a3 = iono->a3() * pow(2, -24); + eph.setIonoAlpha({a0, a1, a2, a3}); + + double b0 = iono->b0() * pow(2, 11); + double b1 = iono->b1() * pow(2, 14); + double b2 = iono->b2() * pow(2, 16); + double b3 = iono->b3() * pow(2, 16); + eph.setIonoBeta({b0, b1, b2, b3}); + } + } + + return capnp::messageToFlatArray(msg_builder); } return kj::Array(); } + +kj::Array UbloxMsgParser::gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg) { + switch (msg->gnss_id()) { + case ubx_t::gnss_type_t::GNSS_TYPE_GPS: + return parse_gps_ephemeris(msg); + default: + return kj::Array(); + } +} + kj::Array UbloxMsgParser::gen_rxm_rawx(ubx_t::rxm_rawx_t *msg) { MessageBuilder msg_builder; auto mr = msg_builder.initEvent().initUbloxGnss().initMeasurementReport(); diff --git a/selfdrive/locationd/ublox_msg.h b/selfdrive/locationd/ublox_msg.h index 919e9963f1..736e6d5171 100644 --- a/selfdrive/locationd/ublox_msg.h +++ b/selfdrive/locationd/ublox_msg.h @@ -102,6 +102,8 @@ class UbloxMsgParser { inline bool valid(); inline bool valid_so_far(); + kj::Array parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg); + std::unordered_map> gps_subframes; std::unordered_map gps_sat_tow_count; From feba2f3fe566114325f8c9119540fb19cf401a4a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 30 Jan 2023 17:41:42 -0800 Subject: [PATCH 0778/1179] fix micd input device (#27160) * try no device * unused * move sounddevice import --- system/micd.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/system/micd.py b/system/micd.py index a56140e3b9..97ba0c262e 100755 --- a/system/micd.py +++ b/system/micd.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import sounddevice as sd import numpy as np from cereal import messaging @@ -84,11 +83,11 @@ class Mic: self.measurements = self.measurements[FFT_SAMPLES:] - def micd_thread(self, device=None): - if device is None: - device = "sysdefault" + def micd_thread(self): + # sounddevice must be imported after forking processes + import sounddevice as sd # pylint: disable=import-outside-toplevel - with sd.InputStream(device=device, channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream: + with sd.InputStream(channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream: cloudlog.info(f"micd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}") while True: self.update() From f3a9dac93e0d1a9058e94d60b48ae5a189841d6c Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 31 Jan 2023 02:42:38 +0100 Subject: [PATCH 0779/1179] cabana: add --dbc command line argument (#27132) --- tools/cabana/cabana.cc | 7 +++++++ tools/cabana/mainwin.cc | 5 +++++ tools/cabana/mainwin.h | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index d9b6b5948b..e34e2d0205 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -24,6 +24,7 @@ int main(int argc, char *argv[]) { cmd_parser.addOption({"zmq", "the ip address on which to receive zmq messages", "zmq"}); cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"}); cmd_parser.addOption({"no-vipc", "do not output video"}); + cmd_parser.addOption({"dbc", "dbc file to open", "dbc"}); cmd_parser.process(app); const QStringList args = cmd_parser.positionalArguments(); if (args.empty() && !cmd_parser.isSet("demo") && !cmd_parser.isSet("stream")) { @@ -57,6 +58,12 @@ int main(int argc, char *argv[]) { } MainWindow w; + + // Load DBC + if (cmd_parser.isSet("dbc")) { + w.loadFile(cmd_parser.value("dbc")); + } + w.show(); return app.exec(); } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 3c2d46cbf2..94cf9840f7 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -243,6 +243,11 @@ void MainWindow::loadDBCFromClipboard() { } void MainWindow::loadDBCFromFingerprint() { + // Don't overwrite already loaded DBC + if (!dbc()->name().isEmpty()) { + return; + } + remindSaveChanges(); auto fingerprint = can->carFingerprint(); video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index ba36d676e0..c26f6973c0 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -20,6 +20,7 @@ public: MainWindow(); void dockCharts(bool dock); void showStatusMessage(const QString &msg, int timeout = 0) { statusBar()->showMessage(msg, timeout); } + void loadFile(const QString &fn); public slots: void newFile(); @@ -40,7 +41,6 @@ signals: protected: void remindSaveChanges(); void saveFile(const QString &fn); - void loadFile(const QString &fn); void setCurrentFile(const QString &fn); void updateRecentFileActions(); void createActions(); From ceceb1c6ccfec5a47b4a290ee6f81dc443ce79cc Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 31 Jan 2023 11:23:36 +0800 Subject: [PATCH 0780/1179] replay: fix hang if started with a special segment and there is no INIT_DATA in events (#27107) * add events if allow or block is specified * add init_data --- tools/replay/replay.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 998c93b938..5c90777bbc 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -25,6 +25,13 @@ Replay::Replay(QString route, QStringList allow, QStringList block, SubMaster *s s.push_back(it.name); } } + + if (!allow_list.empty()) { + // the following events are needed for replay to work properly. + allow_list.insert(cereal::Event::Which::INIT_DATA); + allow_list.insert(cereal::Event::Which::CAR_PARAMS); + } + qDebug() << "services " << s; qDebug() << "loading route " << route; From ef9deeb6eba3823982dadd485a3676441320226b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 30 Jan 2023 22:37:54 -0800 Subject: [PATCH 0781/1179] Ford longitudinal control (#27161) ford long --- selfdrive/car/ford/carcontroller.py | 19 ++++++++++++++++++- selfdrive/car/ford/fordcan.py | 20 ++++++++++++++++++++ selfdrive/car/ford/values.py | 5 +++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 06da87bf34..cfff37f6d5 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -2,7 +2,8 @@ from cereal import car from common.numpy_fast import clip from opendbc.can.packer import CANPacker from selfdrive.car import apply_std_steer_angle_limits -from selfdrive.car.ford.fordcan import create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, create_lka_msg, create_lkas_ui_msg +from selfdrive.car.ford.fordcan import create_acc_command, create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, \ + create_lka_msg, create_lkas_ui_msg from selfdrive.car.ford.values import CANBUS, CarControllerParams VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -55,6 +56,22 @@ class CarController: can_sends.append(create_lka_msg(self.packer)) can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.)) + ### longitudinal control ### + # send acc command at 50Hz + if self.CP.openpilotLongitudinalControl and (self.frame % CarControllerParams.ACC_CONTROL_STEP) == 0: + accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX) + + precharge_brake = accel < -0.1 + if accel > -0.5: + gas = accel + decel = False + else: + gas = -5.0 + decel = True + + can_sends.append(create_acc_command(self.packer, CC.longActive, gas, accel, precharge_brake, decel)) + + ### ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index 9ddde80f87..d9c37426f8 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -55,6 +55,26 @@ def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: return packer.make_can_msg("LateralMotionControl", CANBUS.main, values) +def create_acc_command(packer, long_active: bool, gas: float, accel: float, precharge_brake: bool, decel: bool): + """ + Creates a CAN message for the Ford ACC Command. + + This command can be used to enable ACC, to set the ACC gas/brake/decel values + and to disable ACC. + + Frequency is 50Hz. + """ + + values = { + "AccBrkTot_A_Rq": accel, # Brake total accel request: [-20|11.9449] m/s^2 + "Cmbb_B_Enbl": 1 if long_active else 0, # Enabled: 0=No, 1=Yes + "AccPrpl_A_Rq": gas, # Acceleration request: [-5|5.23] m/s^2 + "AccBrkPrchg_B_Rq": 1 if precharge_brake else 0, # Pre-charge brake request: 0=No, 1=Yes + "AccBrkDecel_B_Rq": 1 if decel else 0, # Deceleration request: 0=Inactive, 1=Active + } + return packer.make_can_msg("ACCDATA", CANBUS.main, values) + + def create_lkas_ui_msg(packer, main_on: bool, enabled: bool, steer_alert: bool, hud_control, stock_values: dict): """ Creates a CAN message for the Ford IPC IPMA/LKAS status. diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index b93be61448..7b075f1547 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -14,6 +14,8 @@ Ecu = car.CarParams.Ecu class CarControllerParams: # Messages: Lane_Assist_Data1, LateralMotionControl STEER_STEP = 5 + # Message: ACCDATA + ACC_CONTROL_STEP = 2 # Message: IPMA_Data LKAS_UI_STEP = 100 # Message: ACCDATA_3 @@ -29,6 +31,9 @@ class CarControllerParams: ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.005, 0.00056, 0.0002]) ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.008, 0.00089, 0.00032]) + ACCEL_MAX = 2.0 # m/s^s max acceleration + ACCEL_MIN = -3.5 # m/s^s max deceleration + def __init__(self, CP): pass From 4c2f8edb7783f4b5797c02f1bdc2008fbaf4e0c7 Mon Sep 17 00:00:00 2001 From: Anthony Rose <20302208+Cx01N@users.noreply.github.com> Date: Tue, 31 Jan 2023 02:23:45 -0500 Subject: [PATCH 0782/1179] Add Hyundai Ioniq 5 Fingerprint (#27137) * added 2022 ioniq 5 fingerprint * removed extra eps field * fixed eps value * removed cornerradar * Apply suggestions from code review --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index c0cf23b50d..4e3dd484c8 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1493,6 +1493,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', + b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', ], }, CAR.TUCSON_4TH_GEN: { From 09cd0b4900d8aff1c9484c8848c9b5f7ff269594 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 31 Jan 2023 01:09:36 -0800 Subject: [PATCH 0783/1179] GM camera ACC: reliable relay open init (#27163) Reliable relay open --- selfdrive/car/gm/carcontroller.py | 2 +- selfdrive/car/gm/carstate.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index b4a79d10a6..c5aae34249 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -63,7 +63,7 @@ class CarController: elif (self.frame - self.last_steer_frame) >= steer_step: # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus if init_lka_counter: - self.lka_steering_cmd_counter = CS.camera_lka_steering_cmd_counter + 1 + self.lka_steering_cmd_counter = CS.pt_lka_steering_cmd_counter + 1 if CC.latActive: new_steer = int(round(actuators.steer * self.params.STEER_MAX)) diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index de0fd2eed6..cf6d2817ec 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -18,7 +18,7 @@ class CarState(CarStateBase): can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] self.loopback_lka_steering_cmd_updated = False - self.camera_lka_steering_cmd_counter = 0 + self.pt_lka_steering_cmd_counter = 0 self.buttons_counter = 0 def update(self, pt_cp, cam_cp, loopback_cp): @@ -33,7 +33,7 @@ class CarState(CarStateBase): # Variables used for avoiding LKAS faults self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 if self.CP.networkLocation == NetworkLocation.fwdCamera: - self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] + self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] ret.wheelSpeeds = self.get_wheel_speeds( pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"], @@ -113,13 +113,11 @@ class CarState(CarStateBase): if CP.networkLocation == NetworkLocation.fwdCamera: signals += [ ("AEBCmdActive", "AEBCmd"), - ("RollingCounter", "ASCMLKASteeringCmd"), ("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"), ("ACCCruiseState", "ASCMActiveCruiseControlStatus"), ] checks += [ ("AEBCmd", 10), - ("ASCMLKASteeringCmd", 10), ("ASCMActiveCruiseControlStatus", 25), ] @@ -180,6 +178,15 @@ class CarState(CarStateBase): ("ECMAcceleratorPos", 80), ] + # Used to read back last counter sent to PT by camera + if CP.networkLocation == NetworkLocation.fwdCamera: + signals += [ + ("RollingCounter", "ASCMLKASteeringCmd"), + ] + checks += [ + ("ASCMLKASteeringCmd", 0), + ] + if CP.transmissionType == TransmissionType.direct: signals.append(("RegenPaddle", "EBCMRegenPaddle")) checks.append(("EBCMRegenPaddle", 50)) From f17bca00ba6919bae309f0c68bad11b0f6b18607 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 31 Jan 2023 17:17:21 +0100 Subject: [PATCH 0784/1179] panda.cc: fix possible heap overflow on wrong checksum (#27151) * panda.cc: fix possible heap overflow on wrong checksum * off by one --- selfdrive/boardd/panda.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 4bba070eee..647a0d9c78 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -236,6 +236,9 @@ void Panda::can_send(capnp::List::Reader can_data_list) { } bool Panda::can_receive(std::vector& out_vec) { + // Check if enough space left in buffer to store RECV_SIZE data + assert(receive_buffer_size + RECV_SIZE <= sizeof(receive_buffer)); + int recv = handle->bulk_read(0x81, &receive_buffer[receive_buffer_size], RECV_SIZE); if (!comms_healthy()) { return false; @@ -278,6 +281,7 @@ bool Panda::unpack_can_buffer(uint8_t *data, uint32_t &size, std::vector Date: Tue, 31 Jan 2023 13:47:41 -0500 Subject: [PATCH 0785/1179] VW MQB: Add FW for 2016 SEAT Leon (#27168) --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index bdb43c542a..5f0913e880 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -942,16 +942,19 @@ FW_VERSIONS = { b'\xf1\x8704L906021EL\xf1\x897542', b'\xf1\x8704L906026BP\xf1\x891198', b'\xf1\x8704L906026BP\xf1\x897608', + b'\xf1\x8704L906056CR\xf1\x892797', b'\xf1\x8705E906018AS\xf1\x899596', b'\xf1\x878V0906264H \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870CW300041D \xf1\x891004', b'\xf1\x870CW300041G \xf1\x891003', b'\xf1\x870CW300050J \xf1\x891908', b'\xf1\x870D9300042M \xf1\x895016', ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AC\xf1\x890189\xf1\x82\r11110011110011021511110200', + b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r11110011110011021511110200', b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r12110012120012021612110200', b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\x0e1312001313001305171311052900', b'\xf1\x873Q0959655CM\xf1\x890720\xf1\x82\0161312001313001305171311052900', @@ -965,6 +968,7 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x875Q0907572B \xf1\x890200\xf1\x82\00101', b'\xf1\x875Q0907572H \xf1\x890620', + b'\xf1\x875Q0907572K \xf1\x890402\xf1\x82\x0101', b'\xf1\x875Q0907572P \xf1\x890682', ], }, From 5ce7572b46dcd2b32f11967cc559402eab2ab5ca Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 31 Jan 2023 14:00:10 -0500 Subject: [PATCH 0786/1179] VW MNB: Volkswagen Crafter Mk2 (#26006) * VW MNB: Volkswagen Crafter Mk2 * Crafter has a min steer speed :( * add to non_tested_cars for now * autogratitude * Revert "autogratitude" This reverts commit 8f19085bfa3424a8a75d7c95f32be8ecb010f8f4. * autogratitude * regen docs --- RELEASES.md | 1 + docs/CARS.md | 7 +++++- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + selfdrive/car/volkswagen/interface.py | 5 +++++ selfdrive/car/volkswagen/values.py | 27 ++++++++++++++++++++++- 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 1b5ef8f7a7..ddb4a036b0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,6 +8,7 @@ Version 0.9.1 (2022-12-XX) * Hyundai Tucson 2022-23 support * Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! +* Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607! Version 0.9.0 (2022-11-21) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index 390d2bf349..3a102795c4 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 224 Supported Cars +# 229 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -135,6 +135,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|| |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B|| @@ -209,6 +211,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| @@ -217,6 +221,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Passat 2015-22[8](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index d1b73afcf6..bcdb00fd60 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -26,6 +26,7 @@ non_tested_cars = [ HYUNDAI.GENESIS_G90, HYUNDAI.KIA_OPTIMA_H, HONDA.ODYSSEY_CHN, + VOLKSWAGEN.CRAFTER_MK2, # need a route from an ACC-equipped Crafter ] CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,)) diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index aeb2e6f280..56057dfae0 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -59,6 +59,7 @@ SKODA SCALA 1ST GEN: SKODA SUPERB 3RD GEN SKODA KODIAQ 1ST GEN: SKODA SUPERB 3RD GEN SKODA KAROQ 1ST GEN: SKODA SUPERB 3RD GEN SKODA KAMIQ 1ST GEN: SKODA SUPERB 3RD GEN +VOLKSWAGEN CRAFTER 2ND GEN: VOLKSWAGEN TIGUAN 2ND GEN VOLKSWAGEN T-ROC 1ST GEN: VOLKSWAGEN TIGUAN 2ND GEN VOLKSWAGEN T-CROSS 1ST GEN: VOLKSWAGEN TIGUAN 2ND GEN VOLKSWAGEN TOURAN 2ND GEN: VOLKSWAGEN TIGUAN 2ND GEN diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index da0ce25afa..b979a96d70 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -107,6 +107,11 @@ class CarInterface(CarInterfaceBase): ret.mass = 2011 + STD_CARGO_KG ret.wheelbase = 2.98 + elif candidate == CAR.CRAFTER_MK2: + ret.mass = 2100 + STD_CARGO_KG + ret.wheelbase = 3.64 # SWB, LWB is 4.49, TBD how to detect difference + ret.minSteerSpeed = 50 * CV.KPH_TO_MS + elif candidate == CAR.GOLF_MK7: ret.mass = 1397 + STD_CARGO_KG ret.wheelbase = 2.62 diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 5f0913e880..9f6dee2689 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -111,6 +111,7 @@ class CANBUS: class CAR: ARTEON_MK1 = "VOLKSWAGEN ARTEON 1ST GEN" # Chassis AN, Mk1 VW Arteon and variants ATLAS_MK1 = "VOLKSWAGEN ATLAS 1ST GEN" # Chassis CA, Mk1 VW Atlas and Atlas Cross Sport + CRAFTER_MK2 = "VOLKSWAGEN CRAFTER 2ND GEN" # Chassis SY/SZ, Mk2 VW Crafter, VW Grand California, MAN TGE GOLF_MK7 = "VOLKSWAGEN GOLF 7TH GEN" # Chassis 5G/AU/BA/BE, Mk7 VW Golf and variants JETTA_MK7 = "VOLKSWAGEN JETTA 7TH GEN" # Chassis BU, Mk7 VW Jetta PASSAT_MK8 = "VOLKSWAGEN PASSAT 8TH GEN" # Chassis 3G, Mk8 VW Passat and variants @@ -122,7 +123,7 @@ class CAR: TIGUAN_MK2 = "VOLKSWAGEN TIGUAN 2ND GEN" # Chassis AD/BW, Mk2 VW Tiguan and variants TOURAN_MK2 = "VOLKSWAGEN TOURAN 2ND GEN" # Chassis 1T, Mk2 VW Touran and variants TRANSPORTER_T61 = "VOLKSWAGEN TRANSPORTER T6.1" # Chassis 7H/7L, T6-facelift Transporter/Multivan/Caravelle/California - TROC_MK1 = "VOLKSWAGEN T-ROC 1ST GEN" # Chassis A1, Mk1 VW VW T-Roc and variants + TROC_MK1 = "VOLKSWAGEN T-ROC 1ST GEN" # Chassis A1, Mk1 VW T-Roc and variants AUDI_A3_MK3 = "AUDI A3 3RD GEN" # Chassis 8V/FF, Mk3 Audi A3 and variants AUDI_Q2_MK1 = "AUDI Q2 1ST GEN" # Chassis GA, Mk1 Audi Q2 (RoW) and Q2L (China only) AUDI_Q3_MK2 = "AUDI Q3 2ND GEN" # Chassis 8U/F3/FS, Mk2 Audi Q3 and variants @@ -184,6 +185,13 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { VWCarInfo("Volkswagen Teramont Cross Sport 2021-22"), VWCarInfo("Volkswagen Teramont X 2021-22"), ], + CAR.CRAFTER_MK2: [ + VWCarInfo("Volkswagen Crafter 2017-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarInfo("Volkswagen e-Crafter 2018-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarInfo("Volkswagen Grand California 2019-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarInfo("MAN TGE 2017-23", video_link="https://youtu.be/4100gLeabmo"), + VWCarInfo("MAN eTGE 2020-23", video_link="https://youtu.be/4100gLeabmo"), + ], CAR.GOLF_MK7: [ VWCarInfo("Volkswagen e-Golf 2014-20"), VWCarInfo("Volkswagen Golf 2015-20"), @@ -352,6 +360,23 @@ FW_VERSIONS = { b'\xf1\x875Q0907572P \xf1\x890682', ], }, + CAR.CRAFTER_MK2: { + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8704L906056EK\xf1\x896391', + ], + # Only current upstreamed vehicle has a manual transmission + #(Ecu.transmission, 0x7e1, None): [ + #], + (Ecu.srs, 0x715, None): [ + b'\xf1\x873Q0959655BG\xf1\x890703\xf1\x82\x0e16120016130012051G1313052900', + ], + (Ecu.eps, 0x712, None): [ + b'\xf1\x872N0909143E \xf1\x897021\xf1\x82\x05163AZ306A2', + ], + (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x872Q0907572M \xf1\x890233', + ], + }, CAR.GOLF_MK7: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906016A \xf1\x897697', From df5ccda7315e7767465c61ebdee5e9cb30832bc9 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Tue, 31 Jan 2023 11:06:03 -0800 Subject: [PATCH 0787/1179] Ford CAN FD (#27166) * add LateralMotionControl2 message * send LatCtl2 message on CAN FD cars --- selfdrive/car/ford/carcontroller.py | 14 ++++++--- selfdrive/car/ford/fordcan.py | 44 ++++++++++++++++++++++++++++- selfdrive/car/ford/values.py | 5 +++- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index cfff37f6d5..00fb461223 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -3,8 +3,8 @@ from common.numpy_fast import clip from opendbc.can.packer import CANPacker from selfdrive.car import apply_std_steer_angle_limits from selfdrive.car.ford.fordcan import create_acc_command, create_acc_ui_msg, create_button_msg, create_lat_ctl_msg, \ - create_lka_msg, create_lkas_ui_msg -from selfdrive.car.ford.values import CANBUS, CarControllerParams + create_lat_ctl2_msg, create_lka_msg, create_lkas_ui_msg +from selfdrive.car.ford.values import CANBUS, CANFD_CARS, CarControllerParams VisualAlert = car.CarControl.HUDControl.VisualAlert @@ -54,7 +54,14 @@ class CarController: self.apply_curvature_last = apply_curvature can_sends.append(create_lka_msg(self.packer)) - can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.)) + + if self.CP.carFingerprint in CANFD_CARS: + # TODO: extended mode + mode = 1 if CC.latActive else 0 + counter = self.frame // CarControllerParams.STEER_STEP + can_sends.append(create_lat_ctl2_msg(self.packer, mode, 0., 0., -apply_curvature, 0., counter)) + else: + can_sends.append(create_lat_ctl_msg(self.packer, CC.latActive, 0., 0., -apply_curvature, 0.)) ### longitudinal control ### # send acc command at 50Hz @@ -71,7 +78,6 @@ class CarController: can_sends.append(create_acc_command(self.packer, CC.longActive, gas, accel, precharge_brake, decel)) - ### ui ### send_ui = (self.main_on_last != main_on) or (self.lkas_enabled_last != CC.latActive) or (self.steer_alert_last != steer_alert) diff --git a/selfdrive/car/ford/fordcan.py b/selfdrive/car/ford/fordcan.py index d9c37426f8..594d50f59f 100644 --- a/selfdrive/car/ford/fordcan.py +++ b/selfdrive/car/ford/fordcan.py @@ -4,6 +4,15 @@ from selfdrive.car.ford.values import CANBUS HUDControl = car.CarControl.HUDControl +def calculate_lat_ctl2_checksum(mode: int, counter: int, dat: bytearray): + checksum = mode + counter + checksum += dat[2] + ((dat[3] & 0xE0) >> 5) # curvature + checksum += dat[6] + ((dat[7] & 0xE0) >> 5) # curvature rate + checksum += (dat[3] & 0x1F) + ((dat[4] & 0xFC) >> 2) # path angle + checksum += (dat[4] & 0x3) + dat[5] # path offset + return 0xFF - (checksum & 0xFF) + + def create_lka_msg(packer): """ Creates an empty CAN message for the Ford LKA Command. @@ -16,7 +25,8 @@ def create_lka_msg(packer): return packer.make_can_msg("Lane_Assist_Data1", CANBUS.main, {}) -def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float, curvature_rate: float): +def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: float, curvature: float, + curvature_rate: float): """ Creates a CAN message for the Ford TJA/LCA Command. @@ -55,6 +65,38 @@ def create_lat_ctl_msg(packer, lat_active: bool, path_offset: float, path_angle: return packer.make_can_msg("LateralMotionControl", CANBUS.main, values) +def create_lat_ctl2_msg(packer, mode: int, path_offset: float, path_angle: float, curvature: float, + curvature_rate: float, counter: int): + """ + Create a CAN message for the new Ford Lane Centering command. + + This message is used on the CAN FD platform and replaces the old LateralMotionControl message. It is similar but has + additional signals for a counter and checksum. + + Frequency is 20Hz. + """ + + values = { + "LatCtl_D2_Rq": mode, # Mode: 0=None, 1=PathFollowingLimitedMode, 2=PathFollowingExtendedMode, + # 3=SafeRampOut, 4-7=NotUsed [0|7] + "LatCtlRampType_D_Rq": 0, # 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3] + "LatCtlPrecision_D_Rq": 1, # 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3] + "LatCtlPathOffst_L_Actl": path_offset, # [-5.12|5.11] meter + "LatCtlPath_An_Actl": path_angle, # [-0.5|0.5235] radians + "LatCtlCurv_No_Actl": curvature, # [-0.02|0.02094] 1/meter + "LatCtlCrv_NoRate2_Actl": curvature_rate, # [-0.001024|0.001023] 1/meter^2 + "HandsOffCnfm_B_Rq": 0, # 0=Inactive, 1=Active [0|1] + "LatCtlPath_No_Cnt": counter, # [0|15] + "LatCtlPath_No_Cs": 0, # [0|255] + } + + # calculate checksum + dat = packer.make_can_msg("LateralMotionControl2", CANBUS.main, values)[2] + values["LatCtlPath_No_Cs"] = calculate_lat_ctl2_checksum(mode, counter, dat) + + return packer.make_can_msg("LateralMotionControl2", CANBUS.main, values) + + def create_acc_command(packer, long_active: bool, gas: float, accel: float, precharge_brake: bool, decel: bool): """ Creates a CAN message for the Ford ACC Command. diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 7b075f1547..4cabdb11e1 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -1,7 +1,7 @@ from collections import defaultdict from dataclasses import dataclass from enum import Enum -from typing import Dict, List, Union +from typing import Dict, List, Set, Union from cereal import car from selfdrive.car import AngleRateLimit, dbc_dict @@ -52,6 +52,9 @@ class CAR: MAVERICK_MK1 = "FORD MAVERICK 1ST GEN" +CANFD_CARS: Set[str] = set() + + class RADAR: DELPHI_ESR = 'ford_fusion_2018_adas' DELPHI_MRR = 'FORD_CADS' From cf943940269ec1e400f820d869aabc45e1c472bb Mon Sep 17 00:00:00 2001 From: Sean Cox Date: Tue, 31 Jan 2023 15:02:05 -0500 Subject: [PATCH 0788/1179] Fix 2017 Genesis G80 car harness and shop link in docs (#27127) * Fix 2017 Genesis G80 car harness * Revert "Fix 2017 Genesis G80 car harness" This reverts commit 2d5a92b7f0972c7ab61b132dce6cfebe978781c9. * split and make G80 2017 have J harness * generate and change min enable speed * adjust min steer speed --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 5 +++-- selfdrive/car/hyundai/values.py | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 3a102795c4..f4ad4b75fa 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 229 Supported Cars +# 230 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -30,7 +30,8 @@ A supported vehicle is one that just works when you install a comma three. All s |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|| |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| |Genesis|G70 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| -|Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|| +|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Genesis|G90 2017-18|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| |Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4e3dd484c8..691b52c936 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -232,7 +232,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f), CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l), - CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2017-19", "All", harness=Harness.hyundai_h), + CAR.GENESIS_G80: [ + HyundaiCarInfo("Genesis G80 2017", "All", min_steer_speed=37 * CV.MPH_TO_MS, min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), + HyundaiCarInfo("Genesis G80 2018-19", "All", harness=Harness.hyundai_h), + ], CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness=Harness.hyundai_c), } From f1caecff727fe4d53edc131b30b7a31c1fb4736c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 31 Jan 2023 12:48:13 -0800 Subject: [PATCH 0789/1179] Genesis G80 2017: group with Hyundai Genesis (#27170) * Revert "Fix 2017 Genesis G80 car harness and shop link in docs (#27127)" This reverts commit cf943940269ec1e400f820d869aabc45e1c472bb. * The HGenesis became rebranded to G80 in 2017 (2018 model year). G80 2017 fingerprints as Hyundai Genesis, and we handle the min steer speed correctly https://en.wikipedia.org/wiki/Genesis_G80 https://en.wikipedia.org/wiki/Hyundai_Genesis * fix --- selfdrive/car/hyundai/values.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 691b52c936..1be612ad74 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -147,7 +147,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { ], CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c", harness=Harness.hyundai_k), - CAR.HYUNDAI_GENESIS: HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages + CAR.HYUNDAI_GENESIS: [ + HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), # TODO: check 2015 packages + HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), + ], CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", harness=Harness.hyundai_c), CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", harness=Harness.hyundai_h), # TODO: confirm 2020-21 harness CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", harness=Harness.hyundai_c), @@ -232,10 +235,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", harness=Harness.hyundai_f), CAR.GENESIS_GV70_1ST_GEN: HyundaiCarInfo("Genesis GV70 2022-23", "All", harness=Harness.hyundai_l), - CAR.GENESIS_G80: [ - HyundaiCarInfo("Genesis G80 2017", "All", min_steer_speed=37 * CV.MPH_TO_MS, min_enable_speed=19 * CV.MPH_TO_MS, harness=Harness.hyundai_j), - HyundaiCarInfo("Genesis G80 2018-19", "All", harness=Harness.hyundai_h), - ], + CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", harness=Harness.hyundai_h), CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", harness=Harness.hyundai_c), } From 49e955d321aff222665ac89b62d9de0b5d8395d2 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 31 Jan 2023 22:08:07 +0100 Subject: [PATCH 0790/1179] cabana: dynamically switch between OpenGL (#27167) * cabana: dynamically switch between OpenGL * put back todo * only switch when x axis changes --- tools/cabana/chartswidget.cc | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 2edc89d857..923b6bbb59 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -358,11 +358,6 @@ void ChartView::setPlotAreaLeftPosition(int pos) { void ChartView::addSeries(const QString &msg_id, const Signal *sig) { QLineSeries *series = new QLineSeries(this); - // TODO: Due to a bug in CameraWidget the camera frames - // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed -#ifndef __APPLE__ - series->setUseOpenGL(true); -#endif chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); @@ -476,17 +471,32 @@ void ChartView::updatePlot(double cur, double min, double max) { if (min != axis_x->min() || max != axis_x->max()) { axis_x->setRange(min, max); updateAxisY(); - } - // Show points when zoomed in enough - 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; }); - auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + // Show points when zoomed in enough + 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; }); + auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); - int num_points = std::max(end - begin, 1); - int pixels_per_point = width() / num_points; + int num_points = std::max(end - begin, 1); + int pixels_per_point = width() / num_points; - s.series->setPointsVisible(pixels_per_point > 20); + s.series->setPointsVisible(pixels_per_point > 20); + + // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs. +#ifndef __APPLE + // OpenGL mode lacks certain features (such as showing points), only use when drawing many points + bool use_opengl = pixels_per_point < 1; + s.series->setUseOpenGL(use_opengl); + + // Qt doesn't properly apply device pixel ratio in OpenGL mode + QApplication* application = static_cast(QApplication::instance()); + float scale = use_opengl ? application->devicePixelRatio() : 1.0; + + QPen pen = s.series->pen(); + pen.setWidth(2.0 * scale); + s.series->setPen(pen); +#endif + } } scene()->invalidate({}, QGraphicsScene::ForegroundLayer); From 0402e949270219bfbd964d38916ed52917090169 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 1 Feb 2023 05:45:57 +0800 Subject: [PATCH 0791/1179] cabana: render light or dark icon based on system theme (#27155) --- tools/cabana/chartswidget.cc | 14 ++++++-------- tools/cabana/detailwidget.cc | 11 +++++------ tools/cabana/signaledit.cc | 8 +++----- tools/cabana/util.cc | 17 +++++++++++++++++ tools/cabana/util.h | 4 ++++ tools/cabana/videowidget.cc | 4 +--- 6 files changed, 36 insertions(+), 22 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 923b6bbb59..47fc5dc03b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -13,8 +13,6 @@ #include #include -#include "selfdrive/ui/qt/util.h" - // ChartsWidget ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { @@ -24,7 +22,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QToolBar *toolbar = new QToolBar(tr("Charts"), this); toolbar->setIconSize({16, 16}); - QAction *new_plot_btn = toolbar->addAction(bootstrapPixmap("file-plus"), ""); + QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), ""); new_plot_btn->setToolTip(tr("New Plot")); toolbar->addWidget(title_label = new QLabel()); title_label->setContentsMargins(0, 0, 12, 0); @@ -46,9 +44,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { range_slider->setPageStep(60); // 1 min toolbar->addWidget(range_slider); - reset_zoom_btn = toolbar->addAction(bootstrapPixmap("zoom-out"), ""); + reset_zoom_btn = toolbar->addAction(utils::icon("zoom-out"), ""); reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); - remove_all_btn = toolbar->addAction(bootstrapPixmap("x"), ""); + remove_all_btn = toolbar->addAction(utils::icon("x"), ""); remove_all_btn->setToolTip(tr("Remove all charts")); dock_btn = toolbar->addAction(""); main_layout->addWidget(toolbar); @@ -170,7 +168,7 @@ void ChartsWidget::setMaxChartRange(int value) { void ChartsWidget::updateToolBar() { range_lb->setText(QString(" %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); title_label->setText(tr("Charts: %1").arg(charts.size())); - dock_btn->setIcon(bootstrapPixmap(docking ? "arrow-up-right" : "arrow-down-left")); + dock_btn->setIcon(utils::icon(docking ? "arrow-up-right" : "arrow-down-left")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); remove_all_btn->setEnabled(!charts.isEmpty()); reset_zoom_btn->setEnabled(is_zoomed); @@ -311,7 +309,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->setMargins({20, 11, 11, 11}); QToolButton *remove_btn = new QToolButton(); - remove_btn->setIcon(bootstrapPixmap("x")); + remove_btn->setIcon(utils::icon("x")); remove_btn->setAutoRaise(true); remove_btn->setToolTip(tr("Remove Chart")); close_btn_proxy = new QGraphicsProxyWidget(chart); @@ -319,7 +317,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { close_btn_proxy->setZValue(chart->zValue() + 11); QToolButton *manage_btn = new QToolButton(); - manage_btn->setIcon(bootstrapPixmap("gear")); + manage_btn->setIcon(utils::icon("gear")); manage_btn->setAutoRaise(true); manage_btn->setToolTip(tr("Manage series")); manage_btn_proxy = new QGraphicsProxyWidget(chart); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 5e127966c1..3af0fa9fc3 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -6,7 +6,6 @@ #include #include -#include "selfdrive/ui/qt/util.h" #include "tools/cabana/commands.h" #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" @@ -38,8 +37,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart name_label->setAlignment(Qt::AlignCenter); name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(name_label); - toolbar->addAction(bootstrapPixmap("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); - remove_msg_act = toolbar->addAction(bootstrapPixmap("x-lg"), "", this, &DetailWidget::removeMsg); + toolbar->addAction(utils::icon("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); + remove_msg_act = toolbar->addAction(utils::icon("x-lg"), "", this, &DetailWidget::removeMsg); remove_msg_act->setToolTip(tr("Remove Message")); main_layout->addWidget(toolbar); @@ -63,8 +62,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart tab_widget = new QTabWidget(this); tab_widget->setTabPosition(QTabWidget::South); - tab_widget->addTab(splitter, bootstrapPixmap("file-earmark-ruled"), "&Msg"); - tab_widget->addTab(history_log = new LogsWidget(this), bootstrapPixmap("stopwatch"), "&Logs"); + tab_widget->addTab(splitter, utils::icon("file-earmark-ruled"), "&Msg"); + tab_widget->addTab(history_log = new LogsWidget(this), utils::icon("stopwatch"), "&Logs"); main_layout->addWidget(tab_widget); stacked_layout = new QStackedLayout(this); @@ -148,7 +147,7 @@ void DetailWidget::refresh() { if (!warnings.isEmpty()) { warning_label->setText(warnings.join('\n')); - warning_icon->setPixmap(bootstrapPixmap(msg ? "exclamation-triangle" : "info-circle")); + warning_icon->setPixmap(utils::icon(msg ? "exclamation-triangle" : "info-circle")); } warning_widget->setVisible(!warnings.isEmpty()); } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index ceb7b7ba3f..7f31293c41 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -10,8 +10,6 @@ #include "tools/cabana/commands.h" -#include "selfdrive/ui/qt/util.h" - // SignalModel SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(parent) { @@ -132,7 +130,7 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { if (item->type == Item::Endian) return item->sig->is_little_endian ? Qt::Checked : Qt::Unchecked; if (item->type == Item::Signed) return item->sig->is_signed ? Qt::Checked : Qt::Unchecked; } else if (role == Qt::DecorationRole && index.column() == 0 && item->type == Item::ExtraInfo) { - return bootstrapPixmap(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up"); + return utils::icon(item->parent->extra_expanded ? "chevron-compact-down" : "chevron-compact-up"); } } return {}; @@ -331,7 +329,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), hl->addWidget(filter_edit); hl->addStretch(1); auto collapse_btn = new QToolButton(); - collapse_btn->setIcon(bootstrapPixmap("dash-square")); + collapse_btn->setIcon(utils::icon("dash-square")); collapse_btn->setIconSize({12, 12}); collapse_btn->setAutoRaise(true); collapse_btn->setToolTip(tr("Collapse All")); @@ -375,7 +373,7 @@ void SignalView::setMessage(const QString &id) { void SignalView::rowsChanged() { auto create_btn = [](const QString &id, const QString &tooltip) { auto btn = new QToolButton(); - btn->setIcon(bootstrapPixmap(id)); + btn->setIcon(utils::icon(id)); btn->setToolTip(tooltip); btn->setAutoRaise(true); return btn; diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 023e893e11..699aa7dc01 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -1,8 +1,11 @@ #include "tools/cabana/util.h" +#include #include #include +#include "selfdrive/ui/qt/util.h" + static QColor blend(QColor a, QColor b) { return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); } @@ -100,3 +103,17 @@ QValidator::State NameValidator::validate(QString &input, int &pos) const { input.replace(' ', '_'); return QRegExpValidator::validate(input, pos); } + +namespace utils { +QPixmap icon(const QString &id) { + static bool dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > + QApplication::style()->standardPalette().color(QPalette::Background).value(); + QPixmap pm = bootstrapPixmap(id); + if (dark_theme) { + QPainter p(&pm); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(pm.rect(), Qt::lightGray); + } + return pm; +} +} // namespace utils diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 20c85af39e..a598726bb6 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -45,3 +45,7 @@ public: NameValidator(QObject *parent=nullptr); QValidator::State validate(QString &input, int &pos) const override; }; + +namespace utils { +QPixmap icon(const QString &id); +} diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 445a21c755..d8d89a708c 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -13,8 +13,6 @@ #include #include -#include "selfdrive/ui/qt/util.h" - inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } @@ -130,7 +128,7 @@ void VideoWidget::updateState() { } void VideoWidget::updatePlayBtnState() { - play_btn->setIcon(bootstrapPixmap(can->isPaused() ? "play" : "pause")); + play_btn->setIcon(utils::icon(can->isPaused() ? "play" : "pause")); play_btn->setToolTip(can->isPaused() ? tr("Play") : tr("Pause")); } From 1ba590e04389aea21e7e54ad574dfcc91f7cd1e6 Mon Sep 17 00:00:00 2001 From: cydia2020 <12470297+cydia2020@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:12:31 +1100 Subject: [PATCH 0792/1179] Toyota: make LKAS message 5hz (#26830) * Toyota: make LKAS message 5hz * update refs --------- Co-authored-by: Shane Smiskol --- selfdrive/car/toyota/carcontroller.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 6dbdd4b5d9..222cf70613 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -143,7 +143,7 @@ class CarController: # forcing the pcm to disengage causes a bad fault sound so play a good sound instead send_ui = True - if self.frame % 100 == 0 or send_ui: + if self.frame % 20 == 0 or send_ui: can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart, CC.enabled, CS.lkas_hud)) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 51de0f0013..b598524fd7 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -844c84eae269e74b246b039d2b33fd44e98a5b68 \ No newline at end of file +d795362593d935767c694c652ecb05ab80dd1914 \ No newline at end of file From ec4c553542b3e63e24bb2b08c0ed007c69356a59 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Tue, 31 Jan 2023 20:46:57 -0300 Subject: [PATCH 0793/1179] Toyota: add FW engine for Brazilian Corolla Hybrid (#26943) * Add miss FW engine for Toyota Corolla Hybrid Test route ` 4f50e44908cc46b8|2023-01-12--21-08-57 ` * braziliam toyota corolla hybrid 2023 is US affected by TSK? * add a new entry for south america * Revert "add a new entry for south america" This reverts commit 28454c04cc93dc241da3b004a7154e44313e85c9. * CARS.md is autogenerated! * delete CARS.md to fix merge conflict * space * i don't know if we know for sure not all international 2023's have TSK --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 3 ++- selfdrive/car/toyota/values.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CARS.md b/docs/CARS.md index f4ad4b75fa..ea06176178 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 230 Supported Cars +# 231 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -184,6 +184,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index c413028a25..6c2b865982 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -125,6 +125,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { ], CAR.COROLLAH_TSS2: [ ToyotaCarInfo("Toyota Corolla Hybrid 2020-22"), + ToyotaCarInfo("Toyota Corolla Hybrid (Non-US only) 2020-23", min_enable_speed=7.5), ToyotaCarInfo("Toyota Corolla Cross Hybrid (Non-US only) 2020-22", min_enable_speed=7.5), ToyotaCarInfo("Lexus UX Hybrid 2019-22"), ], @@ -841,6 +842,7 @@ FW_VERSIONS = { b'\x02896630A07000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630A21000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZJ5000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896630ZK8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZN8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZQ3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZR2000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', From f37d35ed63e463ea0634885e0578f605958d5121 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 31 Jan 2023 15:48:40 -0800 Subject: [PATCH 0794/1179] Hyundai: add FW for Genesis and Genesis G80 (#27171) * add FW for Genesis and G80 * move to top --- selfdrive/car/hyundai/values.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1be612ad74..1d531c2b87 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -367,6 +367,13 @@ FW_QUERY_CONFIG = FwQueryConfig( ) FW_VERSIONS = { + CAR.HYUNDAI_GENESIS: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00DH LKAS 1.1 -150210', + b'\xf1\x00DH LKAS 1.4 -140110', + b'\xf1\x00DH LKAS 1.5 -140425', + ], + }, CAR.IONIQ: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ', @@ -1031,6 +1038,25 @@ FW_VERSIONS = { b'\xf1\x81640H0051\x00\x00\x00\x00\x00\x00\x00\x00', ], }, + CAR.GENESIS_G80: { + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00DH__ SCC F-CUP 1.00 1.01 96400-B1120 ', + ], + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00DH LKAS AT USA LHD 1.01 1.03 95895-B1500 180713', + b'\xf1\x00DH LKAS AT USA LHD 1.01 1.02 95895-B1500 170810', + b'\xf1\x00DH LKAS AT USA LHD 1.01 1.01 95895-B1500 161014', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00bcsh8p54 E21\x00\x00\x00\x00\x00\x00\x00SDH0T33NH4\xd7O\x9e\xc9', + b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00TDH0G38NH3:-\xa9n', + b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0G38NH2j\x9dA\x1c', + b'\xf1\x00bcsh8p54 E18\x00\x00\x00\x00\x00\x00\x00SDH0T33NH3\x97\xe6\xbc\xb8', + ], + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x81640F0051\x00\x00\x00\x00\x00\x00\x00\x00', + ], + }, CAR.GENESIS_G90: { (Ecu.transmission, 0x7e1, None): [b'\xf1\x87VDGMD15866192DD3x\x88x\x89wuFvvfUf\x88vWwgwwwvfVgx\x87o\xff\xbc^\xf1\x81E14\x00\x00\x00\x00\x00\x00\x00\xf1\x00bcshcm49 E14\x00\x00\x00\x00\x00\x00\x00SHI0G50NB1tc5\xb7'], (Ecu.fwdRadar, 0x7d0, None): [b'\xf1\x00HI__ SCC F-CUP 1.00 1.01 96400-D2100 '], From 022ef679e6d67f0be82ddc19b595bc874d456138 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 31 Jan 2023 20:26:33 -0800 Subject: [PATCH 0795/1179] GM camera ACC: reliable relay closing (#27164) * Reliable relay open * Reliable relay close * ign in a loop * fixes * we need this * log * comment to remind me tmrw * ign fix * this makes it 2x more reliable, but messyyy * Revert "this makes it 2x more reliable, but messyyy" This reverts commit 03401dc4a705cfacbe5a7048d95dccb6fa80d57f. * revert non-related stuff * comments, spaces * a stands for indefinite article * not applicable for non-camera acc * something... * Revert "something..." This reverts commit de8a158488efd5ef257434fbc3c55aefff800cb7. * Update ref_commit --- selfdrive/car/gm/carcontroller.py | 9 +++++++-- selfdrive/car/gm/carstate.py | 4 ++++ selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index c5aae34249..c25de41769 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -50,9 +50,14 @@ class CarController: # Steering (Active: 50Hz, inactive: 10Hz) # Attempt to sync with camera on startup at 50Hz, first few msgs are blocked - init_lka_counter = not self.sent_lka_steering_cmd and self.CP.networkLocation == NetworkLocation.fwdCamera + init_lka_counter = not self.sent_lka_steering_cmd + # Also send at 50Hz until we're in sync with camera so counters align when relay closes, preventing a fault + # openpilot can subtly drift, so this is activated throughout a drive to stay synced + out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.camera_lka_steering_cmd_counter + 1) % 4 + sync_steer = (init_lka_counter or out_of_sync) and self.CP.networkLocation == NetworkLocation.fwdCamera + steer_step = self.params.INACTIVE_STEER_STEP - if CC.latActive or init_lka_counter: + if CC.latActive or sync_steer: steer_step = self.params.STEER_STEP # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index cf6d2817ec..8ea8ea8874 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -19,6 +19,7 @@ class CarState(CarStateBase): self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] self.loopback_lka_steering_cmd_updated = False self.pt_lka_steering_cmd_counter = 0 + self.camera_lka_steering_cmd_counter = 0 self.buttons_counter = 0 def update(self, pt_cp, cam_cp, loopback_cp): @@ -34,6 +35,7 @@ class CarState(CarStateBase): self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 if self.CP.networkLocation == NetworkLocation.fwdCamera: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] + self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] ret.wheelSpeeds = self.get_wheel_speeds( pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"], @@ -113,11 +115,13 @@ class CarState(CarStateBase): if CP.networkLocation == NetworkLocation.fwdCamera: signals += [ ("AEBCmdActive", "AEBCmd"), + ("RollingCounter", "ASCMLKASteeringCmd"), ("ACCSpeedSetpoint", "ASCMActiveCruiseControlStatus"), ("ACCCruiseState", "ASCMActiveCruiseControlStatus"), ] checks += [ ("AEBCmd", 10), + ("ASCMLKASteeringCmd", 10), ("ASCMActiveCruiseControlStatus", 25), ] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index b598524fd7..b7cb6ceb33 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -d795362593d935767c694c652ecb05ab80dd1914 \ No newline at end of file +baef183c9602b702756e2fd0781b5d289b61d19a From 519b3c8847d5c054b130667977e181cc7e54e7fa Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 1 Feb 2023 11:21:51 -0800 Subject: [PATCH 0796/1179] paramsd: Check if roll from the localizer is actually valid (#27105) * add roll_valid check, use localizer roll when it is valid * increase std to 1.5 * btter check * avoid numpy * update refs * update refs --- selfdrive/locationd/paramsd.py | 17 +++++++++++------ selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index 7e7c2b091f..7e30b1e3a7 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -14,8 +14,9 @@ from system.swaglog import cloudlog MAX_ANGLE_OFFSET_DELTA = 20 * DT_MDL # Max 20 deg/s -ROLL_MAX_DELTA = np.radians(20.0) * DT_MDL # 20deg in 1 second is well within curvature limits +ROLL_MAX_DELTA = math.radians(20.0) * DT_MDL # 20deg in 1 second is well within curvature limits ROLL_MIN, ROLL_MAX = math.radians(-10), math.radians(10) +ROLL_STD_MAX = math.radians(1.5) LATERAL_ACC_SENSOR_THRESHOLD = 4.0 @@ -37,8 +38,7 @@ class ParamsLearner: self.yaw_rate_std = 0.0 self.roll = 0.0 self.steering_angle = 0.0 - - self.valid = True + self.roll_valid = False def handle_log(self, t, which, msg): if which == 'liveLocationKalman': @@ -47,8 +47,8 @@ class ParamsLearner: localizer_roll = msg.orientationNED.value[0] localizer_roll_std = np.radians(1) if np.isnan(msg.orientationNED.std[0]) else msg.orientationNED.std[0] - roll_valid = msg.orientationNED.valid and ROLL_MIN < localizer_roll < ROLL_MAX - if roll_valid: + self.roll_valid = (localizer_roll_std < ROLL_STD_MAX) and (ROLL_MIN < localizer_roll < ROLL_MAX) and msg.sensorsOK + if self.roll_valid: roll = localizer_roll # Experimentally found multiplier of 2 to be best trade-off between stability and accuracy or similar? roll_std = 2 * localizer_roll_std @@ -156,6 +156,7 @@ def main(sm=None, pm=None): learner = ParamsLearner(CP, params['steerRatio'], params['stiffnessFactor'], math.radians(params['angleOffsetAverageDeg'])) angle_offset_average = params['angleOffsetAverageDeg'] angle_offset = angle_offset_average + roll = 0.0 while True: sm.update() @@ -175,6 +176,8 @@ def main(sm=None, pm=None): angle_offset_average = clip(math.degrees(x[States.ANGLE_OFFSET]), angle_offset_average - MAX_ANGLE_OFFSET_DELTA, angle_offset_average + MAX_ANGLE_OFFSET_DELTA) angle_offset = clip(math.degrees(x[States.ANGLE_OFFSET] + x[States.ANGLE_OFFSET_FAST]), angle_offset - MAX_ANGLE_OFFSET_DELTA, angle_offset + MAX_ANGLE_OFFSET_DELTA) + roll = clip(float(x[States.ROAD_ROLL]), roll - ROLL_MAX_DELTA, roll + ROLL_MAX_DELTA) + roll_std = float(P[States.ROAD_ROLL]) # Account for the opposite signs of the yaw rates sensors_valid = bool(abs(learner.speed * (x[States.YAW_RATE] + learner.yaw_rate)) < LATERAL_ACC_SENSOR_THRESHOLD) @@ -185,12 +188,14 @@ def main(sm=None, pm=None): liveParameters.sensorValid = sensors_valid liveParameters.steerRatio = float(x[States.STEER_RATIO]) liveParameters.stiffnessFactor = float(x[States.STIFFNESS]) - liveParameters.roll = float(x[States.ROAD_ROLL]) + liveParameters.roll = roll liveParameters.angleOffsetAverageDeg = angle_offset_average liveParameters.angleOffsetDeg = angle_offset liveParameters.valid = all(( abs(liveParameters.angleOffsetAverageDeg) < 10.0, abs(liveParameters.angleOffsetDeg) < 10.0, + abs(liveParameters.roll) < ROLL_MAX, + roll_std < ROLL_STD_MAX, 0.2 <= liveParameters.stiffnessFactor <= 5.0, min_sr <= liveParameters.steerRatio <= max_sr, )) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index b7cb6ceb33..959c213a03 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -baef183c9602b702756e2fd0781b5d289b61d19a +9ef210f7e473fa46dd43337b5f09eeabebc694b7 \ No newline at end of file From 02c751f4830b87793530732b5ac820ac48978ba9 Mon Sep 17 00:00:00 2001 From: Sean Cox Date: Wed, 1 Feb 2023 16:01:08 -0500 Subject: [PATCH 0797/1179] Hyundai: remove HYUNDAI_GENESIS from legacy steer max blacklist (#27176) --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1d531c2b87..6bd4789552 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -35,7 +35,7 @@ class CarControllerParams: # To determine the limit for your car, find the maximum value that the stock LKAS will request. # If the max stock LKAS request is <384, add your car to this list. - elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.IONIQ, + elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV, CAR.KIA_OPTIMA_H, CAR.KIA_SORENTO): self.STEER_MAX = 255 From b740bdc99c213a73628081b9f07b559420072d99 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:01:26 -0500 Subject: [PATCH 0798/1179] Hyundai: Enable radar tracks for Santa Fe 2019 (#27175) --- selfdrive/debug/hyundai_enable_radar_points.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/debug/hyundai_enable_radar_points.py b/selfdrive/debug/hyundai_enable_radar_points.py index ac7e7102d0..07ce5ebddb 100755 --- a/selfdrive/debug/hyundai_enable_radar_points.py +++ b/selfdrive/debug/hyundai_enable_radar_points.py @@ -52,6 +52,10 @@ SUPPORTED_FW_VERSIONS = { b'IK__ SCC F-CUP 1.00 1.02 96400-G9100\x18\x07\x06\x17\x12 ': ConfigValues( default_config=b"\x00\x00\x00\x01\x00\x00", tracks_enabled=b"\x00\x00\x00\x01\x00\x01"), + # 2019 SANTA FE + b"TM__ SCC F-CUP 1.00 1.00 99110-S1210\x19\x01%\x168 ": ConfigValues( + default_config=b"\x00\x00\x00\x01\x00\x00", + tracks_enabled=b"\x00\x00\x00\x01\x00\x01"), } if __name__ == "__main__": From ef0e8a312768e710e060e846e34c14255ffce028 Mon Sep 17 00:00:00 2001 From: Rewat S <76684800+taperec@users.noreply.github.com> Date: Thu, 2 Feb 2023 05:17:06 +0700 Subject: [PATCH 0799/1179] Multilang: add missing Thai translations (#27148) * Multilang: add missing Thai translations * Multilang: update Thai translations * Multilang: add missing Thai translations --- selfdrive/ui/translations/main_th.ts | 97 ++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 0de0ba5f9a..ce394ecb97 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -238,6 +238,14 @@ Disengage to Power Off ยกเลิกระบบช่วยขับเพื่อปิดเครื่อง + + Reset + รีเซ็ต + + + Review + ทบทวน + DriveStats @@ -273,6 +281,17 @@ กำลังเปิดกล้อง + + ExperimentalModeButton + + EXPERIMENTAL MODE ON + คุณกำลังใช้โหมดทดลอง + + + CHILL MODE ON + คุณกำลังใช้โหมดชิล + + InputDialog @@ -463,6 +482,17 @@ location set จดจำ connect.comma.ai โดยการเพิ่มไปยังหน้าจอโฮม เพื่อใช้งานเหมือนเป็นแอปพลิเคชัน + + ParamControl + + Enable + เปิดใช้งาน + + + Cancel + ยกเลิก + + PrimeAdWidget @@ -585,13 +615,6 @@ location set ไม่สามารถเมานต์พาร์ติชั่นข้อมูล กดยืนยันเพื่อรีเซ็ตอุปกรณ์ของคุณ - - RichTextDialog - - Ok - ตกลง - - SettingsWindow @@ -850,6 +873,10 @@ location set Select a branch เลือก Branch + + Uninstall + ถอนการติดตั้ง + SshControl @@ -974,29 +1001,57 @@ location set Show map on left side when in split screen view. แสดงแผนที่ด้านซ้ายของหน้าจอเมื่ออยู่ในโหมดแบ่งหน้าจอ - - 🌮 End-to-end longitudinal (extremely alpha) 🌮 - 🌮 ควบคุมเร่ง/เบรคแบบ End-to-end (อยู่ขั้นพัฒนา) 🌮 - Experimental openpilot Longitudinal Control ทดลองใช้ระบบควบคุมการเร่ง/เบรคโดย openpilot - <b>WARNING: openpilot longitudinal control is experimental for this car and will disable AEB.</b> - <b>คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในขั้นทดลอง และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด</b> + Experimental Mode + โหมดทดลอง - Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would. Super experimental. - ให้ openpilot ควบคุมการเร่ง/เบรคแบบ end-to-end โดย openpilot จะขับอย่างที่มนุษย์คิด ระบบยังอยู่ในขั้นทดลอง + WARNING: openpilot longitudinal control is experimental for this car and will disable Automatic Emergency Braking (AEB). + คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในขั้นพัฒนา และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด - openpilot longitudinal control is not currently available for this car. - ขณะนี้ยังไม่มีระบบควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ + 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 ควบคุมการเร่ง/เบรค แนะนำให้เปิดโหมดทดลองเมื่อต้องการให้ openpilot ควบคุมการเร่ง/เบรค ซึ่งอยู่ในขั้นพัฒนา - Enable experimental longitudinal control to enable this. - เปิดใช้งานระบบควบคุมการเร่ง/เบรคขั้นทดลอง เพื่อเปิดใช้งานสิ่งนี้ + 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: + โดยปกติ openpilot จะขับใน<b>โหมดชิล</b> เปิดโหมดทดลองเพื่อใช้<b>ความสามารถในขั้นพัฒนา</b> ซึ่งยังไม่พร้อมสำหรับโหมดชิล ความสามารถในขั้นพัฒนามีดังนี้: + + + 🌮 End-to-End Longitudinal Control 🌮 + 🌮 ควบคุมเร่ง/เบรคแบบ End-to-End 🌮 + + + 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 ควบคุมการเร่ง/เบรค โดย openpilot จะขับอย่างที่มนุษย์คิด รวมถึงการหยุดที่ไฟแดง และป้ายหยุดรถ เนื่องจาก 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. + การแสดงภาพการขับขี่จะเปลี่ยนไปใช้กล้องมุมกว้างที่หันหน้าไปทางถนนเมื่ออยู่ในความเร็วต่ำ เพื่อแสดงภาพการเลี้ยวที่ดีขึ้น โลโก้โหมดการทดลองจะแสดงที่มุมบนขวาด้วย + + + Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. + ขณะนี้โหมดทดลองไม่สามารถใช้งานได้ในรถคันนี้ เนื่องจากเปิดใช้ระบบควบคุมการเร่ง/เบรคของรถที่ติดตั้งจากโรงงานอยู่ + + + openpilot longitudinal control may come in a future update. + ระบบควบคุมการเร่ง/เบรคโดย openpilot อาจมาในการอัปเดตในอนาคต + + + An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + เวอร์ชันทดลองของระบบควบคุมการเร่ง/เบรคโดย openpilot สามารถทดสอบได้พร้อมกับโหมดการทดลอง บน branch ที่กำลังพัฒนา + + + Enable experimental longitudinal control to allow Experimental mode. + เปิดระบบควบคุมการเร่ง/เบรคขั้นพัฒนาโดย openpilot เพื่อเปิดใช้งานโหมดทดลอง @@ -1052,5 +1107,9 @@ location set Forget Wi-Fi Network "%1"? เลิกใช้เครือข่าย Wi-Fi "%1"? + + Forget + เลิกใช้ + From 3d98cb72c08ec5d9b9ac5645ea9effecadd6bc38 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 1 Feb 2023 15:19:40 -0700 Subject: [PATCH 0800/1179] Ubloxd: gps add iodc check (#27162) * gps add iodc check * add test * simplify * update ref --------- Co-authored-by: Kurt Nistelberger --- .../locationd/test/test_ublox_processing.py | 38 +++++++++++++- selfdrive/locationd/ublox_msg.cc | 52 +++++++------------ selfdrive/locationd/ublox_msg.h | 1 - selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 55 insertions(+), 38 deletions(-) diff --git a/selfdrive/locationd/test/test_ublox_processing.py b/selfdrive/locationd/test/test_ublox_processing.py index 7aa588d43e..cd4ce0de04 100755 --- a/selfdrive/locationd/test/test_ublox_processing.py +++ b/selfdrive/locationd/test/test_ublox_processing.py @@ -1,5 +1,5 @@ import unittest - +import time import numpy as np from laika import AstroDog @@ -8,7 +8,8 @@ from laika.raw_gnss import correct_measurements, process_measurements, read_raw_ from laika.opt import calc_pos_fix from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader - +from selfdrive.test.helpers import with_processes +import cereal.messaging as messaging def get_gnss_measurements(log_reader): gnss_measurements = [] @@ -21,6 +22,12 @@ def get_gnss_measurements(log_reader): gnss_measurements.append(read_raw_ublox(report)) return gnss_measurements +def get_ublox_raw(log_reader): + ublox_raw = [] + for msg in log_reader: + if msg.which() == "ubloxRaw": + ublox_raw.append(msg) + return ublox_raw class TestUbloxProcessing(unittest.TestCase): NUM_TEST_PROCESS_MEAS = 10 @@ -30,6 +37,10 @@ class TestUbloxProcessing(unittest.TestCase): lr = LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", 0)) cls.gnss_measurements = get_gnss_measurements(lr) + # test gps ephemeris continuity check (drive has ephemeris issues with cutover data) + lr = LogReader(get_url("37b6542f3211019a|2023-01-15--23-45-10", 14)) + cls.ublox_raw = get_ublox_raw(lr) + def test_read_ublox_raw(self): count_gps = 0 count_glonass = 0 @@ -76,6 +87,29 @@ class TestUbloxProcessing(unittest.TestCase): self.assertEqual(count_processed_measurements, 69) self.assertEqual(count_corrected_measurements, 69) + @with_processes(['ubloxd']) + def test_ublox_gps_cutover(self): + time.sleep(2) + ugs = messaging.sub_sock("ubloxGnss", timeout=0.1) + ur_pm = messaging.PubMaster(['ubloxRaw']) + + def replay_segment(): + rcv_msgs = [] + for msg in self.ublox_raw: + ur_pm.send(msg.which(), msg.as_builder()) + time.sleep(0.01) + rcv_msgs += messaging.drain_sock(ugs) + + time.sleep(0.1) + rcv_msgs += messaging.drain_sock(ugs) + return rcv_msgs + + # replay twice to enforce cutover data on rewind + rcv_msgs = replay_segment() + rcv_msgs += replay_segment() + + ephems_cnt = sum(m.ubloxGnss.which() == 'ephemeris' for m in rcv_msgs) + self.assertEqual(ephems_cnt, 15) if __name__ == "__main__": unittest.main() diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 4b31b0101e..127c7e56b6 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -166,26 +166,25 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m { kaitai::kstream stream(subframe_data); gps_t subframe(&stream); + int subframe_id = subframe.how()->subframe_id(); - int sv_id = msg->sv_id(); - uint64_t tow_counter = subframe.how()->tow_count(); - - bool clear_buffer = subframe_id == 1; - if (gps_sat_tow_count.count(sv_id) != 0) { - int64_t counter_diff = tow_counter - gps_sat_tow_count[sv_id]; - clear_buffer |= counter_diff != 1 && counter_diff != -100798; + if (subframe_id > 3) { + // dont parse almanac subframes + return kj::Array(); } - if (clear_buffer) gps_subframes[sv_id].clear(); - - gps_subframes[sv_id][subframe_id] = subframe_data; - gps_sat_tow_count[sv_id] = tow_counter; + gps_subframes[msg->sv_id()][subframe_id] = subframe_data; } - if (gps_subframes[msg->sv_id()].size() == 5) { + // publish if subframes 1-3 have been collected + if (gps_subframes[msg->sv_id()].size() == 3) { MessageBuilder msg_builder; auto eph = msg_builder.initEvent().initUbloxGnss().initEphemeris(); eph.setSvId(msg->sv_id()); + int iode_s2 = 0; + int iode_s3 = 0; + int iodc_lsb = 0; + // Subframe 1 { kaitai::kstream stream(gps_subframes[msg->sv_id()][1]); @@ -199,6 +198,7 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m eph.setAf1(subframe_1->af_1() * pow(2, -43)); eph.setAf0(subframe_1->af_0() * pow(2, -31)); eph.setSvHealth(subframe_1->sv_health()); + iodc_lsb = subframe_1->iodc_lsb(); } // Subframe 2 @@ -215,6 +215,7 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m eph.setCus(subframe_2->c_us() * pow(2, -29)); eph.setA(pow(subframe_2->sqrt_a() * pow(2, -19), 2.0)); eph.setToe(subframe_2->t_oe() * pow(2, 4)); + iode_s2 = subframe_2->iode(); } // Subframe 3 @@ -232,31 +233,14 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m eph.setOmegaDot(subframe_3->omega_dot() * pow(2, -43) * gpsPi); eph.setIode(subframe_3->iode()); eph.setIDot(subframe_3->idot() * pow(2, -43) * gpsPi); + iode_s3 = subframe_3->iode(); } - // Subframe 4 - { - kaitai::kstream stream(gps_subframes[msg->sv_id()][4]); - gps_t subframe(&stream); - gps_t::subframe_4_t* subframe_4 = static_cast(subframe.body()); - - // This is page 18, why is the page id 56? - if (subframe_4->data_id() == 1 && subframe_4->page_id() == 56) { - auto iono = static_cast(subframe_4->body()); - double a0 = iono->a0() * pow(2, -30); - double a1 = iono->a1() * pow(2, -27); - double a2 = iono->a2() * pow(2, -24); - double a3 = iono->a3() * pow(2, -24); - eph.setIonoAlpha({a0, a1, a2, a3}); - - double b0 = iono->b0() * pow(2, 11); - double b1 = iono->b1() * pow(2, 14); - double b2 = iono->b2() * pow(2, 16); - double b3 = iono->b3() * pow(2, 16); - eph.setIonoBeta({b0, b1, b2, b3}); - } + gps_subframes[msg->sv_id()].clear(); + if (iodc_lsb != iode_s2 || iodc_lsb != iode_s3) { + // data set cutover, reject ephemeris + return kj::Array(); } - return capnp::messageToFlatArray(msg_builder); } return kj::Array(); diff --git a/selfdrive/locationd/ublox_msg.h b/selfdrive/locationd/ublox_msg.h index 736e6d5171..f031313168 100644 --- a/selfdrive/locationd/ublox_msg.h +++ b/selfdrive/locationd/ublox_msg.h @@ -105,7 +105,6 @@ class UbloxMsgParser { kj::Array parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg); std::unordered_map> gps_subframes; - std::unordered_map gps_sat_tow_count; size_t bytes_in_parse_buf = 0; uint8_t msg_parse_buf[ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_MAX_MSG_SIZE]; diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 959c213a03..a6c8aa682d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -9ef210f7e473fa46dd43337b5f09eeabebc694b7 \ No newline at end of file +e825c953316277a342284a1f10b8dab88e95fc31 \ No newline at end of file From 83af2182b457692532ecc1426304782af1f9887d Mon Sep 17 00:00:00 2001 From: mrquell <48170600+mrquell@users.noreply.github.com> Date: Wed, 1 Feb 2023 20:04:48 -0500 Subject: [PATCH 0801/1179] Support for Kia Niro PHEV 2020 (#27158) * Update values.py * Update values.py Added support for Kia Niro PHEV 2020 * Update values.py Added support for Kia Niro PHEV 2020 * Update values.py Changed the fingerprint to be 4 seperate IDs * Apply suggestions from code review * generate * gen docs --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 3 ++- selfdrive/car/hyundai/values.py | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index ea06176178..9a33278d3b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 231 Supported Cars +# 232 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -107,6 +107,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| |Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| |Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| |Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 6bd4789552..b355da6cac 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -198,7 +198,10 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Niro EV 2021", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Niro EV 2022", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), ], - CAR.KIA_NIRO_PHEV: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c), + CAR.KIA_NIRO_PHEV: [ + HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, harness=Harness.hyundai_c), + HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", harness=Harness.hyundai_d), + ], CAR.KIA_NIRO_HEV_2021: [ HyundaiCarInfo("Kia Niro Hybrid 2021", harness=Harness.hyundai_f), # TODO: could be hyundai_d, verify HyundaiCarInfo("Kia Niro Hybrid 2022", harness=Harness.hyundai_h), @@ -1231,22 +1234,27 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x816H6F4051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6D1051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.transmission, 0x7e1, None): [ b"\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\xf4'\\\x91", b'\xf1\x816U3J2051\x00\x00\xf1\x006U3H0_C2\x00\x006U3J2051\x00\x00PDE0G16NS2\x00\x00\x00\x00', b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x00\x00\x00\x00', b'\xf1\x816U3H3051\x00\x00\xf1\x006U3H0_C2\x00\x006U3H3051\x00\x00PDE0G16NS1\x13\xcd\x88\x92', + b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PDE0G16NL2&[\xc3\x01', ], (Ecu.eps, 0x7D4, None): [ b'\xf1\x00DE MDPS C 1.00 1.09 56310G5301\x00 4DEHC109', + b'\xf1\x00DE MDPS C 1.00 1.01 56310G5520\x00 4DEPC101', ], (Ecu.fwdCamera, 0x7C4, None): [ b'\xf1\x00DEP MFC AT USA LHD 1.00 1.01 95740-G5010 170424', b'\xf1\x00DEP MFC AT USA LHD 1.00 1.00 95740-G5010 170117', + b'\xf1\x00DEP MFC AT USA LHD 1.00 1.05 99211-G5000 190826', ], (Ecu.fwdRadar, 0x7D0, None): [ b'\xf1\x00DEhe SCC H-CUP 1.01 1.02 96400-G5100 ', + b'\xf1\x00DEhe SCC F-CUP 1.00 1.02 99110-G5100 ', ], }, CAR.KIA_NIRO_HEV_2021: { From 0ee53532be30c740a77f20c39b672f7b0ebb755b Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 1 Feb 2023 17:33:08 -0800 Subject: [PATCH 0802/1179] fix pigeond device reset --- selfdrive/sensord/pigeond.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/sensord/pigeond.py b/selfdrive/sensord/pigeond.py index bb53dd1bd4..9d0a62bd3b 100755 --- a/selfdrive/sensord/pigeond.py +++ b/selfdrive/sensord/pigeond.py @@ -123,7 +123,7 @@ class TTYPigeon(): init_baudrate(self) # clear configuration - self.send_with_ack(b"\xb5\x62\x06\x09\x0d\x00\x00\x00\x1f\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x17\x71\x5b") + self.send_with_ack(b"\xb5\x62\x06\x09\x0d\x00\x1f\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x71\xd7") # clear flash memory (almanac backup) self.send_with_ack(b"\xB5\x62\x09\x14\x04\x00\x01\x00\x00\x00\x22\xf0") From 2a6de71cc0d369314d098a91baa9984f01b05faa Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 1 Feb 2023 18:38:00 -0800 Subject: [PATCH 0803/1179] get_present_ecus: check available pandas (#27181) * add num_pandas to get_present_ecus * always bugged me * move this to function signature --- selfdrive/car/car_helpers.py | 2 +- selfdrive/car/ecu_addrs.py | 2 +- selfdrive/car/fw_versions.py | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 88e8c72153..e326209096 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -99,7 +99,7 @@ def fingerprint(logcan, sendcan, num_pandas): else: cloudlog.warning("Getting VIN & FW versions") vin_rx_addr, vin = get_vin(logcan, sendcan, bus) - ecu_rx_addrs = get_present_ecus(logcan, sendcan) + ecu_rx_addrs = get_present_ecus(logcan, sendcan, num_pandas=num_pandas) car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas) cached = False diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index 9f6ace2b5f..e5d550fac8 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -87,5 +87,5 @@ if __name__ == "__main__": for addr, subaddr, bus in ecu_addrs: msg = f" 0x{hex(addr)}" if subaddr is not None: - msg += f" (sub-address: 0x{hex(subaddr)})" + msg += f" (sub-address: {hex(subaddr)})" print(msg) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index f4d92ab960..0db260abbd 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -146,12 +146,16 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): return True, set() -def get_present_ecus(logcan, sendcan): +def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[Tuple[int, Optional[int], int]]: queries = list() parallel_queries = list() responses = set() for brand, r in REQUESTS: + # Skip query if no panda available + if r.bus > num_pandas * 4 - 1: + continue + for brand_versions in VERSIONS[brand].values(): for ecu_type, addr, sub_addr in brand_versions: # Only query ecus in whitelist if whitelist is not empty @@ -171,7 +175,7 @@ def get_present_ecus(logcan, sendcan): queries.insert(0, parallel_queries) - ecu_responses: Set[Tuple[int, Optional[int], int]] = set() + ecu_responses = set() for query in queries: ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) return ecu_responses From 0eeb69a5d0f2009a38bf4ebdf18e0e143ff7d5f2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 1 Feb 2023 19:50:48 -0800 Subject: [PATCH 0804/1179] boardd: enable fingerprinting with both multiplexed modes (#27159) Co-authored-by: Shane Smiskol --- common/params.cc | 1 + selfdrive/boardd/boardd.cc | 15 ++++++--------- selfdrive/car/car_helpers.py | 5 ++++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/common/params.cc b/common/params.cc index 35ceecfdc3..7dd0fbcb41 100644 --- a/common/params.cc +++ b/common/params.cc @@ -111,6 +111,7 @@ std::unordered_map keys = { {"DoReboot", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START}, + {"FirmwareObdQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"ForcePowerDown", CLEAR_ON_MANAGER_START}, {"GitBranch", PERSISTENT}, {"GitCommit", PERSISTENT}, diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 5ef49d4b22..0473d3488c 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -106,6 +106,8 @@ void sync_time(Panda *panda, SyncTimeDir dir) { bool safety_setter_thread(std::vector pandas) { LOGD("Starting safety setter thread"); + Params p; + // there should be at least one panda connected if (pandas.size() == 0) { return false; @@ -117,25 +119,20 @@ bool safety_setter_thread(std::vector pandas) { pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); } - Params p = Params(); - - // wait for VIN to be read + // wait for FW query at OBD port to finish while (true) { if (do_exit || !check_all_connected(pandas) || !ignition) { return false; } - std::string value_vin = p.get("CarVin"); - if (value_vin.size() > 0) { - // sanity check VIN format - assert(value_vin.size() == 17); - LOGW("got CarVin %s", value_vin.c_str()); + if (p.getBool("FirmwareObdQueryDone")) { + LOGW("finished FW query at OBD port"); break; } util::sleep_for(20); } - // set to ELM327 for ECU knockouts + // set to ELM327 to finish fingerprinting and for potential ECU knockouts for (Panda *panda : pandas) { panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); } diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index e326209096..4ccce979d3 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -113,7 +113,10 @@ def fingerprint(logcan, sendcan, num_pandas): cloudlog.event("Malformed VIN", vin=vin, error=True) vin = VIN_UNKNOWN cloudlog.warning("VIN %s", vin) - Params().put("CarVin", vin) + + params = Params() + params.put("CarVin", vin) + params.put_bool("FirmwareObdQueryDone", True) finger = gen_empty_fingerprint() candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 From e07865fe4dbe5855fd2d5a53f6770a416bbe2ee3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 1 Feb 2023 20:11:40 -0800 Subject: [PATCH 0805/1179] boardd: update loopback test with new param --- selfdrive/boardd/tests/test_boardd_loopback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index e9bbcb4586..b8ebbd88a3 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -51,7 +51,7 @@ class TestBoardd(unittest.TestCase): cp.safetyConfigs = [safety_config]*num_pandas params = Params() - params.put("CarVin", b"0"*17) + params.put_bool("FirmwareObdQueryDone", True) params.put_bool("ControlsReady", True) params.put("CarParams", cp.to_bytes()) From 647e81f9bbab53439dea4b418c532c21afbbb50a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Feb 2023 02:23:21 +0800 Subject: [PATCH 0806/1179] cabana: show series colors in tooltip (#27186) show series colors in tooltip --- tools/cabana/chartswidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 47fc5dc03b..b49b20f2cc 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -652,10 +652,10 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto value_pos = chart()->mapToPosition(*it); if (value_pos.x() > track_pt.x()) track_pt = value_pos; } - text_list.push_back(QString(" %1 : %2 ").arg(sigs.size() > 1 ? s.sig->name.c_str() : "Value").arg(value)); + text_list.push_back(QString("%2: %3").arg(s.series->color().name(), s.sig->name.c_str(), value)); } if (track_pt.x() == 0) track_pt = ev->pos(); - QString text = QString("
 Time: %1  
%2
") + QString text = QString("%1
%2") .arg(chart()->mapToValue(track_pt).x(), 0, 'f', 3) .arg(text_list.join("
")); QPoint pt((int)track_pt.x() + 20, plot_area.top() - 20); From 24f4ada36d21a8ec841b2d866b1dc142baae8eb2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Feb 2023 10:25:20 -0800 Subject: [PATCH 0807/1179] updated: fix brief notification of update for same version (#27182) --- common/params.cc | 2 +- selfdrive/updated.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/common/params.cc b/common/params.cc index 7dd0fbcb41..db5e5e700d 100644 --- a/common/params.cc +++ b/common/params.cc @@ -171,7 +171,7 @@ std::unordered_map keys = { {"Timezone", PERSISTENT}, {"TrainingVersion", PERSISTENT}, {"UbloxAvailable", PERSISTENT}, - {"UpdateAvailable", CLEAR_ON_MANAGER_START}, + {"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"UpdateFailedCount", CLEAR_ON_MANAGER_START}, {"UpdaterState", CLEAR_ON_MANAGER_START}, {"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/updated.py b/selfdrive/updated.py index 9da2a05a11..2cb7d1c13b 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -423,6 +423,9 @@ def main() -> None: wait_helper = WaitTimeHelper() wait_helper.only_check_for_update = True + # invalidate old finalized update + set_consistent_flag(False) + # Run the update loop while True: wait_helper.ready_event.clear() From 6fa9b555a435cc9639193cca516b78a22189356c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Feb 2023 11:38:09 -0800 Subject: [PATCH 0808/1179] rename carState.radarOffCan to radarUnavailable (#27187) * rename carState.radarOffCan to radarUnavailable * bump cereal --- cereal | 2 +- selfdrive/car/body/interface.py | 2 +- selfdrive/car/chrysler/interface.py | 2 +- selfdrive/car/ford/interface.py | 2 +- selfdrive/car/gm/carcontroller.py | 2 +- selfdrive/car/gm/interface.py | 4 ++-- selfdrive/car/gm/radar_interface.py | 2 +- selfdrive/car/honda/interface.py | 2 +- selfdrive/car/honda/radar_interface.py | 2 +- selfdrive/car/hyundai/interface.py | 2 +- selfdrive/car/hyundai/radar_interface.py | 2 +- selfdrive/car/mazda/interface.py | 2 +- selfdrive/car/nissan/interface.py | 2 +- selfdrive/car/subaru/interface.py | 2 +- selfdrive/car/tests/test_car_interfaces.py | 2 +- selfdrive/car/volkswagen/interface.py | 2 +- selfdrive/test/process_replay/process_replay.py | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cereal b/cereal index b27131e72f..bdbac40160 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit b27131e72f987f3bd0fcd28a42f686b583709e1f +Subproject commit bdbac40160a550c88e481a3bf700a1016901bd9b diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index bc5b36e2ee..a90c4cfb87 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -24,7 +24,7 @@ class CarInterface(CarInterfaceBase): ret.wheelSpeedFactor = SPEED_FROM_RPM ret.centerToFront = ret.wheelbase * 0.44 - ret.radarOffCan = True + ret.radarUnavailable = True ret.openpilotLongitudinalControl = True ret.steerControlType = car.CarParams.SteerControlType.angle diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index c8504d6fb1..99f1692daa 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "chrysler" ret.dashcamOnly = candidate in RAM_HD - ret.radarOffCan = DBC[candidate]['radar'] is None + ret.radarUnavailable = DBC[candidate]['radar'] is None ret.steerActuatorDelay = 0.1 ret.steerLimitTimer = 0.4 diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 7c6a8ecbe4..8ce30e5d68 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -18,7 +18,7 @@ class CarInterface(CarInterfaceBase): # These cars are dashcam only until the port is finished ret.dashcamOnly = True - ret.radarOffCan = True + ret.radarUnavailable = True ret.steerControlType = car.CarParams.SteerControlType.angle ret.steerActuatorDelay = 0.2 ret.steerLimitTimer = 1.0 diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index c25de41769..56f6ff5a31 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -114,7 +114,7 @@ class CarController: # Radar needs to know current speed and yaw rate (50hz), # and that ADAS is alive (10hz) - if not self.CP.radarOffCan: + if not self.CP.radarUnavailable: tt = self.frame * DT_CTRL time_and_headlights_step = 10 if self.frame % time_and_headlights_step == 0: diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 856dcbaae5..3c2a12ef86 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -63,7 +63,7 @@ class CarInterface(CarInterfaceBase): if candidate in CAMERA_ACC_CAR: ret.experimentalLongitudinalAvailable = True ret.networkLocation = NetworkLocation.fwdCamera - ret.radarOffCan = True # no radar + ret.radarUnavailable = True # no radar ret.pcmCruise = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.minEnableSpeed = 5 * CV.KPH_TO_MS @@ -85,7 +85,7 @@ class CarInterface(CarInterfaceBase): else: # ASCM, OBD-II harness ret.openpilotLongitudinalControl = True ret.networkLocation = NetworkLocation.gateway - ret.radarOffCan = False + ret.radarUnavailable = False ret.pcmCruise = False # stock non-adaptive cruise control is kept off # supports stop and go, but initial engage must (conservatively) be above 18mph ret.minEnableSpeed = 18 * CV.MPH_TO_MS diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py index 5cb211812d..b86a85f915 100755 --- a/selfdrive/car/gm/radar_interface.py +++ b/selfdrive/car/gm/radar_interface.py @@ -36,7 +36,7 @@ class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) - self.rcp = None if CP.radarOffCan else create_radar_can_parser(CP.carFingerprint) + self.rcp = None if CP.radarUnavailable else create_radar_can_parser(CP.carFingerprint) self.trigger_msg = LAST_RADAR_MSG self.updated_messages = set() diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index da921ccda7..98243d81dd 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -34,7 +34,7 @@ class CarInterface(CarInterfaceBase): if candidate in HONDA_BOSCH: ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaBosch)] - ret.radarOffCan = True + ret.radarUnavailable = True if candidate not in HONDA_BOSCH_RADARLESS: # Disable the radar and let openpilot control longitudinal diff --git a/selfdrive/car/honda/radar_interface.py b/selfdrive/car/honda/radar_interface.py index 629ab01d4c..660be4c449 100755 --- a/selfdrive/car/honda/radar_interface.py +++ b/selfdrive/car/honda/radar_interface.py @@ -21,7 +21,7 @@ class RadarInterface(RadarInterfaceBase): self.track_id = 0 self.radar_fault = False self.radar_wrong_config = False - self.radar_off_can = CP.radarOffCan + self.radar_off_can = CP.radarUnavailable self.radar_ts = CP.radarTimeStep self.delay = int(round(0.1 / CP.radarTimeStep)) # 0.1s delay of radar diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 6d6d9833df..030c3f1abc 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -20,7 +20,7 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "hyundai" - ret.radarOffCan = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None + ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None # These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars likely still work fine. Once a user confirms each car works and a test route is diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py index 0d22611fb5..4ecca542b5 100644 --- a/selfdrive/car/hyundai/radar_interface.py +++ b/selfdrive/car/hyundai/radar_interface.py @@ -37,7 +37,7 @@ class RadarInterface(RadarInterfaceBase): self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1 self.track_id = 0 - self.radar_off_can = CP.radarOffCan + self.radar_off_can = CP.radarUnavailable self.rcp = get_radar_can_parser(CP) def update(self, can_strings): diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index fdd2439ff9..65444ff6e0 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "mazda" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)] - ret.radarOffCan = True + ret.radarUnavailable = True ret.dashcamOnly = candidate not in (CAR.CX5_2022, CAR.CX9_2021) diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 386e859089..2e769cf662 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -19,7 +19,7 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 17 ret.steerControlType = car.CarParams.SteerControlType.angle - ret.radarOffCan = True + ret.radarUnavailable = True if candidate in (CAR.ROGUE, CAR.XTRAIL): ret.mass = 1610 + STD_CARGO_KG diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 22468801ec..f94333baab 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "subaru" - ret.radarOffCan = True + ret.radarUnavailable = True ret.dashcamOnly = candidate in PREGLOBAL_CARS ret.autoResumeSng = False diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index deb0454b9c..24c995a2d0 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -76,7 +76,7 @@ class TestCarInterfaces(unittest.TestCase): # Run radar interface once radar_interface.update([]) - if not car_params.radarOffCan and radar_interface.rcp is not None and \ + if not car_params.radarUnavailable and radar_interface.rcp is not None and \ hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): radar_interface._update([radar_interface.trigger_msg]) diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index b979a96d70..1e620b4f73 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -23,7 +23,7 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "volkswagen" - ret.radarOffCan = True + ret.radarUnavailable = True use_off_car_defaults = len(fingerprint[0]) == 0 # Pick sensible carParams during offline doc generation/CI jobs diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 606dcad9c4..b531cb3430 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -204,7 +204,7 @@ def controlsd_rcv_callback(msg, CP, cfg, fsm): def radar_rcv_callback(msg, CP, cfg, fsm): if msg.which() != "can": return [], False - elif CP.radarOffCan: + elif CP.radarUnavailable: return ["radarState", "liveTracks"], True radar_msgs = {"honda": [0x445], "toyota": [0x19f, 0x22f], "gm": [0x474], From 4fd15096979675379b7f99320bb6fe187f9bcf6b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 2 Feb 2023 12:48:57 -0800 Subject: [PATCH 0809/1179] Ford: restore radar DBC, check radarUnavailable (#27188) --- selfdrive/car/ford/radar_interface.py | 2 +- selfdrive/car/ford/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py index c942703002..ee4efb311d 100644 --- a/selfdrive/car/ford/radar_interface.py +++ b/selfdrive/car/ford/radar_interface.py @@ -47,7 +47,7 @@ class RadarInterface(RadarInterfaceBase): self.updated_messages = set() self.track_id = 0 self.radar = DBC[CP.carFingerprint]['radar'] - if self.radar is None: + if self.radar is None or CP.radarUnavailable: self.rcp = None elif self.radar == RADAR.DELPHI_ESR: self.rcp = _create_delphi_esr_radar_can_parser() diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 4cabdb11e1..3723fe1d4a 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -60,7 +60,7 @@ class RADAR: DELPHI_MRR = 'FORD_CADS' -DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", None)) +DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base_pt", RADAR.DELPHI_MRR)) @dataclass From cb50244a89fde385f55b2f6ad3ecd83c9b8f5c3a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 2 Feb 2023 13:03:53 -0800 Subject: [PATCH 0810/1179] Bump total scons nodes --- selfdrive/manager/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/build.py b/selfdrive/manager/build.py index c8a7d41539..5b69e3dca7 100755 --- a/selfdrive/manager/build.py +++ b/selfdrive/manager/build.py @@ -15,7 +15,7 @@ from system.version import is_dirty MAX_CACHE_SIZE = 4e9 if "CI" in os.environ else 2e9 CACHE_DIR = Path("/data/scons_cache" if AGNOS else "/tmp/scons_cache") -TOTAL_SCONS_NODES = 2395 +TOTAL_SCONS_NODES = 2460 MAX_BUILD_PROGRESS = 100 PREBUILT = os.path.exists(os.path.join(BASEDIR, 'prebuilt')) From 6b04ead6dd8fc89540c9d0000a2aa262c6b420e1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Feb 2023 05:14:36 +0800 Subject: [PATCH 0811/1179] cabana: remove the hardcoded width for columns (#27185) --- tools/cabana/messageswidget.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 0526ff141f..9011ce0a4d 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -26,9 +26,6 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget->setSelectionMode(QAbstractItemView::SingleSelection); table_widget->setSortingEnabled(true); table_widget->sortByColumn(0, Qt::AscendingOrder); - table_widget->setColumnWidth(0, 250); - table_widget->setColumnWidth(1, 80); - table_widget->setColumnWidth(2, 80); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); From 628b80de3d1ac9b5556fcd4c60818d99b4b76af9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Feb 2023 05:14:53 +0800 Subject: [PATCH 0812/1179] cabana: improve line marker (#27189) --- tools/cabana/chartswidget.cc | 42 ++++++++++++++++++++---------------- tools/cabana/chartswidget.h | 2 +- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index b49b20f2cc..ca56b5810e 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -589,7 +589,7 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) { } void ChartView::leaveEvent(QEvent *event) { - track_pt = {0, 0}; + track_pts.clear(); scene()->update(); QChartView::leaveEvent(event); } @@ -639,27 +639,26 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); const auto plot_area = chart()->plotArea(); - track_pt = {0, 0}; + track_pts.clear(); if (!is_zooming && plot_area.contains(ev->pos())) { + track_pts.resize(sigs.size()); QStringList text_list; const double sec = chart()->mapToValue(ev->pos()).x(); - for (auto &s : sigs) { + for (int i = 0; i < sigs.size(); ++i) { QString value = "--"; // use reverse iterator to find last item <= sec. - auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); - if (it != s.vals.rend() && it->x() >= axis_x->min()) { + auto it = std::lower_bound(sigs[i].vals.rbegin(), sigs[i].vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); + if (it != sigs[i].vals.rend() && it->x() >= axis_x->min()) { value = QString::number(it->y()); - auto value_pos = chart()->mapToPosition(*it); - if (value_pos.x() > track_pt.x()) track_pt = value_pos; + track_pts[i] = chart()->mapToPosition(*it); } - text_list.push_back(QString("%2: %3").arg(s.series->color().name(), s.sig->name.c_str(), value)); + text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name.c_str(), value)); } - if (track_pt.x() == 0) track_pt = ev->pos(); - QString text = QString("%1
%2") - .arg(chart()->mapToValue(track_pt).x(), 0, 'f', 3) - .arg(text_list.join("
")); - QPoint pt((int)track_pt.x() + 20, plot_area.top() - 20); - QToolTip::showText(mapToGlobal(pt), text, this, plot_area.toRect()); + auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); + auto pt = (max == track_pts.end()) ? ev->pos() : *max; + text_list.push_front(QString::number(chart()->mapToValue(pt).x(), 'f', 3)); + QPointF tooltip_pt(pt.x() + 12, plot_area.top() - 20); + QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), pt.isNull() ? "" : text_list.join("
"), this, plot_area.toRect()); scene()->update(); } else { QToolTip::hideText(); @@ -712,11 +711,18 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { qreal y2 = chart()->plotArea().bottom() + 2; painter->setPen(QPen(chart()->titleBrush().color(), 2)); painter->drawLine(QPointF{x, y1}, QPointF{x, y2}); - if (!track_pt.isNull()) { + + auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); + if (max != track_pts.end() && !max->isNull()) { painter->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); - painter->drawLine(QPointF{track_pt.x(), y1}, QPointF{track_pt.x(), y2}); - painter->setBrush(Qt::darkGray); - painter->drawEllipse(track_pt, 5, 5); + painter->drawLine(QPointF{max->x(), y1}, QPointF{max->x(), y2}); + painter->setPen(Qt::NoPen); + for (int i = 0; i < track_pts.size(); ++i) { + if (!track_pts[i].isNull() && i < sigs.size()) { + painter->setBrush(sigs[i].series->color().darker(125)); + painter->drawEllipse(track_pts[i], 5.5, 5.5); + } + } } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index d5572756c1..41b2ddffcc 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -73,7 +73,7 @@ private: QValueAxis *axis_x; QValueAxis *axis_y; - QPointF track_pt; + QVector track_pts; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; QList sigs; From 9ece098098d571224ebf0a5b75e069416ca9d7f3 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 2 Feb 2023 22:15:11 +0100 Subject: [PATCH 0813/1179] cabana: do not round time when seeking from chartswidget (#27141) * cabana: do not round time when seeking from chartswidget * prevent zooming/seeking past end of route --- tools/cabana/chartswidget.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index ca56b5810e..f0a81fe65d 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -617,14 +617,21 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && rubber && rubber->isVisible()) { rubber->hide(); QRectF rect = rubber->geometry().normalized(); - double min = std::floor(chart()->mapToValue(rect.topLeft()).x() * 10.0) / 10.0; - double max = std::floor(chart()->mapToValue(rect.bottomRight()).x() * 10.0) / 10.0; + double min = chart()->mapToValue(rect.topLeft()).x(); + double max = chart()->mapToValue(rect.bottomRight()).x(); + + // Prevent zooming/seeking past the end of the route + min = std::clamp(min, can->routeStartTime(), can->routeStartTime() + can->totalSeconds()); + max = std::clamp(max, can->routeStartTime(), can->routeStartTime() + can->totalSeconds()); + + double min_rounded = std::floor(min * 10.0) / 10.0; + double max_rounded = std::floor(max * 10.0) / 10.0; if (rubber->width() <= 0) { // no rubber dragged, seek to mouse position can->seekTo(min); - } else if ((max - min) >= 0.5) { + } else if ((max_rounded - min_rounded) >= 0.5) { // zoom in if selected range is greater than 0.5s - emit zoomIn(min, max); + emit zoomIn(min_rounded, max_rounded); } event->accept(); } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { From e3c202b4a2d79f6843aa54ec9a1ef81e39da2731 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 2 Feb 2023 22:16:09 +0100 Subject: [PATCH 0814/1179] cabana: add button to suppress highlighted bytes (#27131) --- tools/cabana/historylog.cc | 8 +-- tools/cabana/historylog.h | 2 +- tools/cabana/messageswidget.cc | 69 +++++++++++++++++++++++--- tools/cabana/messageswidget.h | 10 +++- tools/cabana/streams/abstractstream.cc | 6 ++- tools/cabana/streams/abstractstream.h | 1 + tools/cabana/util.cc | 7 ++- tools/cabana/util.h | 13 ++--- 8 files changed, 93 insertions(+), 23 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 830390f4a8..ab5c6cbbe0 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -17,7 +17,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { } return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { - return HexColors::toVariantList(m.colors); + return ChangeTracker::toVariantList(m.colors); } return {}; } @@ -142,7 +142,8 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti auto msgs = fetchData(first, events->rend(), min_time); if (update_colors && min_time > 0) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { - it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + it->colors = hex_colors.colors; } } return msgs; @@ -152,7 +153,8 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti auto msgs = fetchData(first, events->end(), 0); if (update_colors) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { - it->colors = hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); + it->colors = hex_colors.colors; } } return msgs; diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index bc2e0e3914..2458fc1c31 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -53,7 +53,7 @@ public: std::deque fetchData(uint64_t from_time, uint64_t min_time = 0); QString msg_id; - HexColors hex_colors; + ChangeTracker hex_colors; bool has_more_data = true; const int batch_size = 50; int filter_sig_idx = -1; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 9011ce0a4d..64f56ae73f 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -1,10 +1,12 @@ #include "tools/cabana/messageswidget.h" -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include "tools/cabana/dbcmanager.h" @@ -28,9 +30,16 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget->sortByColumn(0, Qt::AscendingOrder); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); - main_layout->addWidget(table_widget); + // suppress + QHBoxLayout *suppress_layout = new QHBoxLayout(); + suppress_add = new QPushButton("Suppress Highlighted"); + suppress_clear = new QPushButton(); + suppress_layout->addWidget(suppress_add); + suppress_layout->addWidget(suppress_clear); + main_layout->addLayout(suppress_layout); + // signals/slots QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); @@ -46,6 +55,16 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { } } }); + QObject::connect(suppress_add, &QPushButton::clicked, [=]() { + model->suppress(); + updateSuppressedButtons(); + }); + QObject::connect(suppress_clear, &QPushButton::clicked, [=]() { + model->clearSuppress(); + updateSuppressedButtons(); + }); + + updateSuppressedButtons(); } void MessagesWidget::selectMessage(const QString &msg_id) { @@ -54,6 +73,17 @@ void MessagesWidget::selectMessage(const QString &msg_id) { } } +void MessagesWidget::updateSuppressedButtons() { + if (model->suppressed_bytes.empty()) { + suppress_clear->setEnabled(false); + suppress_clear->setText("Clear Suppressed"); + } else { + suppress_clear->setEnabled(true); + suppress_clear->setText(QString("Clear Suppressed (%1)").arg(model->suppressed_bytes.size())); + } +} + + // MessageListModel QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -75,7 +105,16 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { case 4: return toHex(can_data.dat); } } else if (role == Qt::UserRole && index.column() == 4) { - return HexColors::toVariantList(can_data.colors); + QList colors; + for (int i = 0; i < can_data.dat.size(); i++){ + if (suppressed_bytes.contains({id, i})) { + colors.append(QColor(255, 255, 255, 0)); + } else { + colors.append(can_data.colors[i]); + } + } + return colors; + } return {}; } @@ -157,3 +196,21 @@ void MessageListModel::sort(int column, Qt::SortOrder order) { sortMessages(); } } + +void MessageListModel::suppress() { + const double cur_ts = can->currentSec(); + + for (auto &id : msgs) { + auto &can_data = can->lastMessage(id); + for (int i = 0; i < can_data.dat.size(); i++) { + const double dt = cur_ts - can_data.last_change_t[i]; + if (dt < 2.0) { + suppressed_bytes.insert({id, i}); + } + } + } +} + +void MessageListModel::clearSuppress() { + suppressed_bytes.clear(); +} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 69fdd26170..1927faa646 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -2,8 +2,9 @@ #include #include -#include +#include #include +#include #include "tools/cabana/streams/abstractstream.h" @@ -20,7 +21,10 @@ public: void setFilterString(const QString &string); void msgsReceived(const QHash *new_msgs = nullptr); void sortMessages(); + void suppress(); + void clearSuppress(); QStringList msgs; + QSet> suppressed_bytes; private: QString filter_str; @@ -36,6 +40,7 @@ public: void selectMessage(const QString &message_id); QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); } bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); } + void updateSuppressedButtons(); signals: void msgSelectionChanged(const QString &message_id); @@ -44,4 +49,7 @@ protected: QTableView *table_widget; QString current_msg_id; MessageListModel *model; + QPushButton *suppress_add; + QPushButton *suppress_clear; + }; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index b188c41826..308e5556c6 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -19,7 +19,7 @@ void AbstractStream::process(QHash *messages) { bool AbstractStream::updateEvent(const Event *event) { static std::unique_ptr new_msgs = std::make_unique>(); - static QHash hex_colors; + static QHash change_trackers; static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { @@ -42,7 +42,9 @@ bool AbstractStream::updateEvent(const Event *event) { if (double delta = (current_sec - counters_begin_sec); delta > 0) { data.freq = data.count / delta; } - data.colors = hex_colors[id].compute(data.dat, data.ts, data.freq); + change_trackers[id].compute(data.dat, data.ts, data.freq); + data.colors = change_trackers[id].colors; + data.last_change_t = change_trackers[id].last_change_t; } double ts = millis_since_boot(); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 9a0187da5e..e16e11a14b 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -17,6 +17,7 @@ struct CanData { uint32_t freq = 0; QByteArray dat; QVector colors; + QVector last_change_t; }; class AbstractStream : public QObject { diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 699aa7dc01..f9d19dfda3 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -10,7 +10,7 @@ static QColor blend(QColor a, QColor b) { return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2, (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); } -const QVector &HexColors::compute(const QByteArray &dat, double ts, uint32_t freq) { +void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { if (prev_dat.size() != dat.size()) { colors.resize(dat.size()); last_change_t.resize(dat.size()); @@ -45,16 +45,15 @@ const QVector &HexColors::compute(const QByteArray &dat, double ts, uint } prev_dat = dat; - return colors; } -void HexColors::clear() { +void ChangeTracker::clear() { prev_dat.clear(); last_change_t.clear(); colors.clear(); } -QList HexColors::toVariantList(const QVector &colors) { +QList ChangeTracker::toVariantList(const QVector &colors) { QList ret; ret.reserve(colors.size()); for (auto &c : colors) ret.append(c); diff --git a/tools/cabana/util.h b/tools/cabana/util.h index a598726bb6..b76652f4b0 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -7,19 +7,20 @@ #include #include -class HexColors { +class ChangeTracker { public: - const QVector &compute(const QByteArray &dat, double ts, uint32_t freq); - static QList toVariantList(const QVector &colors); - void clear(); + void compute(const QByteArray &dat, double ts, uint32_t freq); + static QList toVariantList(const QVector &colors); + void clear(); + + QVector last_change_t; + QVector colors; private: const int periodic_threshold = 10; const int start_alpha = 128; const float fade_time = 2.0; QByteArray prev_dat; - QVector last_change_t; - QVector colors; }; class MessageBytesDelegate : public QStyledItemDelegate { From 53396076dfaa857da735d9943fc7e33cefdadf69 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Feb 2023 05:16:32 +0800 Subject: [PATCH 0815/1179] cabana: add capability for switching between line and scatter plots (#27169) * add capability for switching between line and scatter plots * Update tools/cabana/chartswidget.cc Co-authored-by: Willem Melching * setUserOpengl in createSeries * update series title * set marker size by pixels_per_point * sync menu state * cleanup * set default series type in settings dlg * remove qdebug --------- Co-authored-by: Willem Melching --- tools/cabana/chartswidget.cc | 84 +++++++++++++++++++++++++++++------- tools/cabana/chartswidget.h | 8 +++- tools/cabana/settings.cc | 8 ++++ tools/cabana/settings.h | 2 + 4 files changed, 86 insertions(+), 16 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index f0a81fe65d..e49d28db44 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -178,6 +179,7 @@ void ChartsWidget::settingChanged() { range_slider->setRange(1, settings.max_cached_minutes * 60); for (auto c : charts) { c->setFixedHeight(settings.chart_height); + c->setSeriesType(settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter); } } @@ -297,6 +299,8 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { // ChartView ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { + series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; + QChart *chart = new QChart(); chart->setBackgroundRoundness(0); axis_x = new QValueAxis(this); @@ -317,9 +321,20 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { close_btn_proxy->setZValue(chart->zValue() + 11); QToolButton *manage_btn = new QToolButton(); + manage_btn->setToolButtonStyle(Qt::ToolButtonIconOnly); manage_btn->setIcon(utils::icon("gear")); manage_btn->setAutoRaise(true); - manage_btn->setToolTip(tr("Manage series")); + QMenu *menu = new QMenu(this); + line_series_action = menu->addAction(tr("Line"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeLine); }); + line_series_action->setCheckable(true); + line_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeLine); + scatter_series_action = menu->addAction(tr("Scatter"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeScatter); }); + scatter_series_action->setCheckable(true); + scatter_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeScatter); + menu->addSeparator(); + menu->addAction(tr("Manage series"), this, &ChartView::manageSeries); + manage_btn->setMenu(menu); + manage_btn->setPopupMode(QToolButton::InstantPopup); manage_btn_proxy = new QGraphicsProxyWidget(chart); manage_btn_proxy->setWidget(manage_btn); manage_btn_proxy->setZValue(chart->zValue() + 11); @@ -334,7 +349,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(dbc(), &DBCManager::msgRemoved, this, &ChartView::msgRemoved); QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated); QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); - QObject::connect(manage_btn, &QToolButton::clicked, this, &ChartView::manageSeries); } qreal ChartView::getYAsixLabelWidth() const { @@ -354,8 +368,7 @@ void ChartView::setPlotAreaLeftPosition(int pos) { } void ChartView::addSeries(const QString &msg_id, const Signal *sig) { - QLineSeries *series = new QLineSeries(this); - + QXYSeries *series = createSeries(series_type); chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); @@ -478,22 +491,26 @@ void ChartView::updatePlot(double cur, double min, double max) { int num_points = std::max(end - begin, 1); int pixels_per_point = width() / num_points; - s.series->setPointsVisible(pixels_per_point > 20); + if (series_type == QAbstractSeries::SeriesTypeScatter) { + ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8)); + } else { + s.series->setPointsVisible(pixels_per_point > 20); - // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs. + // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs. #ifndef __APPLE - // OpenGL mode lacks certain features (such as showing points), only use when drawing many points - bool use_opengl = pixels_per_point < 1; - s.series->setUseOpenGL(use_opengl); + // OpenGL mode lacks certain features (such as showing points), only use when drawing many points + bool use_opengl = pixels_per_point < 1; + s.series->setUseOpenGL(use_opengl); - // Qt doesn't properly apply device pixel ratio in OpenGL mode - QApplication* application = static_cast(QApplication::instance()); - float scale = use_opengl ? application->devicePixelRatio() : 1.0; + // Qt doesn't properly apply device pixel ratio in OpenGL mode + QApplication *application = static_cast(QApplication::instance()); + float scale = use_opengl ? application->devicePixelRatio() : 1.0; - QPen pen = s.series->pen(); - pen.setWidth(2.0 * scale); - s.series->setPen(pen); + QPen pen = s.series->pen(); + pen.setWidth(2.0 * scale); + s.series->setPen(pen); #endif + } } } @@ -733,6 +750,43 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } +QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type) { + QXYSeries *series = nullptr; + if (type == QAbstractSeries::SeriesTypeLine) { + series = new QLineSeries(this); + } else { + series = new QScatterSeries(this); + } + // TODO: Due to a bug in CameraWidget the camera frames + // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed +#ifndef __APPLE__ + series->setUseOpenGL(true); +#endif + return series; +} + +void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { + if (type != series_type) { + series_type = type; + line_series_action->setChecked(type == QAbstractSeries::SeriesTypeLine); + scatter_series_action->setChecked(type == QAbstractSeries::SeriesTypeScatter); + + for (auto &s : sigs) { + chart()->removeSeries(s.series); + s.series->deleteLater(); + } + for (auto &s : sigs) { + auto series = createSeries(series_type); + chart()->addSeries(series); + series->attachAxis(axis_x); + series->attachAxis(axis_y); + series->replace(s.vals); + s.series = series; + } + updateTitle(); + } +} + // SeriesSelector SeriesSelector::SeriesSelector(QWidget *parent) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 41b2ddffcc..9b2afd45a9 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "tools/cabana/dbcmanager.h" @@ -30,13 +31,14 @@ public: void updatePlot(double cur, double min, double max); void setPlotAreaLeftPosition(int pos); qreal getYAsixLabelWidth() const; + void setSeriesType(QAbstractSeries::SeriesType type); struct SigItem { QString msg_id; uint8_t source = 0; uint32_t address = 0; const Signal *sig = nullptr; - QLineSeries *series = nullptr; + QXYSeries *series = nullptr; QVector vals; uint64_t last_value_mono_time = 0; }; @@ -70,6 +72,7 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; void applyNiceNumbers(qreal min, qreal max); qreal niceNumber(qreal x, bool ceiling); + QXYSeries *createSeries(QAbstractSeries::SeriesType type); QValueAxis *axis_x; QValueAxis *axis_y; @@ -79,6 +82,9 @@ private: QList sigs; double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; + QAbstractSeries::SeriesType series_type = QAbstractSeries::SeriesTypeLine; + QAction *line_series_action; + QAction *scatter_series_action; }; class ChartsWidget : public QWidget { diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 78969c76c3..22c7a941ab 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -25,6 +25,7 @@ void Settings::save() { s.setValue("video_splitter_state", video_splitter_state); s.setValue("recent_files", recent_files); s.setValue("message_header_state", message_header_state); + s.setValue("chart_series_type", chart_series_type); } void Settings::load() { @@ -40,6 +41,7 @@ void Settings::load() { video_splitter_state = s.value("video_splitter_state").toByteArray(); recent_files = s.value("recent_files").toStringList(); message_header_state = s.value("message_header_state").toByteArray(); + chart_series_type = s.value("chart_series_type", 0).toInt(); } // SettingsDlg @@ -60,6 +62,11 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { cached_minutes->setValue(settings.max_cached_minutes); form_layout->addRow(tr("Max Cached Minutes"), cached_minutes); + chart_series_type = new QComboBox(this); + chart_series_type->addItems({tr("Line"), tr("Scatter")}); + chart_series_type->setCurrentIndex(settings.chart_series_type); + form_layout->addRow(tr("Chart Default Series Type"), chart_series_type); + chart_height = new QSpinBox(this); chart_height->setRange(100, 500); chart_height->setSingleStep(10); @@ -77,6 +84,7 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { void SettingsDlg::save() { settings.fps = fps->value(); settings.max_cached_minutes = cached_minutes->value(); + settings.chart_series_type = chart_series_type->currentIndex(); settings.chart_height = chart_height->value(); settings.save(); accept(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 56c6a992ae..7abad81c29 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -18,6 +18,7 @@ public: int chart_height = 200; int chart_column_count = 1; int chart_range = 3 * 60; // e minutes + int chart_series_type = 0; QString last_dir; QByteArray geometry; QByteArray video_splitter_state; @@ -38,6 +39,7 @@ public: QSpinBox *fps; QSpinBox *cached_minutes; QSpinBox *chart_height; + QComboBox *chart_series_type; }; extern Settings settings; From 444df54a70c8d0fb31c1a2474053c862e4efb61b Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Feb 2023 13:46:44 -0800 Subject: [PATCH 0816/1179] Chrysler: disable radar parsing (#27190) * Chrysler: disable radar parsing * update refs --- selfdrive/car/chrysler/interface.py | 4 ++-- selfdrive/car/chrysler/radar_interface.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 99f1692daa..da086105e3 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from selfdrive.car import STD_CARGO_KG, get_safety_config -from selfdrive.car.chrysler.values import CAR, DBC, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags +from selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags from selfdrive.car.interfaces import CarInterfaceBase @@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "chrysler" ret.dashcamOnly = candidate in RAM_HD - ret.radarUnavailable = DBC[candidate]['radar'] is None + ret.radarUnavailable = True # DBC[candidate]['radar'] is None ret.steerActuatorDelay = 0.1 ret.steerLimitTimer = 0.4 diff --git a/selfdrive/car/chrysler/radar_interface.py b/selfdrive/car/chrysler/radar_interface.py index 348e3c3632..0ab8c10b44 100755 --- a/selfdrive/car/chrysler/radar_interface.py +++ b/selfdrive/car/chrysler/radar_interface.py @@ -45,12 +45,13 @@ def _address_to_track(address): class RadarInterface(RadarInterfaceBase): def __init__(self, CP): super().__init__(CP) + self.CP = CP self.rcp = _create_radar_can_parser(CP.carFingerprint) self.updated_messages = set() self.trigger_msg = LAST_MSG def update(self, can_strings): - if self.rcp is None: + if self.rcp is None or self.CP.radarUnavailable: return super().update(None) vls = self.rcp.update_strings(can_strings) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a6c8aa682d..c49ed64c65 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -e825c953316277a342284a1f10b8dab88e95fc31 \ No newline at end of file +78f00e30719a6af9644b2cbd0c76d2e652e95ccd \ No newline at end of file From 20fb2b9bb3f06187665928eda6e740db29b45e5b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 2 Feb 2023 14:28:45 -0800 Subject: [PATCH 0817/1179] ui: tap experimental mode icon to toggle (#27064) * ui: tap experimental mode icon to toggle After experimental mode has been enabled for the first time (confirmed), it can be toggled by tapping the engage-ability/experimental mode icon in the upper right. Closes #27002 * replace with QPushButton * fixes * cleanup --- selfdrive/ui/qt/onroad.cc | 72 ++++++++++++++++++++++++++++++++------- selfdrive/ui/qt/onroad.h | 29 ++++++++++++---- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 1b4b880fbf..7a4b4240c3 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -175,11 +175,62 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { } +ExperimentalButton::ExperimentalButton(QWidget *parent) : QPushButton(parent) { + setVisible(false); + setFixedSize(btn_size, btn_size); + setCheckable(true); + + params = Params(); + engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size}); + experimental_img = loadPixmap("../assets/img_experimental.svg", {img_size, img_size}); + + QObject::connect(this, &QPushButton::toggled, [=](bool checked) { + params.putBool("ExperimentalMode", checked); + }); +} + +void ExperimentalButton::updateState(const UIState &s) { + const SubMaster &sm = *(s.sm); + + // button is "visible" if engageable or enabled + const auto cs = sm["controlsState"].getControlsState(); + setVisible(cs.getEngageable() || cs.getEnabled()); + + // button is "checked" if experimental mode is enabled + setChecked(sm["controlsState"].getControlsState().getExperimentalMode()); + + // disable button when experimental mode is not available, or has not been confirmed for the first time + const auto cp = sm["carParams"].getCarParams(); + const bool experimental_mode_available = cp.getExperimentalLongitudinalAvailable() ? params.getBool("ExperimentalLongitudinalEnabled") : cp.getOpenpilotLongitudinalControl(); + setEnabled(params.getBool("ExperimentalModeConfirmed") && experimental_mode_available); +} + +void ExperimentalButton::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + + QPoint center(btn_size / 2, btn_size / 2); + QPixmap img = isChecked() ? experimental_img : engage_img; + + p.setOpacity(1.0); + p.setPen(Qt::NoPen); + p.setBrush(QColor(0, 0, 0, 166)); + p.drawEllipse(center, btn_size / 2, btn_size / 2); + p.setOpacity(isDown() ? 0.8 : 1.0); + p.drawPixmap((btn_size - img_size) / 2, (btn_size - img_size) / 2, img); +} + + 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}); - experimental_img = loadPixmap("../assets/img_experimental.svg", {img_size - 5, img_size - 5}); + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setMargin(bdr_s); + main_layout->setSpacing(0); + + experimental_btn = new ExperimentalButton(this); + main_layout->addWidget(experimental_btn, 0, Qt::AlignTop | Qt::AlignRight); + dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size}); } @@ -227,9 +278,11 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { setProperty("hideDM", cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE); setProperty("status", s.status); - // update engageability and DM icons at 2Hz + // update engageability/experimental mode button + experimental_btn->updateState(s); + + // update DM icons at 2Hz if (sm.frame % (UI_FREQ / 2) == 0) { - setProperty("engageable", cs.getEngageable() || cs.getEnabled()); setProperty("dmActive", sm["driverMonitoringState"].getDriverMonitoringState().getIsActiveMode()); setProperty("rightHandDM", sm["driverMonitoringState"].getDriverMonitoringState().getIsRHD()); } @@ -382,16 +435,9 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { configFont(p, "Inter", 66, "Regular"); drawText(p, rect().center().x(), 290, speedUnit, 200); - // engage-ability icon - if (engageable) { - SubMaster &sm = *(uiState()->sm); - drawIcon(p, rect().right() - radius / 2 - bdr_s * 2, radius / 2 + int(bdr_s * 1.5), - sm["controlsState"].getControlsState().getExperimentalMode() ? experimental_img : engage_img, blackColor(166), 1.0); - } - // dm icon if (!hideDM) { - int dm_icon_x = rightHandDM ? rect().right() - radius / 2 - (bdr_s * 2) : radius / 2 + (bdr_s * 2); + int dm_icon_x = rightHandDM ? rect().right() - btn_size / 2 - (bdr_s * 2) : btn_size / 2 + (bdr_s * 2); drawIcon(p, dm_icon_x, rect().bottom() - footer_h / 2, dm_img, blackColor(70), dmActive ? 1.0 : 0.2); } @@ -414,7 +460,7 @@ void AnnotatedCameraWidget::drawIcon(QPainter &p, int x, int y, QPixmap &img, QB p.setOpacity(1.0); // bg dictates opacity of ellipse p.setPen(Qt::NoPen); p.setBrush(bg); - p.drawEllipse(x - radius / 2, y - radius / 2, radius, radius); + p.drawEllipse(x - btn_size / 2, y - btn_size / 2, btn_size, btn_size); p.setOpacity(opacity); p.drawPixmap(x - img.size().width() / 2, y - img.size().height() / 2, img); } diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 3dbb05b674..73c2e03795 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -1,11 +1,16 @@ #pragma once +#include #include #include #include "common/util.h" -#include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/widgets/cameraview.h" + + +const int btn_size = 192; +const int img_size = (btn_size / 4) * 3; // ***** onroad widgets ***** @@ -24,6 +29,21 @@ private: Alert alert = {}; }; +class ExperimentalButton : public QPushButton { + Q_OBJECT + +public: + explicit ExperimentalButton(QWidget *parent = 0); + void updateState(const UIState &s); + +private: + void paintEvent(QPaintEvent *event) override; + + Params params; + QPixmap engage_img; + QPixmap experimental_img; +}; + // container window for the NVG UI class AnnotatedCameraWidget : public CameraWidget { Q_OBJECT @@ -36,7 +56,6 @@ class AnnotatedCameraWidget : public CameraWidget { Q_PROPERTY(bool has_us_speed_limit MEMBER has_us_speed_limit); Q_PROPERTY(bool is_metric MEMBER is_metric); - Q_PROPERTY(bool engageable MEMBER engageable); Q_PROPERTY(bool dmActive MEMBER dmActive); Q_PROPERTY(bool hideDM MEMBER hideDM); Q_PROPERTY(bool rightHandDM MEMBER rightHandDM); @@ -50,18 +69,14 @@ private: void drawIcon(QPainter &p, int x, int y, QPixmap &img, QBrush bg, float opacity); void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); - QPixmap engage_img; - QPixmap experimental_img; + ExperimentalButton *experimental_btn; QPixmap dm_img; - const int radius = 192; - const int img_size = (radius / 2) * 1.5; float speed; QString speedUnit; float setSpeed; float speedLimit; bool is_cruise_set = false; bool is_metric = false; - bool engageable = false; bool dmActive = false; bool hideDM = false; bool rightHandDM = false; From 2ecdb2857e863cb29831f6a9bd4ca3359dce63af Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Feb 2023 15:30:52 -0800 Subject: [PATCH 0818/1179] loggerd: rotate if segment length is >20% longer than expected (#27193) * loggerd: rotate if segment length is >20% expected * add that back * comment --------- Co-authored-by: Comma Device --- selfdrive/loggerd/loggerd.cc | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index 9beb3c3bf1..e09cdfaa9e 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -24,15 +24,25 @@ void logger_rotate(LoggerdState *s) { } void rotate_if_needed(LoggerdState *s) { - if (s->ready_to_rotate == s->max_waiting) { - logger_rotate(s); + // all encoders ready, trigger rotation + bool all_ready = s->ready_to_rotate == s->max_waiting; + + // fallback logic to prevent extremely long segments in the case of camera, encoder, etc. malfunctions + bool timed_out = false; + double tms = millis_since_boot(); + double seg_length_secs = (tms - s->last_rotate_tms) / 1000.; + if ((seg_length_secs > SEGMENT_LENGTH) && !LOGGERD_TEST) { + // TODO: might be nice to put these reasons in the sentinel + if ((tms - s->last_camera_seen_tms) > NO_CAMERA_PATIENCE) { + timed_out = true; + LOGE("no camera packets seen. auto rotating"); + } else if (seg_length_secs > SEGMENT_LENGTH*1.2) { + timed_out = true; + LOGE("segment too long. auto rotating"); + } } - double tms = millis_since_boot(); - if ((tms - s->last_rotate_tms) > SEGMENT_LENGTH * 1000 && - (tms - s->last_camera_seen_tms) > NO_CAMERA_PATIENCE && - !LOGGERD_TEST) { - LOGW("no camera packet seen. auto rotating"); + if (all_ready || timed_out) { logger_rotate(s); } } From b3b35b23fab832781bcf4f34d218ecc0b07c67fb Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 2 Feb 2023 17:12:13 -0800 Subject: [PATCH 0819/1179] controlsd: don't show steer saturated if recently overriding (#27191) * controlsd: don't show steer saturated if recently overriding * 2s * update refs --- selfdrive/controls/controlsd.py | 46 +++++++++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 21d8fe2d66..fff6bcf576 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -173,6 +173,7 @@ class Controls: self.cruise_mismatch_counter = 0 self.can_rcv_timeout_counter = 0 self.last_blinker_frame = 0 + self.last_steering_pressed_frame = 0 self.distance_traveled = 0 self.last_functional_fan_frame = 0 self.events_prev = [] @@ -623,29 +624,34 @@ class Controls: lac_log.output = actuators.steer lac_log.saturated = abs(actuators.steer) >= 0.9 + if CS.steeringPressed: + self.last_steering_pressed_frame = self.sm.frame + recent_steer_pressed = (self.sm.frame - self.last_steering_pressed_frame)*DT_CTRL < 2.0 + # Send a "steering required alert" if saturation count has reached the limit - if lac_log.active and not CS.steeringPressed and self.CP.lateralTuning.which() == 'torque' and not self.joystick_mode: - undershooting = abs(lac_log.desiredLateralAccel) / abs(1e-3 + lac_log.actualLateralAccel) > 1.2 - turning = abs(lac_log.desiredLateralAccel) > 1.0 - good_speed = CS.vEgo > 5 - max_torque = abs(self.last_actuators.steer) > 0.99 - if undershooting and turning and good_speed and max_torque: - self.events.add(EventName.steerSaturated) - elif lac_log.active and lac_log.saturated: - dpath_points = lat_plan.dPathPoints - if len(dpath_points): - # Check if we deviated from the path - # TODO use desired vs actual curvature - if self.CP.steerControlType == car.CarParams.SteerControlType.angle: - steering_value = actuators.steeringAngleDeg - else: - steering_value = actuators.steer + if lac_log.active and not recent_steer_pressed: + if self.CP.lateralTuning.which() == 'torque' and not self.joystick_mode: + undershooting = abs(lac_log.desiredLateralAccel) / abs(1e-3 + lac_log.actualLateralAccel) > 1.2 + turning = abs(lac_log.desiredLateralAccel) > 1.0 + good_speed = CS.vEgo > 5 + max_torque = abs(self.last_actuators.steer) > 0.99 + if undershooting and turning and good_speed and max_torque: + lac_log.active and self.events.add(EventName.steerSaturated) + elif lac_log.saturated: + dpath_points = lat_plan.dPathPoints + if len(dpath_points): + # Check if we deviated from the path + # TODO use desired vs actual curvature + if self.CP.steerControlType == car.CarParams.SteerControlType.angle: + steering_value = actuators.steeringAngleDeg + else: + steering_value = actuators.steer - left_deviation = steering_value > 0 and dpath_points[0] < -0.20 - right_deviation = steering_value < 0 and dpath_points[0] > 0.20 + left_deviation = steering_value > 0 and dpath_points[0] < -0.20 + right_deviation = steering_value < 0 and dpath_points[0] > 0.20 - if left_deviation or right_deviation: - self.events.add(EventName.steerSaturated) + if left_deviation or right_deviation: + self.events.add(EventName.steerSaturated) # Ensure no NaNs/Infs for p in ACTUATOR_FIELDS: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c49ed64c65..c787f4be2d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -78f00e30719a6af9644b2cbd0c76d2e652e95ccd \ No newline at end of file +21b29c8a9eb9acd63e91cbda55657afb266a07f9 \ No newline at end of file From 4e27a7f22a94ee5d8afc0476a6781f7e19b6fcf0 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Thu, 2 Feb 2023 20:29:45 -0700 Subject: [PATCH 0820/1179] Glonass support, ubloxd add ephemeris parsing (#27119) * add glonass kaitai parsing * add kaita generated files * remove glonass from build * add string non immediate type * fix kaitai bug * cleanUp * add patch file * fix scons order * make lookup const * remove comments * rename * add to release files * add signs * final ublox parsing * bump cereal * update ref --------- Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/ublox_msg.cc | 152 ++++++++++++++++++++++- selfdrive/locationd/ublox_msg.h | 12 +- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 162 insertions(+), 4 deletions(-) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 127c7e56b6..3ff768ba06 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -65,6 +65,21 @@ inline bool UbloxMsgParser::valid_so_far() { return true; } +inline uint16_t UbloxMsgParser::get_glonass_year(uint8_t N4, uint16_t Nt) { + // convert time to year (conversion from A3.1.3) + int J = 0; + if (1 <= Nt && Nt <= 366) { + J = 1; + } else if (367 <= Nt && Nt <= 731) { + J = 2; + } else if (732 <= Nt && Nt <= 1096) { + J = 3; + } else if (1097 <= Nt && Nt <= 1461) { + J = 4; + } + uint16_t year = 1996 + 4*(N4 -1) + (J - 1); + return year; +} bool UbloxMsgParser::add_data(const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed) { int needed = needed_bytes(); @@ -103,9 +118,9 @@ std::pair> UbloxMsgParser::gen_msg() { switch (ubx_message.msg_type()) { case 0x0107: return {"gpsLocationExternal", gen_nav_pvt(static_cast(body))}; - case 0x0213: + case 0x0213: // UBX-RXM-SFRB (Broadcast Navigation Data Subframe) return {"ubloxGnss", gen_rxm_sfrbx(static_cast(body))}; - case 0x0215: + case 0x0215: // UBX-RXM-RAW (Multi-GNSS Raw Measurement Data) return {"ubloxGnss", gen_rxm_rawx(static_cast(body))}; case 0x0a09: return {"ubloxGnss", gen_mon_hw(static_cast(body))}; @@ -246,11 +261,144 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m return kj::Array(); } +kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_t *msg) { + if (msg->sv_id() == 255) { + // data can be decoded before identifying the SV number, in this case 255 + // is returned, which means "unknown" (ublox p32) + return kj::Array(); + } + + auto body = *msg->body(); + assert(body.size() == 4); + { + std::string string_data; + string_data.reserve(16); + for (uint32_t word : body) { + for (int i = 3; i >= 0; i--) + string_data.push_back(word >> 8*i); + } + + kaitai::kstream stream(string_data); + glonass_t gl_string(&stream); + + int string_number = gl_string.string_number(); + if (string_number > 5 || gl_string.idle_chip()) { + // dont parse non immediate data, idle_chip == 0 + return kj::Array(); + } + + // immediate data is the same within one superframe + if (glonass_superframes[msg->sv_id()] != gl_string.superframe_number()) { + glonass_strings[msg->sv_id()].clear(); + glonass_superframes[msg->sv_id()] = gl_string.superframe_number(); + } + glonass_strings[msg->sv_id()][string_number] = string_data; + } + + // publish if strings 1-5 have been collected + if (glonass_strings[msg->sv_id()].size() != 5) { + return kj::Array(); + } + + MessageBuilder msg_builder; + auto eph = msg_builder.initEvent().initUbloxGnss().initGlonassEphemeris(); + eph.setSvId(msg->sv_id()); + uint16_t current_day = 0; + + // string number 1 + { + kaitai::kstream stream(glonass_strings[msg->sv_id()][1]); + glonass_t gl_stream(&stream); + glonass_t::string_1_t* data = static_cast(gl_stream.data()); + + eph.setP1(data->p1()); + eph.setTk(data->t_k()); + eph.setXVel(data->x_vel() * pow(2, -20)); + eph.setXAccel(data->x_accel() * pow(2, -30)); + eph.setX(data->x() * pow(2, -11)); + } + + // string number 2 + { + kaitai::kstream stream(glonass_strings[msg->sv_id()][2]); + glonass_t gl_stream(&stream); + glonass_t::string_2_t* data = static_cast(gl_stream.data()); + + eph.setSvHealth(data->b_n()>>2); // MSB indicates health + eph.setP2(data->p2()); + eph.setTb(data->t_b()); + eph.setYVel(data->y_vel() * pow(2, -20)); + eph.setYAccel(data->y_accel() * pow(2, -30)); + eph.setY(data->y() * pow(2, -11)); + } + + // string number 3 + { + kaitai::kstream stream(glonass_strings[msg->sv_id()][3]); + glonass_t gl_stream(&stream); + glonass_t::string_3_t* data = static_cast(gl_stream.data()); + + eph.setP3(data->p3()); + eph.setGammaN(data->gamma_n() * pow(2, -40)); + eph.setSvHealth(eph.getSvHealth() | data->l_n()); + eph.setZVel(data->z_vel() * pow(2, -20)); + eph.setZAccel(data->z_accel() * pow(2, -30)); + eph.setZ(data->z() * pow(2, -11)); + } + + // string number 4 + { + kaitai::kstream stream(glonass_strings[msg->sv_id()][4]); + glonass_t gl_stream(&stream); + glonass_t::string_4_t* data = static_cast(gl_stream.data()); + + current_day = data->n_t(); + eph.setTauN(data->tau_n() * pow(2, -30)); + eph.setDeltaTauN(data->delta_tau_n() * pow(2, -30)); + eph.setAge(data->e_n()); + eph.setP4(data->p4()); + eph.setSvURA(glonass_URA_lookup.at(data->f_t())); + if (msg->sv_id() != data->n()) { + LOGE("SV_ID != SLOT_NUMBER: %d %d", msg->sv_id(), data->n()) + } + eph.setSvType(data->m()); + } + + // string number 5 + { + kaitai::kstream stream(glonass_strings[msg->sv_id()][5]); + glonass_t gl_stream(&stream); + glonass_t::string_5_t* data = static_cast(gl_stream.data()); + + // string5 parsing is only needed to get the year, this can be removed and + // the year can be fetched later in laika (note rollovers and leap year) + uint8_t n_4 = data->n_4(); + uint16_t year = get_glonass_year(n_4, current_day); + + uint16_t last_leap_year = 1996 + 4*(n_4-1); + uint16_t days_till_this_year = (year - last_leap_year)*365; + if (days_till_this_year != 0) { + days_till_this_year++; + } + + eph.setYear(year); + eph.setDayInYear(current_day - days_till_this_year); + eph.setHour((eph.getTk()>>7) & 0x1F); + eph.setMinute((eph.getTk()>>1) & 0x3F); + eph.setSecond((eph.getTk() & 0x1) * 30); + } + + glonass_strings[msg->sv_id()].clear(); + return capnp::messageToFlatArray(msg_builder); +} + kj::Array UbloxMsgParser::gen_rxm_sfrbx(ubx_t::rxm_sfrbx_t *msg) { switch (msg->gnss_id()) { case ubx_t::gnss_type_t::GNSS_TYPE_GPS: return parse_gps_ephemeris(msg); + case ubx_t::gnss_type_t::GNSS_TYPE_GLONASS: + return parse_glonass_ephemeris(msg); default: return kj::Array(); } diff --git a/selfdrive/locationd/ublox_msg.h b/selfdrive/locationd/ublox_msg.h index f031313168..6988f20b74 100644 --- a/selfdrive/locationd/ublox_msg.h +++ b/selfdrive/locationd/ublox_msg.h @@ -10,6 +10,7 @@ #include "cereal/messaging/messaging.h" #include "common/util.h" #include "selfdrive/locationd/generated/gps.h" +#include "selfdrive/locationd/generated/glonass.h" #include "selfdrive/locationd/generated/ubx.h" using namespace std::string_literals; @@ -101,13 +102,22 @@ class UbloxMsgParser { inline bool valid_cheksum(); inline bool valid(); inline bool valid_so_far(); + inline uint16_t get_glonass_year(uint8_t N4, uint16_t Nt); kj::Array parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg); + kj::Array parse_glonass_ephemeris(ubx_t::rxm_sfrbx_t *msg); std::unordered_map> gps_subframes; size_t bytes_in_parse_buf = 0; uint8_t msg_parse_buf[ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_MAX_MSG_SIZE]; -}; + // user range accuracy in meters + const std::unordered_map glonass_URA_lookup = + {{ 0, 1}, { 1, 2}, { 2, 2.5}, { 3, 4}, { 4, 5}, {5, 7}, + { 6, 10}, { 7, 12}, { 8, 14}, { 9, 16}, {10, 32}, + {11, 64}, {12, 128}, {13, 256}, {14, 512}, {15, 1024}}; + std::unordered_map> glonass_strings; + std::unordered_map glonass_superframes; +}; diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c787f4be2d..68675e7007 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -21b29c8a9eb9acd63e91cbda55657afb266a07f9 \ No newline at end of file +2beed04e654cdf84fac5842869f38c8cd55e9867 \ No newline at end of file From 04a7808590ac55a5e3dea6080b6a24aae78d9277 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Thu, 2 Feb 2023 21:16:28 -0700 Subject: [PATCH 0821/1179] glonass support laikad (#27173) * add glonass kaitai parsing * add kaita generated files * remove glonass from build * add string non immediate type * fix kaitai bug * cleanUp * add patch file * fix scons order * make lookup const * remove comments * add to release files * init * add laika * remove printf * laikad add glonass ephem parsing * add signs * final ublox parsing * rev gps * bump subs * address comments * disable internet for laikad --------- Co-authored-by: Kurt Nistelberger --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/laika_repo b/laika_repo index 2e5c7b8a85..b30afe44d2 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 2e5c7b8a85cbaebda7fa715fe53d5e6ecbd62b0a +Subproject commit b30afe44d283072b6ee0ea17f290cca5d002baf7 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index b8d86c63fd..e85cd0ad42 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -17,7 +17,7 @@ from common.params import Params, put_nonblocking from laika import AstroDog from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed -from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_ephem, parse_qcom_ephem +from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_gps_ephem, convert_ublox_glonass_ephem, parse_qcom_ephem from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom @@ -139,17 +139,22 @@ class Laikad: if self.use_qcom: return gnss_msg.which() == 'drSvPoly' else: - return gnss_msg.which() == 'ephemeris' + return gnss_msg.which() in ('ephemeris', 'glonassEphemeris') def read_ephemeris(self, gnss_msg): - # TODO this only works on GLONASS if self.use_qcom: # TODO this is not robust to gps week rollover if self.gps_week is None: return ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) else: - ephem = convert_ublox_ephem(gnss_msg.ephemeris) + if gnss_msg.which() == 'ephemeris': + ephem = convert_ublox_gps_ephem(gnss_msg.ephemeris) + elif gnss_msg.which() == 'glonassEphemeris': + ephem = convert_ublox_glonass_ephem(gnss_msg.glonassEphemeris) + else: + cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") + return self.astro_dog.add_navs({ephem.prn: [ephem]}) self.cache_ephemeris(t=ephem.epoch) @@ -410,8 +415,13 @@ def main(sm=None, pm=None, qc=None): if pm is None: pm = messaging.PubMaster(['gnssMeasurements']) + # disable until set as main gps source, to better analyze startup time + use_internet = False #"LAIKAD_NO_INTERNET" not in os.environ + replay = "REPLAY" in os.environ - use_internet = "LAIKAD_NO_INTERNET" not in os.environ + if replay or "CI" in os.environ: + use_internet = True + laikad = Laikad(save_ephemeris=not replay, auto_fetch_navs=use_internet, use_qcom=use_qcom) while True: From 41304db1e661fa6593d777f0f17dfd60e6f909c8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Feb 2023 12:39:16 +0800 Subject: [PATCH 0822/1179] cabana: syc the last messages after seeking (#27149) * fix wrong last message time * update last messages after seekto * cleanup * remove src,address from CanData * merge master merge master --- tools/cabana/historylog.cc | 6 +-- tools/cabana/messageswidget.cc | 7 +-- tools/cabana/streams/abstractstream.cc | 64 +++++++++++++++++++------- tools/cabana/streams/abstractstream.h | 10 ++-- tools/cabana/streams/replaystream.cc | 6 --- tools/cabana/streams/replaystream.h | 2 +- tools/replay/replay.cc | 2 +- 7 files changed, 62 insertions(+), 35 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index ab5c6cbbe0..95bd94e76b 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -79,7 +79,7 @@ void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function void HistoryLogModel::updateState() { if (!msg_id.isEmpty()) { - uint64_t current_time = (can->currentSec() + can->routeStartTime()) * 1e9; + uint64_t current_time = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9 + 1; auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); if ((has_more_data = !new_msgs.empty())) { beginInsertRows({}, 0, new_msgs.size() - 1); @@ -109,7 +109,7 @@ std::deque HistoryLogModel::fetchData(InputIt first, I for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - if (src == c.getSrc() && address == c.getAddress()) { + if (address == c.getAddress() && src == c.getSrc()) { const auto dat = c.getDat(); for (int i = 0; i < sigs.size(); ++i) { values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i])); @@ -140,7 +140,7 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti if (dynamic_mode) { auto first = std::upper_bound(events->rbegin(), events->rend(), from_time, [=](uint64_t ts, auto &e) { return e->mono_time < ts; }); auto msgs = fetchData(first, events->rend(), min_time); - if (update_colors && min_time > 0) { + if (update_colors && (min_time > 0 || messages.empty())) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); it->colors = hex_colors.colors; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 64f56ae73f..9d0fc23e4d 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -106,11 +106,12 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } } else if (role == Qt::UserRole && index.column() == 4) { QList colors; + colors.reserve(can_data.dat.size()); for (int i = 0; i < can_data.dat.size(); i++){ if (suppressed_bytes.contains({id, i})) { colors.append(QColor(255, 255, 255, 0)); } else { - colors.append(can_data.colors[i]); + colors.append(i < can_data.colors.size() ? can_data.colors[i] : QColor(255, 255, 255, 0)); } } return colors; @@ -152,8 +153,8 @@ void MessageListModel::sortMessages() { }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - auto ll = std::tuple{can->lastMessage(l).src, can->lastMessage(l).address, l}; - auto rr = std::tuple{can->lastMessage(r).src, can->lastMessage(r).address, r}; + auto ll = DBCManager::parseId(l); + auto rr = DBCManager::parseId(r); return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } else if (sort_column == 2) { diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 308e5556c6..8a77e0eb39 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -4,7 +4,9 @@ AbstractStream *can = nullptr; AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_live_streaming(is_live_streaming), QObject(parent) { can = this; + new_msgs = std::make_unique>(); QObject::connect(this, &AbstractStream::received, this, &AbstractStream::process, Qt::QueuedConnection); + QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); } void AbstractStream::process(QHash *messages) { @@ -18,30 +20,17 @@ void AbstractStream::process(QHash *messages) { } bool AbstractStream::updateEvent(const Event *event) { - static std::unique_ptr new_msgs = std::make_unique>(); - static QHash change_trackers; static double prev_update_ts = 0; if (event->which == cereal::Event::Which::CAN) { - double current_sec = currentSec(); - if (counters_begin_sec == 0 || counters_begin_sec >= current_sec) { - new_msgs->clear(); - counters.clear(); - counters_begin_sec = current_sec; - } - - auto can_events = event->event.getCan(); - for (const auto &c : can_events) { + double current_sec = event->mono_time / 1e9 - routeStartTime(); + for (const auto &c : event->event.getCan()) { QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); CanData &data = (*new_msgs)[id]; data.ts = current_sec; - data.src = c.getSrc(); - data.address = c.getAddress(); data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); data.count = ++counters[id]; - if (double delta = (current_sec - counters_begin_sec); delta > 0) { - data.freq = data.count / delta; - } + data.freq = data.count / std::max(1.0, current_sec); change_trackers[id].compute(data.dat, data.ts, data.freq); data.colors = change_trackers[id].colors; data.last_change_t = change_trackers[id].last_change_t; @@ -60,3 +49,46 @@ bool AbstractStream::updateEvent(const Event *event) { } return true; } + +const CanData &AbstractStream::lastMessage(const QString &id) { + static CanData empty_data; + auto it = can_msgs.find(id); + return it != can_msgs.end() ? it.value() : empty_data; +} + +void AbstractStream::updateLastMsgsTo(double sec) { + QHash, CanData> last_msgs; // Much faster than QHash + last_msgs.reserve(can_msgs.size()); + double route_start_time = routeStartTime(); + uint64_t last_ts = (sec + route_start_time) * 1e9; + auto last = std::upper_bound(events()->rbegin(), events()->rend(), last_ts, [](uint64_t ts, auto &e) { return e->mono_time < ts; }); + for (auto it = last; it != events()->rend(); ++it) { + if ((*it)->which == cereal::Event::Which::CAN) { + for (const auto &c : (*it)->event.getCan()) { + auto &m = last_msgs[{c.getSrc(), c.getAddress()}]; + if (++m.count == 1) { + m.ts = ((*it)->mono_time / 1e9) - route_start_time; + m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); + m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); + m.last_change_t = QVector(m.dat.size(), m.ts); + } else { + m.freq = m.count / std::max(1.0, m.ts); + } + } + } + } + + // it is thread safe to update data here. + // updateEvent will not be called before replayStream::seekedTo return. + new_msgs->clear(); + change_trackers.clear(); + counters.clear(); + can_msgs.clear(); + for (auto it = last_msgs.cbegin(); it != last_msgs.cend(); ++it) { + QString msg_id = QString("%1:%2").arg(it.key().first).arg(it.key().second, 1, 16); + can_msgs[msg_id] = it.value(); + counters[msg_id] = it.value().count; + } + emit updated(); + emit msgsReceived(&can_msgs); +} diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index e16e11a14b..0dbb3d96a6 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -11,8 +11,6 @@ struct CanData { double ts = 0.; - uint8_t src = 0; - uint32_t address = 0; uint32_t count = 0; uint32_t freq = 0; QByteArray dat; @@ -34,7 +32,7 @@ public: virtual double routeStartTime() const { return 0; } virtual double currentSec() const = 0; virtual QDateTime currentDateTime() const { return {}; } - virtual const CanData &lastMessage(const QString &id) { return can_msgs[id]; } + virtual const CanData &lastMessage(const QString &id); virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } virtual const Route *route() const { return nullptr; } virtual const std::vector *events() const = 0; @@ -54,16 +52,18 @@ signals: void received(QHash *); public: - QMap can_msgs; + QHash can_msgs; protected: void process(QHash *); bool updateEvent(const Event *event); + void updateLastMsgsTo(double sec); bool is_live_streaming = false; - std::atomic counters_begin_sec = 0; std::atomic processing = false; QHash counters; + std::unique_ptr> new_msgs; + QHash change_trackers; }; // A global pointer referring to the unique AbstractStream object diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index fd58f7a409..72c4a13048 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -42,12 +42,6 @@ bool ReplayStream::eventFilter(const Event *event) { return true; } -void ReplayStream::seekTo(double ts) { - replay->seekTo(std::max(double(0), ts), false); - counters_begin_sec = 0; - emit updated(); -} - void ReplayStream::pause(bool pause) { replay->pause(pause); emit(pause ? paused() : resume()); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 1688915212..a9a74e33b5 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -12,7 +12,7 @@ public: ~ReplayStream(); bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); bool eventFilter(const Event *event); - void seekTo(double ts) override; + void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); }; inline QString routeName() const override { return replay->route()->name(); } inline QString carFingerprint() const override { return replay->carFingerprint().c_str(); } inline VisionStreamType visionStreamType() const override { return replay->hasFlag(REPLAY_FLAG_ECAM) ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD; } diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 5c90777bbc..178b116a87 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -114,9 +114,9 @@ void Replay::seekTo(double seconds, bool relative) { rInfo("seeking to %d s, segment %d", (int)seconds, seg); current_segment_ = seg; cur_mono_time_ = route_start_ts_ + seconds * 1e9; + emit seekedTo(seconds); return isSegmentMerged(seg); }); - emit seekedTo(seconds); queueSegment(); } From b1e744987f88641577139061a6444b6357f5773a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 2 Feb 2023 22:00:49 -0800 Subject: [PATCH 0823/1179] Ford: add Lincoln Aviator 2021 to Ford Explorer platform (#27095) * add Lincoln Aviator 2021 to Ford Explorer platform Based on the Ford Explorer, the Aviator has very similar firmware versions. Add these to the Explorer platform and create a new CarInfo for the Aviator. f0709d2bc6ca451f|2022-12-10--12-36-59--0 VIN: 5LM5J7XC8MGL09541 * Ford: new gear shifter signal to support Aviator * probably don't need these * don't need to pass None here, it defaults to None * will rename in DBC * bump opendbc * bump process replay ref --- opendbc | 2 +- selfdrive/car/ford/carstate.py | 6 +++--- selfdrive/car/ford/values.py | 8 +++++++- selfdrive/car/interfaces.py | 18 +++++++++--------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/opendbc b/opendbc index d585a9bf29..0b7439f551 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit d585a9bf2908b2c83bf02b567b9e1f5bfc587a01 +Subproject commit 0b7439f551168f202fb033b7e3e177048687e726 diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 215900fef6..f97225e9f2 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -14,7 +14,7 @@ class CarState(CarStateBase): super().__init__(CP) can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) if CP.transmissionType == TransmissionType.automatic: - self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnGear_D_RqDrv"] + self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"] def update(self, cp, cp_cam): ret = car.CarState.new_message() @@ -51,7 +51,7 @@ class CarState(CarStateBase): # gear if self.CP.transmissionType == TransmissionType.automatic: - gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnGear_D_RqDrv"], None) + gear = self.shifter_values.get(cp.vl["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"]) ret.gearShifter = self.parse_gear_shifter(gear) elif self.CP.transmissionType == TransmissionType.manual: ret.clutchPressed = cp.vl["Engine_Clutch_Data"]["CluPdlPos_Pc_Meas"] > 0 @@ -171,7 +171,7 @@ class CarState(CarStateBase): if CP.transmissionType == TransmissionType.automatic: signals += [ - ("TrnGear_D_RqDrv", "Gear_Shift_by_Wire_FD1"), # GWM transmission gear position + ("TrnRng_D_RqGsm", "Gear_Shift_by_Wire_FD1"), # GWM transmission gear position ] checks += [ ("Gear_Shift_by_Wire_FD1", 10), diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 3723fe1d4a..526b74b16c 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -75,7 +75,10 @@ CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { FordCarInfo("Ford Escape 2020-21"), FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"), ], - CAR.EXPLORER_MK6: FordCarInfo("Ford Explorer 2020-22"), + CAR.EXPLORER_MK6: [ + FordCarInfo("Ford Explorer 2020-22"), + FordCarInfo("Lincoln Aviator 2021", "Co-Pilot360 Plus"), + ], CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2019", "Driver Assistance Pack"), CAR.MAVERICK_MK1: FordCarInfo("Ford Maverick 2022", "Co-Pilot360 Assist"), } @@ -165,13 +168,16 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x706, None): [ b'LB5T-14F397-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5T-14F397-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LC5T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7E0, None): [ b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'MB5A-14C204-RC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'NB5A-14C204-HB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.shiftByWire, 0x732, None): [ + b'L1MP-14C561-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-AE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MP-14G395-JB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 7192f5252c..e75067da7e 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -401,15 +401,15 @@ class CarStateBase(ABC): return GearShifter.unknown d: Dict[str, car.CarState.GearShifter] = { - 'P': GearShifter.park, 'PARK': GearShifter.park, - 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, - 'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral, - 'E': GearShifter.eco, 'ECO': GearShifter.eco, - 'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic, - 'D': GearShifter.drive, 'DRIVE': GearShifter.drive, - 'S': GearShifter.sport, 'SPORT': GearShifter.sport, - 'L': GearShifter.low, 'LOW': GearShifter.low, - 'B': GearShifter.brake, 'BRAKE': GearShifter.brake, + 'P': GearShifter.park, 'PARK': GearShifter.park, + 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, + 'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral, + 'E': GearShifter.eco, 'ECO': GearShifter.eco, + 'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic, + 'D': GearShifter.drive, 'DRIVE': GearShifter.drive, + 'S': GearShifter.sport, 'SPORT': GearShifter.sport, + 'L': GearShifter.low, 'LOW': GearShifter.low, + 'B': GearShifter.brake, 'BRAKE': GearShifter.brake, } return d.get(gear.upper(), GearShifter.unknown) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 68675e7007..2c66c7075c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -2beed04e654cdf84fac5842869f38c8cd55e9867 \ No newline at end of file +7c2a98f4a94b6dded6a90d8913ab85a63069c186 \ No newline at end of file From 1816b499c4c55461797d41b8418faeb58d5f7292 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 3 Feb 2023 01:58:29 -0500 Subject: [PATCH 0824/1179] HKG: Car Port for Kia K5 Hybrid 2020 (#26947) * HKG: Car Port for Kia K5 Hybrid 2020 * Add test route (Experimental Mode) * No abs * remove extra trans * move up --------- Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/hyundai/carcontroller.py | 3 ++- selfdrive/car/hyundai/hyundaican.py | 2 +- selfdrive/car/hyundai/interface.py | 2 +- selfdrive/car/hyundai/values.py | 28 +++++++++++++++++++---- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + 8 files changed, 33 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ddb4a036b0..9103fbc4b5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -6,6 +6,7 @@ Version 0.9.1 (2022-12-XX) * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support +* Kia K5 Hybrid 2020 support thanks to sunnyhaibin! * Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! * Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607! diff --git a/docs/CARS.md b/docs/CARS.md index 9a33278d3b..45873c4924 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 232 Supported Cars +# 233 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -100,6 +100,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|EV6 (without HDA II) 2022[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|| |Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| +|Kia|K5 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| |Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index b81c5e3f7d..6f043fddbb 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -181,7 +181,8 @@ class CarController: if self.frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV, CAR.KONA_EV_2022, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022, - CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022): + CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022, + CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020): can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled)) # 5 Hz ACC options diff --git a/selfdrive/car/hyundai/hyundaican.py b/selfdrive/car/hyundai/hyundaican.py index c2ffffbf22..858f3d0876 100644 --- a/selfdrive/car/hyundai/hyundaican.py +++ b/selfdrive/car/hyundai/hyundaican.py @@ -21,7 +21,7 @@ def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, - CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022): + CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020): values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1) values["CF_Lkas_LdwsOpt_USM"] = 2 diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 030c3f1abc..c708e2b78e 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -166,7 +166,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.65 ret.steerRatio = 13.75 tire_stiffness_factor = 0.5 - elif candidate == CAR.KIA_K5_2021: + elif candidate in (CAR.KIA_K5_2021, CAR.KIA_K5_HEV_2020): ret.mass = 3228. * CV.LB_TO_KG ret.wheelbase = 2.85 ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index b355da6cac..1a0c12d2e0 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -96,6 +96,7 @@ class CAR: # Kia KIA_FORTE = "KIA FORTE E 2018 & GT 2021" KIA_K5_2021 = "KIA K5 2021" + KIA_K5_HEV_2020 = "KIA K5 HYBRID 2020" KIA_NIRO_EV = "KIA NIRO EV 2020" KIA_NIRO_PHEV = "KIA NIRO HYBRID 2019" KIA_NIRO_HEV_2021 = "KIA NIRO HYBRID 2021" @@ -192,6 +193,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { # Kia CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", harness=Harness.hyundai_a), + CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020", harness=Harness.hyundai_a), CAR.KIA_NIRO_EV: [ HyundaiCarInfo("Kia Niro EV 2019", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro EV 2020", "All", "https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f), @@ -1148,6 +1150,23 @@ FW_VERSIONS = { b'\xf1\x00bcsh8p54 U913\x00\x00\x00\x00\x00\x00TDL4T16NB05\x94t\x18', ], }, + CAR.KIA_K5_HEV_2020: { + (Ecu.fwdRadar, 0x7D0, None): [ + b'\xf1\x00DLhe SCC FHCUP 1.00 1.02 99110-L7000 ', + ], + (Ecu.eps, 0x7D4, None): [ + b'\xf1\x00DL3 MDPS C 1.00 1.02 56310-L7000 4DLHC102', + ], + (Ecu.fwdCamera, 0x7C4, None): [ + b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.02 99210-L2000 200309', + ], + (Ecu.engine, 0x7E0, None): [ + b'\xf1\x87391162JLA0', + ], + (Ecu.transmission, 0x7E1, None): [ + b'\xf1\x00PSBG2323 E08\x00\x00\x00\x00\x00\x00\x00TDL2H20KA2\xe3\xc6cz', + ], + }, CAR.KONA_EV: { (Ecu.abs, 0x7D1, None): [ b'\xf1\x00OS IEB \r 105\x18\t\x18 58520-K4000', @@ -1608,7 +1627,7 @@ FW_VERSIONS = { } CHECKSUM = { - "crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022], + "crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.KIA_K5_HEV_2020], "6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS], } @@ -1616,10 +1635,10 @@ FEATURES = { # which message has the gear "use_cluster_gears": {CAR.ELANTRA, CAR.KONA}, "use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON}, - "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022}, + "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022, CAR.KIA_K5_HEV_2020}, # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022}, + "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN} @@ -1630,7 +1649,7 @@ CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, C # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } -HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN} # these cars use a different gas signal +HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_K5_HEV_2020} # these cars use a different gas signal EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5, CAR.GENESIS_GV60_EV_1ST_GEN} # these cars require a special panda safety mode due to missing counters and checksums in the messages @@ -1655,6 +1674,7 @@ DBC = { CAR.IONIQ_HEV_2022: dbc_dict('hyundai_kia_generic', None), CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None), CAR.KIA_K5_2021: dbc_dict('hyundai_kia_generic', None), + CAR.KIA_K5_HEV_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.KIA_NIRO_PHEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'), CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None), diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index bcdb00fd60..ce38eeb0de 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -123,6 +123,7 @@ routes = [ CarTestRoute("d545129f3ca90f28|2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # HDA2 CarTestRoute("68d6a96e703c00c9|2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # HDA1 CarTestRoute("007d5e4ad9f86d13|2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021), + CarTestRoute("c58dfc9fc16590e0|2023-01-14--13-51-48", HYUNDAI.KIA_K5_HEV_2020), CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV), CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV), CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 56057dfae0..1ac43efc39 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -37,6 +37,7 @@ HYUNDAI ELANTRA HYBRID 2021: HYUNDAI SONATA 2020 HYUNDAI TUCSON 2019: HYUNDAI SANTA FE 2019 HYUNDAI TUCSON 4TH GEN: HYUNDAI TUCSON HYBRID 4TH GEN HYUNDAI SANTA FE 2022: HYUNDAI SANTA FE HYBRID 2022 +KIA K5 HYBRID 2020: KIA K5 2021 KIA STINGER 2022: KIA STINGER GT2 2018 GENESIS G90 2017: GENESIS G70 2018 GENESIS G80 2017: GENESIS G70 2018 From bd67d0088783d52262f6796060a53a31e393333b Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Fri, 3 Feb 2023 02:08:38 -0500 Subject: [PATCH 0825/1179] Hyundai: Add FW Versions for 2020 Ioniq Plug-in Hybrid (#27196) * Hyundai: Add FW Versions for 2020 Ioniq Plug-in Hybrid * Aha! * Another one * Update selfdrive/car/hyundai/values.py * missing a radar --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 1a0c12d2e0..9c1efa812d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -416,17 +416,18 @@ FW_VERSIONS = { }, CAR.IONIQ_PHEV: { (Ecu.fwdRadar, 0x7d0, None): [ - b'\xf1\000AEhe SCC FHCUP 1.00 1.02 99110-G2100 ', + b'\xf1\x00AEhe SCC FHCUP 1.00 1.02 99110-G2100 ', b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2200 ', b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ', + b'\xf1\x00AEhe SCC F-CUP 1.00 1.02 99110-G2100 ', ], (Ecu.eps, 0x7d4, None): [ - b'\xf1\000AE MDPS C 1.00 1.01 56310/G2510 4APHC101', + b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101', b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101', ], (Ecu.fwdCamera, 0x7c4, None): [ - b'\xf1\000AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819', + b'\xf1\x00AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEP MFC AT EUR RHD 1.00 1.01 95740-G2600 190819', b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2700 201027', ], @@ -439,6 +440,7 @@ FW_VERSIONS = { b'\xf1\x816U3J8051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00', b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt', b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00', + b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL0\x00\x00\x00\x00', ], }, CAR.IONIQ_EV_2020: { From 603e03116e4ef8dac20f0b957c38369f6cad9c7f Mon Sep 17 00:00:00 2001 From: jayvin100 <34394301+jayvin100@users.noreply.github.com> Date: Fri, 3 Feb 2023 15:16:43 +0800 Subject: [PATCH 0826/1179] Add support for Malaysian Civic 2022 (#27126) Co-authored-by: Shane Smiskol --- selfdrive/car/honda/values.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 07eed0cfc2..3d1c006aaa 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1440,6 +1440,7 @@ FW_VERSIONS = { (Ecu.eps, 0x18DA30F1, None): [ b'39990-T39-A130\x00\x00', b'39990-T43-J020\x00\x00', + b'39990-T24-T120\x00\x00', ], (Ecu.gateway, 0x18DAEFF1, None): [ b'38897-T20-A020\x00\x00', @@ -1447,11 +1448,13 @@ FW_VERSIONS = { b'38897-T21-A010\x00\x00', b'38897-T20-A210\x00\x00', b'38897-T20-A310\x00\x00', + b'38897-T24-Z120\x00\x00', ], (Ecu.srs, 0x18DA53F1, None): [ b'77959-T20-A970\x00\x00', b'77959-T47-A940\x00\x00', b'77959-T47-A950\x00\x00', + b'77959-T20-M820\x00\x00', ], (Ecu.combinationMeter, 0x18DA60F1, None): [ b'78108-T21-A220\x00\x00', @@ -1459,22 +1462,26 @@ FW_VERSIONS = { b'78108-T23-A110\x00\x00', b'78108-T21-A230\x00\x00', b'78108-T22-A020\x00\x00', + b'78108-T21-MB10\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36161-T20-A070\x00\x00', b'36161-T20-A080\x00\x00', b'36161-T20-A060\x00\x00', b'36161-T47-A070\x00\x00', + b'36161-T24-T070\x00\x00', ], (Ecu.vsa, 0x18DA28F1, None): [ b'57114-T20-AB40\x00\x00', b'57114-T43-JB30\x00\x00', + b'57114-T24-TB30\x00\x00', ], (Ecu.transmission, 0x18da1ef1, None): [ b'28101-65D-A020\x00\x00', b'28101-65D-A120\x00\x00', b'28101-65H-A020\x00\x00', b'28101-65H-A120\x00\x00', + b'28101-65J-N010\x00\x00', ], (Ecu.programmedFuelInjection, 0x18da10f1, None): [ b'37805-64L-A540\x00\x00', @@ -1482,6 +1489,7 @@ FW_VERSIONS = { b'37805-64S-A720\x00\x00', b'37805-64A-A540\x00\x00', b'37805-64A-A620\x00\x00', + b'37805-64D-P510\x00\x00', ], }, } From a8b43a44c56600d5a003ef1314873a509c165363 Mon Sep 17 00:00:00 2001 From: Jacob Pfeifer Date: Fri, 3 Feb 2023 02:25:51 -0500 Subject: [PATCH 0827/1179] 2020 Hyundai Santa Fe fingerprint update (#27135) * add new transmission fwVersion for 2020 hyundai santa fe * use shorter trans, add missing fw * duplicate --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 9c1efa812d..4c8e924c49 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -686,7 +686,7 @@ FW_VERSIONS = { (Ecu.abs, 0x7d1, None): [ b'\xf1\x00TM ESC \r 100\x18\x031 58910-S2650', b'\xf1\x00TM ESC \r 103\x18\x11\x08 58910-S2650', - b'\xf1\x00TM ESC \r 104\x19\a\b 58910-S2650', + b'\xf1\x00TM ESC \r 104\x19\x07\x08 58910-S2650', b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600', b'\xf1\x00TM ESC \x02 102\x18\x07\x01 58910-S2600', b'\xf1\x00TM ESC \x02 103\x18\x11\x07 58910-S2600', @@ -708,6 +708,7 @@ FW_VERSIONS = { b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00', b'\xf1\x87LBJSGA7082574HG0\x87www\x98\x88\x88\x88\x99\xaa\xb9\x9afw\x86gx\x99\xa7\x89co\xf8\xffvU_\xffR\xaf\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\xa6\xe0\x91', b'\xf1\x87LBKSGA0458404HG0vfvg\x87www\x89\x99\xa8\x99y\xaa\xa7\x9ax\x88\xa7\x88t_\xf9\xff\x86w\x8f\xff\x15x\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\x00\x00\x00', b'\xf1\x87LDJUEA6010814HG1\x87w\x87x\x86gvw\x88\x88\x98\x88gw\x86wx\x88\x97\x88\x85o\xf8\xff\x86f_\xff\xd37\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM4T20NS0\xf8\x19\x92g', From ef95f921d1e3a5f8566ed4820b8ae8ca9b03609e Mon Sep 17 00:00:00 2001 From: Iamz Date: Fri, 3 Feb 2023 14:35:22 +0700 Subject: [PATCH 0828/1179] Added new fingerprint for Toyota Corolla Cross GR Sport (#26693) Co-authored-by: Shane Smiskol --- selfdrive/car/toyota/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 6c2b865982..490c94db75 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -848,6 +848,7 @@ FW_VERSIONS = { b'\x02896630ZR2000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZT8000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x02896630ZT9000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', + b'\x02896630ZZ0000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966312K6000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966312L0000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', b'\x028966312Q3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', @@ -860,6 +861,7 @@ FW_VERSIONS = { b'8965B12361\x00\x00\x00\x00\x00\x00', b'8965B12451\x00\x00\x00\x00\x00\x00', b'8965B16011\x00\x00\x00\x00\x00\x00', + b'8965B16101\x00\x00\x00\x00\x00\x00', b'8965B76012\x00\x00\x00\x00\x00\x00', b'8965B76050\x00\x00\x00\x00\x00\x00', b'\x018965B12350\x00\x00\x00\x00\x00\x00', @@ -907,6 +909,7 @@ FW_VERSIONS = { b'\x028646F1202100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b'\x028646F1202200\x00\x00\x00\x008646G2601500\x00\x00\x00\x00', b'\x028646F1601100\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', + b'\x028646F1601200\x00\x00\x00\x008646G2601400\x00\x00\x00\x00', b"\x028646F1601300\x00\x00\x00\x008646G2601400\x00\x00\x00\x00", b'\x028646F4203400\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', b'\x028646F76020C0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', From 1ace481fa85287cbfb1799bea9d2fd325eaf1ce7 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Feb 2023 02:50:39 +0800 Subject: [PATCH 0829/1179] cabana: elide long signal names (#27202) elide long signal names --- tools/cabana/signaledit.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 7f31293c41..b871ffa21a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -292,7 +292,10 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op font.setBold(true); painter->setFont(font); painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); - painter->drawText(option.rect.adjusted(rc.width() + 9, 0, 0, 0), option.displayAlignment, index.data(Qt::DisplayRole).toString()); + QString text = index.data(Qt::DisplayRole).toString(); + QRect text_rect = option.rect.adjusted(rc.width() + 9, 0, 0, 0); + text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); + painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); } else { QStyledItemDelegate::paint(painter, option, index); From bd66f77a3b5f59c1b0f72a4a655f0ca883b35f11 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Feb 2023 03:40:35 +0800 Subject: [PATCH 0830/1179] cabana: fix chart buttons occasionally did not respond to click. (#27198) * fix btn not responding on click * change icon from gear to list(menu) --- tools/cabana/chartswidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index e49d28db44..1b8ce657a6 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -322,7 +322,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QToolButton *manage_btn = new QToolButton(); manage_btn->setToolButtonStyle(Qt::ToolButtonIconOnly); - manage_btn->setIcon(utils::icon("gear")); + manage_btn->setIcon(utils::icon("list")); manage_btn->setAutoRaise(true); QMenu *menu = new QMenu(this); line_series_action = menu->addAction(tr("Line"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeLine); }); @@ -613,7 +613,7 @@ void ChartView::leaveEvent(QEvent *event) { void ChartView::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && !chart()->plotArea().contains(event->pos()) && - !manage_btn_proxy->widget()->underMouse() && !close_btn_proxy->widget()->underMouse()) { + !manage_btn_proxy->geometry().contains(event->pos()) && !close_btn_proxy->geometry().contains(event->pos())) { QMimeData *mimeData = new QMimeData; mimeData->setData(mime_type, QByteArray::number((qulonglong)this)); QDrag *drag = new QDrag(this); From 858f185fd28444b5ca72038b5e284a5699704917 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 3 Feb 2023 12:46:14 -0800 Subject: [PATCH 0831/1179] Hyundai: update Hyundai Genesis tuning (#27197) --- selfdrive/car/torque_data/params.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 397b29525d..7da508a156 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -25,7 +25,7 @@ HONDA ODYSSEY 2018: [1.8774809275211801, 0.8394431662987996, 0.2096978613792822] HONDA PILOT 2017: [1.7262026201812795, 0.9470005614967523, 0.21351430733218763] HONDA RIDGELINE 2017: [1.4146525028237624, 0.7356572861629564, 0.23307177552211328] HYUNDAI ELANTRA 2021: [3.169, 2.1259108157250735, 0.0819] -HYUNDAI GENESIS 2015-2016: [1.8466226943929824, 1.5552063647830634, 0.0984484465421171] +HYUNDAI GENESIS 2015-2016: [2.7807965280270794, 2.325, 0.0984484465421171] HYUNDAI IONIQ 5 2022: [3.172929, 2.713050, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] From 29d9d037590d2db33b7d49c44120d83307ec6568 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Feb 2023 04:47:26 +0800 Subject: [PATCH 0832/1179] cabana: add dialog to open route from remote or local (#27183) * add OpenRouteDialog * cleanup * failed_to_load * fix load * clear message list and stream after open new route * show message * remove all tabs and charts after open * use textEdited * check route format * cleanup loadRoute --- tools/cabana/SConscript | 2 +- tools/cabana/cabana.cc | 23 +++++++--- tools/cabana/chartswidget.cc | 4 +- tools/cabana/chartswidget.h | 2 +- tools/cabana/detailwidget.cc | 10 ++++ tools/cabana/detailwidget.h | 1 + tools/cabana/mainwin.cc | 17 +++++++ tools/cabana/mainwin.h | 1 + tools/cabana/messageswidget.cc | 26 +++++++++-- tools/cabana/messageswidget.h | 4 ++ tools/cabana/route.cc | 68 ++++++++++++++++++++++++++++ tools/cabana/route.h | 19 ++++++++ tools/cabana/settings.cc | 2 + tools/cabana/settings.h | 1 + tools/cabana/streams/replaystream.cc | 12 ++--- tools/cabana/streams/replaystream.h | 7 +-- 16 files changed, 174 insertions(+), 25 deletions(-) create mode 100644 tools/cabana/route.cc create mode 100644 tools/cabana/route.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 0c9ad14973..a9922ba9be 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -21,7 +21,7 @@ cabana_env = qt_env.Clone() prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', - 'commands.cc', 'messageswidget.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + 'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if arch == "Darwin": diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index e34e2d0205..e028e383c2 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -4,6 +4,7 @@ #include "common/prefix.h" #include "selfdrive/ui/qt/util.h" #include "tools/cabana/mainwin.h" +#include "tools/cabana/route.h" #include "tools/cabana/streams/livestream.h" #include "tools/cabana/streams/replaystream.h" @@ -26,10 +27,6 @@ int main(int argc, char *argv[]) { cmd_parser.addOption({"no-vipc", "do not output video"}); cmd_parser.addOption({"dbc", "dbc file to open", "dbc"}); cmd_parser.process(app); - const QStringList args = cmd_parser.positionalArguments(); - if (args.empty() && !cmd_parser.isSet("demo") && !cmd_parser.isSet("stream")) { - cmd_parser.showHelp(); - } std::unique_ptr op_prefix; std::unique_ptr stream; @@ -41,7 +38,6 @@ int main(int argc, char *argv[]) { #ifndef __APPLE__ op_prefix.reset(new OpenpilotPrefix()); #endif - const QString route = args.empty() ? DEMO_ROUTE : args.first(); uint32_t replay_flags = REPLAY_FLAG_NONE; if (cmd_parser.isSet("ecam")) { replay_flags |= REPLAY_FLAG_ECAM; @@ -50,9 +46,22 @@ int main(int argc, char *argv[]) { } else if (cmd_parser.isSet("no-vipc")) { replay_flags |= REPLAY_FLAG_NO_VIPC; } - auto replay_stream = new ReplayStream(&app); + + const QStringList args = cmd_parser.positionalArguments(); + QString route; + if (args.size() > 0) { + route = args.first(); + } else if (cmd_parser.isSet("demo")) { + route = DEMO_ROUTE; + } + + auto replay_stream = new ReplayStream(replay_flags, &app); stream.reset(replay_stream); - if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) { + if (route.isEmpty()) { + if (OpenRouteDialog dlg(nullptr); !dlg.exec()) { + return 0; + } + } else if (!replay_stream->loadRoute(route, cmd_parser.value("data_dir"))) { return 0; } } diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 1b8ce657a6..eb14e5a044 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -137,7 +137,7 @@ void ChartsWidget::updateState() { if (!is_zoomed) { double pos = (cur_sec - display_range.first) / max_chart_range; if (pos < 0 || pos > 0.8) { - const double min_event_sec = (can->events()->front()->mono_time / (double)1e9) - can->routeStartTime(); + const double min_event_sec = can->events()->empty() ? 0 : (can->events()->front()->mono_time / (double)1e9 - can->routeStartTime()); display_range.first = std::floor(std::max(min_event_sec, cur_sec - max_chart_range * 0.2)); } display_range.second = std::floor(display_range.first + max_chart_range); @@ -157,7 +157,7 @@ void ChartsWidget::updateState() { void ChartsWidget::setMaxChartRange(int value) { max_chart_range = settings.chart_range = value; double current_sec = can->currentSec(); - const double min_event_sec = (can->events()->front()->mono_time / (double)1e9) - can->routeStartTime(); + const double min_event_sec = can->events()->empty() ? 0 : (can->events()->front()->mono_time / (double)1e9 - can->routeStartTime()); // keep current_sec's pos double pos = (current_sec - display_range.first) / (display_range.second - display_range.first); display_range.first = std::floor(std::max(min_event_sec, current_sec - max_chart_range * (1.0 - pos))); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 9b2afd45a9..15da8e53ad 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -97,6 +97,7 @@ public: public slots: void setColumnCount(int n); + void removeAll(); signals: void dock(bool floating); @@ -114,7 +115,6 @@ private: void zoomIn(double min, double max); void zoomReset(); void updateToolBar(); - void removeAll(); void setMaxChartRange(int value); void updateLayout(); void settingChanged(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 3af0fa9fc3..46f7a148f4 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -104,6 +104,16 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { } } +void DetailWidget::removeAll() { + msg_id = ""; + tabbar->blockSignals(true); + while (tabbar->count() > 0) { + tabbar->removeTab(0); + } + tabbar->blockSignals(false); + stacked_layout->setCurrentIndex(0); +} + void DetailWidget::setMessage(const QString &message_id) { msg_id = message_id; int index = tabbar->count() - 1; diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 3a3f3adf0e..a62e23f226 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -30,6 +30,7 @@ public: DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const QString &message_id); void refresh(); + void removeAll(); QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } private: diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 94cf9840f7..dfd38e267d 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -15,6 +15,7 @@ #include #include "tools/cabana/commands.h" +#include "tools/cabana/route.h" static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { @@ -66,6 +67,11 @@ MainWindow::MainWindow() : QMainWindow() { void MainWindow::createActions() { QMenu *file_menu = menuBar()->addMenu(tr("&File")); + if (!can->liveStreaming()) { + file_menu->addAction(tr("Open Route..."), this, &MainWindow::openRoute); + file_menu->addSeparator(); + } + file_menu->addAction(tr("New DBC File"), this, &MainWindow::newFile)->setShortcuts(QKeySequence::New); file_menu->addAction(tr("Open DBC File..."), this, &MainWindow::openFile)->setShortcuts(QKeySequence::Open); @@ -185,6 +191,17 @@ void MainWindow::DBCFileChanged() { setWindowFilePath(QString("%1").arg(dbc()->name())); } +void MainWindow::openRoute() { + OpenRouteDialog dlg(this); + if (dlg.exec()) { + detail_widget->removeAll(); + charts_widget->removeAll(); + statusBar()->showMessage(tr("Route %1 loaded").arg(can->routeName()), 2000); + } else if (dlg.failedToLoad()) { + close(); + } +} + void MainWindow::newFile() { remindSaveChanges(); dbc()->open("untitled.dbc", ""); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index c26f6973c0..5e627df58b 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -23,6 +23,7 @@ public: void loadFile(const QString &fn); public slots: + void openRoute(); void newFile(); void openFile(); void openRecentFile(); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 9d0fc23e4d..359fe10f50 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -14,7 +13,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); // message filter - QLineEdit *filter = new QLineEdit(this); + filter = new QLineEdit(this); filter->setClearButtonEnabled(true); filter->setPlaceholderText(tr("filter messages")); main_layout->addWidget(filter); @@ -41,8 +40,9 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { main_layout->addLayout(suppress_layout); // signals/slots - QObject::connect(filter, &QLineEdit::textChanged, model, &MessageListModel::setFilterString); + QObject::connect(filter, &QLineEdit::textEdited, model, &MessageListModel::setFilterString); QObject::connect(can, &AbstractStream::msgsReceived, model, &MessageListModel::msgsReceived); + QObject::connect(can, &AbstractStream::streamStarted, this, &MessagesWidget::reset); QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); @@ -83,6 +83,13 @@ void MessagesWidget::updateSuppressedButtons() { } } +void MessagesWidget::reset() { + model->reset(); + filter->clear(); + current_msg_id = ""; + updateSuppressedButtons(); +} + // MessageListModel @@ -175,10 +182,11 @@ void MessageListModel::sortMessages() { void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); - if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { + bool update_all = new_msgs->size() == can->can_msgs.size(); + if (update_all || (filter_str.isEmpty() && msgs.size() != can->can_msgs.size())) { msgs = can->can_msgs.keys(); } - if (msgs.size() != prev_row_count) { + if (update_all || msgs.size() != prev_row_count) { sortMessages(); return; } @@ -215,3 +223,11 @@ void MessageListModel::suppress() { void MessageListModel::clearSuppress() { suppressed_bytes.clear(); } + +void MessageListModel::reset() { + beginResetModel(); + filter_str = ""; + msgs.clear(); + clearSuppress(); + endResetModel(); +} diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 1927faa646..81ee36cd6f 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,7 @@ public: void sortMessages(); void suppress(); void clearSuppress(); + void reset(); QStringList msgs; QSet> suppressed_bytes; @@ -41,6 +43,7 @@ public: QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); } bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); } void updateSuppressedButtons(); + void reset(); signals: void msgSelectionChanged(const QString &message_id); @@ -48,6 +51,7 @@ signals: protected: QTableView *table_widget; QString current_msg_id; + QLineEdit *filter; MessageListModel *model; QPushButton *suppress_add; QPushButton *suppress_clear; diff --git a/tools/cabana/route.cc b/tools/cabana/route.cc new file mode 100644 index 0000000000..ab322cdf90 --- /dev/null +++ b/tools/cabana/route.cc @@ -0,0 +1,68 @@ +#include "tools/cabana/route.h" + +#include +#include +#include +#include +#include +#include + +#include "tools/cabana/streams/replaystream.h" + +OpenRouteDialog::OpenRouteDialog(QWidget *parent) : QDialog(parent) { + // TODO: get route list from api.comma.ai + QHBoxLayout *edit_layout = new QHBoxLayout; + edit_layout->addWidget(new QLabel(tr("Route:"))); + edit_layout->addWidget(route_edit = new QLineEdit(this)); + route_edit->setPlaceholderText(tr("Enter remote route name or click browse to select a local route")); + auto file_btn = new QPushButton(tr("Browse..."), this); + edit_layout->addWidget(file_btn); + + btn_box = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel); + btn_box->button(QDialogButtonBox::Open)->setEnabled(false); + + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->addStretch(0); + main_layout->addLayout(edit_layout); + main_layout->addStretch(0); + main_layout->addWidget(btn_box); + setMinimumSize({550, 120}); + + QObject::connect(btn_box, &QDialogButtonBox::accepted, this, &OpenRouteDialog::loadRoute); + QObject::connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + QObject::connect(route_edit, &QLineEdit::textChanged, [this]() { + btn_box->button(QDialogButtonBox::Open)->setEnabled(!route_edit->text().isEmpty()); + }); + QObject::connect(file_btn, &QPushButton::clicked, [=]() { + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Local Route"), settings.last_route_dir); + if (!dir.isEmpty()) { + route_edit->setText(dir); + settings.last_route_dir = QFileInfo(dir).absolutePath(); + } + }); +} + +void OpenRouteDialog::loadRoute() { + btn_box->setEnabled(false); + + QString route = route_edit->text(); + QString data_dir; + if (int idx = route.lastIndexOf('/'); idx != -1) { + data_dir = route.mid(0, idx + 1); + route = route.mid(idx + 1); + } + + bool is_valid_format = Route::parseRoute(route).str.size() > 0; + if (!is_valid_format) { + QMessageBox::warning(nullptr, tr("Warning"), tr("Invalid route format: '%1'").arg(route)); + } else { + failed_to_load = !dynamic_cast(can)->loadRoute(route, data_dir); + if (failed_to_load) { + QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to load route: '%1'").arg(route)); + } else { + accept(); + } + } + + btn_box->setEnabled(true); +} diff --git a/tools/cabana/route.h b/tools/cabana/route.h new file mode 100644 index 0000000000..ceda71d585 --- /dev/null +++ b/tools/cabana/route.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +class OpenRouteDialog : public QDialog { + Q_OBJECT + +public: + OpenRouteDialog(QWidget *parent); + void loadRoute(); + inline bool failedToLoad() const { return failed_to_load; } + +private: + QLineEdit *route_edit; + QDialogButtonBox *btn_box; + bool failed_to_load = false; +}; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 22c7a941ab..6cbd16cabf 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -20,6 +20,7 @@ void Settings::save() { s.setValue("chart_range", chart_range); s.setValue("chart_column_count", chart_column_count); s.setValue("last_dir", last_dir); + s.setValue("last_route_dir", last_route_dir); s.setValue("window_state", window_state); s.setValue("geometry", geometry); s.setValue("video_splitter_state", video_splitter_state); @@ -36,6 +37,7 @@ void Settings::load() { chart_range = s.value("chart_range", 3 * 60).toInt(); chart_column_count = s.value("chart_column_count", 1).toInt(); last_dir = s.value("last_dir", QDir::homePath()).toString(); + last_route_dir = s.value("last_route_dir", QDir::homePath()).toString(); window_state = s.value("window_state").toByteArray(); geometry = s.value("geometry").toByteArray(); video_splitter_state = s.value("video_splitter_state").toByteArray(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index 7abad81c29..a302d20077 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -20,6 +20,7 @@ public: int chart_range = 3 * 60; // e minutes int chart_series_type = 0; QString last_dir; + QString last_route_dir; QByteArray geometry; QByteArray video_splitter_state; QByteArray window_state; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 72c4a13048..b768b94327 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -2,7 +2,7 @@ #include "tools/cabana/dbcmanager.h" -ReplayStream::ReplayStream(QObject *parent) : AbstractStream(parent, false) { +ReplayStream::ReplayStream(uint32_t replay_flags, QObject *parent) : replay_flags(replay_flags), AbstractStream(parent, false) { QObject::connect(&settings, &Settings::changed, [this]() { if (replay) replay->setSegmentCacheLimit(settings.max_cached_minutes); }); @@ -16,13 +16,13 @@ static bool event_filter(const Event *e, void *opaque) { return ((ReplayStream *)opaque)->eventFilter(e); } -bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) { - replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this); +bool ReplayStream::loadRoute(const QString &route, const QString &data_dir) { + replay.reset(new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this)); replay->setSegmentCacheLimit(settings.max_cached_minutes); replay->installEventFilter(event_filter, this); - QObject::connect(replay, &Replay::seekedTo, this, &AbstractStream::seekedTo); - QObject::connect(replay, &Replay::segmentsMerged, this, &AbstractStream::eventsMerged); - QObject::connect(replay, &Replay::streamStarted, this, &AbstractStream::streamStarted); + QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo); + QObject::connect(replay.get(), &Replay::segmentsMerged, this, &AbstractStream::eventsMerged); + QObject::connect(replay.get(), &Replay::streamStarted, this, &AbstractStream::streamStarted); if (replay->load()) { const auto &segments = replay->route()->segments(); if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index a9a74e33b5..69fb738ab8 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -8,9 +8,9 @@ class ReplayStream : public AbstractStream { Q_OBJECT public: - ReplayStream(QObject *parent); + ReplayStream(uint32_t replay_flags, QObject *parent); ~ReplayStream(); - bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE); + bool loadRoute(const QString &route, const QString &data_dir); bool eventFilter(const Event *event); void seekTo(double ts) override { replay->seekTo(std::max(double(0), ts), false); }; inline QString routeName() const override { return replay->route()->name(); } @@ -28,5 +28,6 @@ public: inline const std::vector> getTimeline() override { return replay->getTimeline(); } private: - Replay *replay = nullptr; + std::unique_ptr replay = nullptr; + uint32_t replay_flags = REPLAY_FLAG_NONE; }; From d6516059bd757b1e23c94808187b2dbc38786ca8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 4 Feb 2023 05:03:01 +0800 Subject: [PATCH 0833/1179] cabana: fix incorrect point size after adding new series to chart or changing series type (#27199) * update pointers after create series * cleanup --- tools/cabana/chartswidget.cc | 65 +++++++++++++++++++----------------- tools/cabana/chartswidget.h | 1 + 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index eb14e5a044..54cacf56cd 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -376,6 +376,7 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); updateTitle(); updateSeries(sig); + updateSeriesPoints(); emit seriesAdded(msg_id, sig); } @@ -482,41 +483,44 @@ void ChartView::updatePlot(double cur, double min, double max) { if (min != axis_x->min() || max != axis_x->max()) { axis_x->setRange(min, max); updateAxisY(); - - // Show points when zoomed in enough - 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; }); - auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); - - int num_points = std::max(end - begin, 1); - int pixels_per_point = width() / num_points; - - if (series_type == QAbstractSeries::SeriesTypeScatter) { - ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8)); - } else { - s.series->setPointsVisible(pixels_per_point > 20); - - // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs. -#ifndef __APPLE - // OpenGL mode lacks certain features (such as showing points), only use when drawing many points - bool use_opengl = pixels_per_point < 1; - s.series->setUseOpenGL(use_opengl); - - // Qt doesn't properly apply device pixel ratio in OpenGL mode - QApplication *application = static_cast(QApplication::instance()); - float scale = use_opengl ? application->devicePixelRatio() : 1.0; - - QPen pen = s.series->pen(); - pen.setWidth(2.0 * scale); - s.series->setPen(pen); -#endif - } - } + updateSeriesPoints(); } scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } +void ChartView::updateSeriesPoints() { + // Show points when zoomed in enough + 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; }); + auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + + int num_points = std::max(end - begin, 1); + int pixels_per_point = width() / num_points; + + if (series_type == QAbstractSeries::SeriesTypeScatter) { + ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8)); + } else { + s.series->setPointsVisible(pixels_per_point > 20); + + // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs. +#ifndef __APPLE + // OpenGL mode lacks certain features (such as showing points), only use when drawing many points + bool use_opengl = pixels_per_point < 1; + s.series->setUseOpenGL(use_opengl); + + // Qt doesn't properly apply device pixel ratio in OpenGL mode + QApplication *application = static_cast(QApplication::instance()); + float scale = use_opengl ? application->devicePixelRatio() : 1.0; + + QPen pen = s.series->pen(); + pen.setWidth(2.0 * scale); + s.series->setPen(pen); +#endif + } + } +} + void ChartView::updateSeries(const Signal *sig, const std::vector *events, bool clear) { events = events ? events : can->events(); for (auto &s : sigs) { @@ -783,6 +787,7 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { series->replace(s.vals); s.series = series; } + updateSeriesPoints(); updateTitle(); } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 15da8e53ad..8c50993971 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -73,6 +73,7 @@ private: void applyNiceNumbers(qreal min, qreal max); qreal niceNumber(qreal x, bool ceiling); QXYSeries *createSeries(QAbstractSeries::SeriesType type); + void updateSeriesPoints(); QValueAxis *axis_x; QValueAxis *axis_y; From 74187463da9f93c6841a6394b0b91a5451ef4765 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 3 Feb 2023 14:45:36 -0700 Subject: [PATCH 0834/1179] laikad: add laikad startup tests (#27207) * add laikad startup test * move debug files to xx * add laikad startup and ephemeris test --------- Co-authored-by: Kurt Nistelberger --- tools/gpstest/test_laikad.py | 105 +++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tools/gpstest/test_laikad.py diff --git a/tools/gpstest/test_laikad.py b/tools/gpstest/test_laikad.py new file mode 100644 index 0000000000..613ac991b1 --- /dev/null +++ b/tools/gpstest/test_laikad.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +import os +import time +import unittest + +import cereal.messaging as messaging +import selfdrive.sensord.pigeond as pd + +from common.params import Params +from system.hardware import TICI +from selfdrive.manager.process_config import managed_processes +from selfdrive.test.helpers import with_processes + + +def wait_for_location(sm, timeout, con=10): + cons_meas = 0 + start_time = time.monotonic() + while (time.monotonic() - start_time) < timeout: + sm.update() + if not sm.updated["gnssMeasurements"]: + continue + + msg = sm["gnssMeasurements"] + cons_meas = (cons_meas + 1) if 'positionECEF' in msg.to_dict() else 0 + if cons_meas >= con: + return True + return False + + +class TestLaikad(unittest.TestCase): + @classmethod + def setUpClass(self): + if not TICI: + raise unittest.SkipTest + + ublox_available = Params().get_bool("UbloxAvailable") + if not ublox_available: + raise unittest.SkipTest + + def setUp(self): + # ensure laikad cold start + Params().remove("LaikadEphemeris") + os.environ["LAIKAD_NO_INTERNET"] = "1" + managed_processes['laikad'].start() + + def tearDown(self): + managed_processes['laikad'].stop() + + + @with_processes(['pigeond', 'ubloxd']) + def test_laikad_cold_start(self): + time.sleep(5) + + start_time = time.monotonic() + sm = messaging.SubMaster(["gnssMeasurements"]) + + success = wait_for_location(sm, 60*2, con=10) + duration = time.monotonic() - start_time + + assert success, "Waiting for location timed out (2min)!" + assert duration < 60, f"Received Location {duration}!" + + + @with_processes(['ubloxd']) + def test_laikad_ublox_reset_start(self): + time.sleep(2) + + pigeon, pm = pd.create_pigeon() + pd.init_baudrate(pigeon) + assert pigeon.reset_device(), "Could not reset device!" + + laikad_sock = messaging.sub_sock("gnssMeasurements", timeout=0.1) + ublox_gnss_sock = messaging.sub_sock("ubloxGnss", timeout=0.1) + + pd.init_baudrate(pigeon) + pd.initialize_pigeon(pigeon) + pd.run_receiving(pigeon, pm, 180) + + ublox_msgs = messaging.drain_sock(ublox_gnss_sock) + laikad_msgs = messaging.drain_sock(laikad_sock) + + gps_ephem_cnt = 0 + glonass_ephem_cnt = 0 + for um in ublox_msgs: + if um.ubloxGnss.which() == 'ephemeris': + gps_ephem_cnt += 1 + elif um.ubloxGnss.which() == 'glonassEphemeris': + glonass_ephem_cnt += 1 + + assert gps_ephem_cnt > 0, "NO gps ephemeris collected!" + assert glonass_ephem_cnt > 0, "NO glonass ephemeris collected!" + + pos_meas = 0 + duration = -1 + for lm in laikad_msgs: + pos_meas = (pos_meas + 1) if 'positionECEF' in lm.gnssMeasurements.to_dict() else 0 + if pos_meas > 5: + duration = (lm.logMonoTime - laikad_msgs[0].logMonoTime)*1e-9 + break + + assert pos_meas > 5, "NOT enough positions at end of read!" + assert duration < 120, "Laikad took too long to get a Position!" + +if __name__ == "__main__": + unittest.main() From 9a42929b0c7bfa259f361b17ec22dfd34e389fec Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Fri, 3 Feb 2023 15:22:33 -0700 Subject: [PATCH 0835/1179] navd: check duration_typical before using (#27184) check duration_typical Co-authored-by: Kurt Nistelberger --- selfdrive/navd/navd.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/navd/navd.py b/selfdrive/navd/navd.py index 81e3bdb3df..7af911ab2a 100755 --- a/selfdrive/navd/navd.py +++ b/selfdrive/navd/navd.py @@ -226,7 +226,11 @@ class RouteEngine: remaining = 1.0 - along_geometry / max(step['distance'], 1) total_distance = step['distance'] * remaining total_time = step['duration'] * remaining - total_time_typical = step['duration_typical'] * remaining + + if step['duration_typical'] is None: + total_time_typical = total_time + else: + total_time_typical = step['duration_typical'] * remaining # Add up totals for future steps for i in range(self.step_idx + 1, len(self.route)): From 73a8d6b95185da3b49129143160b99d83e5a753d Mon Sep 17 00:00:00 2001 From: pbkompasz <47194071+pbkompasz@users.noreply.github.com> Date: Sat, 4 Feb 2023 01:30:59 +0200 Subject: [PATCH 0836/1179] docs: Add cabana to tools (#27208) --- docs/overview.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/overview.rst b/docs/overview.rst index cda51ba3d4..cc4c582155 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -77,3 +77,4 @@ tools Simulator tools/ssh/README.md Webcam + tools/cabana/README.md From 90108c0c28082b9129703b3a67e68180362e3dba Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 5 Feb 2023 01:42:39 +0800 Subject: [PATCH 0837/1179] cabana: better window title for live streaming (#27214) better title for live streaming --- tools/cabana/mainwin.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index dfd38e267d..b24c4e6dc4 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -267,7 +267,11 @@ void MainWindow::loadDBCFromFingerprint() { remindSaveChanges(); auto fingerprint = can->carFingerprint(); - video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); + if (can->liveStreaming()) { + video_dock->setWindowTitle(can->routeName()); + } else { + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); + } if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint]; if (dbc_name != QJsonValue::Undefined) { From 2d64f99b016401a8b81d275aac4a3305798c3171 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Sat, 4 Feb 2023 17:10:55 -0600 Subject: [PATCH 0838/1179] Add missing HIGHLANDER_TSS2 engine f/w (#27220) @Arnold Jagt#4866 2023 Highlander LE (ICE) DongleID/route b75bae9b9bde6210|2023-02-04--17-44-15 --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 490c94db75..1b30fe43e9 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1012,6 +1012,7 @@ FW_VERSIONS = { b'\x01896630ED9100\x00\x00\x00\x00', b'\x01896630EE1000\x00\x00\x00\x00', b'\x01896630EE1100\x00\x00\x00\x00', + b'\x01896630EG3000\x00\x00\x00\x00', b'\x01896630EG5000\x00\x00\x00\x00', ], (Ecu.fwdRadar, 0x750, 0xf): [ From d662f6d289aa8689045d4cf5fa017bcf32d249a2 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Sat, 4 Feb 2023 17:11:08 -0600 Subject: [PATCH 0839/1179] Add sveral missing LEXUS_ESH_TSS2 firmwares (#27219) * Add sveral missing LEXUS_ESH_TSS2 firmwares @salmankali#7352 2023 Lexus ES 300h DongleID/route c010a8cd3af884f5|2023-02-04--03-27-12 * docs.py gen'd CARS.md w/ 2023 Lexus ES Hybrid update --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 45873c4924..c48698b84f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -124,7 +124,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 1b30fe43e9..6cedef414b 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -162,7 +162,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.LEXUS_CTH: ToyotaCarInfo("Lexus CT Hybrid 2017-18", "Lexus Safety System+"), CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18", "Lexus Safety System+"), CAR.LEXUS_ES_TSS2: ToyotaCarInfo("Lexus ES 2019-22"), - CAR.LEXUS_ESH_TSS2: ToyotaCarInfo("Lexus ES Hybrid 2019-22", video_link="https://youtu.be/BZ29osRVJeg?t=12"), + CAR.LEXUS_ESH_TSS2: ToyotaCarInfo("Lexus ES Hybrid 2019-23", video_link="https://youtu.be/BZ29osRVJeg?t=12"), CAR.LEXUS_IS: ToyotaCarInfo("Lexus IS 2017-19"), CAR.LEXUS_NX: ToyotaCarInfo("Lexus NX 2018-19"), CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19"), @@ -1592,12 +1592,14 @@ FW_VERSIONS = { b'\x028966333V4000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x02896633T09000\x00\x00\x00\x00897CF3307001\x00\x00\x00\x00', b'\x01896633T38000\x00\x00\x00\x00', + b'\x01896633T58000\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'F152633423\x00\x00\x00\x00\x00\x00', b'F152633680\x00\x00\x00\x00\x00\x00', b'F152633681\x00\x00\x00\x00\x00\x00', b'F152633F50\x00\x00\x00\x00\x00\x00', + b'F152633F51\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B33252\x00\x00\x00\x00\x00\x00', @@ -1613,6 +1615,7 @@ FW_VERSIONS = { b'\x018821F6201300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0610000\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', b'\x028646F33030D0\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F3303100\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', b'\x028646F3303200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00', From 784bef20ce1686f8ebbb2b17b3e806599921b8ed Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Sat, 4 Feb 2023 17:24:37 -0600 Subject: [PATCH 0840/1179] Add missing AVALONH_TSS2 fwdRadar f/w (#27215) `@shankapotamous#6637` 2022 Avalon Hybrid DongleID/route 301800decccd6669|2023-02-04--10-09-55 --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 6cedef414b..3046814fac 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -348,6 +348,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F6201200\x00\x00\x00\x00', + b'\x018821F6201300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F4104100\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', From 2cb0f599628f65d4fdb9dc3d84bdcc0865c33224 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 5 Feb 2023 07:25:06 +0800 Subject: [PATCH 0841/1179] cabana: delay starting live streaming thread (#27213) --- tools/cabana/streams/livestream.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 3edd2a7758..b2fc7ea4a6 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -8,7 +8,7 @@ LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), stream_thread = new QThread(this); QObject::connect(stream_thread, &QThread::started, [=]() { streamThread(); }); QObject::connect(stream_thread, &QThread::finished, stream_thread, &QThread::deleteLater); - stream_thread->start(); + QTimer::singleShot(0, [this]() { stream_thread->start(); }); } LiveStream::~LiveStream() { @@ -45,9 +45,6 @@ void LiveStream::streamThread() { } void LiveStream::handleEvent(Event *evt) { - std::lock_guard lk(lock); - can_events.push_back(evt); - current_ts = evt->mono_time; if (start_ts == 0 || current_ts < start_ts) { if (current_ts < start_ts) { @@ -57,6 +54,8 @@ void LiveStream::handleEvent(Event *evt) { emit streamStarted(); } + std::lock_guard lk(lock); + can_events.push_back(evt); if (!pause_) { if (speed_ < 1 && last_update_ts > 0) { auto it = std::upper_bound(can_events.begin(), can_events.end(), last_update_event_ts, [](uint64_t ts, auto &e) { From 9b054af8b6943ffea8d26a4dadb6cfe8fbefe990 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Feb 2023 04:35:15 +0800 Subject: [PATCH 0842/1179] cabana: improve align charts (#27217) * improve align charts * set range on need * cleanup * remove unused include --- tools/cabana/chartswidget.cc | 120 +++++++++++++++++------------------ tools/cabana/chartswidget.h | 19 +++--- 2 files changed, 69 insertions(+), 70 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 54cacf56cd..87a0e8abd0 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -68,10 +68,6 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { charts_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); main_layout->addWidget(charts_scroll); - align_charts_timer = new QTimer(this); - align_charts_timer->setSingleShot(true); - align_charts_timer->callOnTimeout(this, &ChartsWidget::alignCharts); - // init settings use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > QApplication::style()->standardPalette().color(QPalette::Background).value(); @@ -125,9 +121,9 @@ void ChartsWidget::zoomReset() { void ChartsWidget::updateState() { if (charts.isEmpty()) return; + const auto events = can->events(); if (can->liveStreaming()) { // appends incoming events to the end of series - const auto events = can->events(); for (auto c : charts) { c->updateSeries(nullptr, events, false); } @@ -135,33 +131,30 @@ void ChartsWidget::updateState() { const double cur_sec = can->currentSec(); if (!is_zoomed) { - double pos = (cur_sec - display_range.first) / max_chart_range; + double pos = (cur_sec - display_range.first) / std::max(1.0, (display_range.second - display_range.first)); if (pos < 0 || pos > 0.8) { - const double min_event_sec = can->events()->empty() ? 0 : (can->events()->front()->mono_time / (double)1e9 - can->routeStartTime()); - display_range.first = std::floor(std::max(min_event_sec, cur_sec - max_chart_range * 0.2)); + display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1); } - display_range.second = std::floor(display_range.first + max_chart_range); + double max_event_sec = events->empty() ? 0 : (events->back()->mono_time / 1e9 - can->routeStartTime()); + double max_sec = std::min(std::floor(display_range.first + max_chart_range), max_event_sec); + display_range.first = std::max(0.0, max_sec - max_chart_range); + display_range.second = display_range.first + max_chart_range; } else if (cur_sec < zoomed_range.first || cur_sec >= zoomed_range.second) { // loop in zoommed range can->seekTo(zoomed_range.first); } - setUpdatesEnabled(false); + charts_layout->parentWidget()->setUpdatesEnabled(false); const auto &range = is_zoomed ? zoomed_range : display_range; for (auto c : charts) { c->updatePlot(cur_sec, range.first, range.second); } - setUpdatesEnabled(true); + alignCharts(); + charts_layout->parentWidget()->setUpdatesEnabled(true); } void ChartsWidget::setMaxChartRange(int value) { max_chart_range = settings.chart_range = value; - double current_sec = can->currentSec(); - const double min_event_sec = can->events()->empty() ? 0 : (can->events()->front()->mono_time / (double)1e9 - can->routeStartTime()); - // keep current_sec's pos - double pos = (current_sec - display_range.first) / (display_range.second - display_range.first); - display_range.first = std::floor(std::max(min_event_sec, current_sec - max_chart_range * (1.0 - pos))); - display_range.second = std::floor(display_range.first + max_chart_range); updateToolBar(); updateState(); } @@ -200,7 +193,6 @@ ChartView *ChartsWidget::createChart() { QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); - QObject::connect(chart, &ChartView::axisYUpdated, [this]() { align_charts_timer->start(100); }); charts.push_back(chart); updateLayout(); return chart; @@ -242,6 +234,7 @@ void ChartsWidget::updateLayout() { for (int i = 0; i < charts.size(); ++i) { charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); } + alignCharts(true); } void ChartsWidget::resizeEvent(QResizeEvent *event) { @@ -278,13 +271,16 @@ void ChartsWidget::removeAll() { emit seriesChanged(); } -void ChartsWidget::alignCharts() { +void ChartsWidget::alignCharts(bool force) { int plot_left = 0; for (auto c : charts) { - plot_left = qMax((qreal)plot_left, c->getYAsixLabelWidth()); + plot_left = std::max(plot_left, c->y_label_width); } - for (auto c : charts) { - c->setPlotAreaLeftPosition(plot_left); + plot_left = std::max((plot_left / 10) * 10 + 10, 50); + if (std::exchange(align_to, plot_left) != align_to || force) { + for (auto c : charts) { + c->updatePlotArea(align_to); + } } } @@ -302,15 +298,20 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; QChart *chart = new QChart(); - chart->setBackgroundRoundness(0); + chart->setBackgroundVisible(false); axis_x = new QValueAxis(this); axis_y = new QValueAxis(this); + axis_y->setLabelFormat("%.1f"); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); chart->legend()->layout()->setContentsMargins(0, 0, 40, 0); chart->legend()->setShowToolTips(true); - chart->layout()->setContentsMargins(0, 0, 0, 0); - chart->setMargins({20, 11, 11, 11}); + chart->setMargins({0, 0, 0, 0}); + + background = new QGraphicsRectItem(chart); + background->setBrush(Qt::white); + background->setPen(Qt::NoPen); + background->setZValue(chart->zValue() - 1); QToolButton *remove_btn = new QToolButton(); remove_btn->setIcon(utils::icon("x")); @@ -351,22 +352,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); } -qreal ChartView::getYAsixLabelWidth() const { - if (axis_y->max() <= axis_y->min() || axis_y->tickCount() <= 1) { - return 0; - } - QFontMetrics fm(axis_y->labelsFont()); - int n = qMax(int(-qFloor(std::log10((axis_y->max() - axis_y->min()) / (axis_y->tickCount() - 1)))), 0) + 1; - return qMax(fm.width(QString::number(axis_y->min(), 'f', n)), fm.width(QString::number(axis_y->max(), 'f', n))) + 20; -} - -void ChartView::setPlotAreaLeftPosition(int pos) { - if (std::ceil(chart()->plotArea().left()) != pos) { - const float left_margin = chart()->margins().left() + pos - chart()->plotArea().left(); - chart()->setMargins(QMargins(left_margin, 11, 11, 11)); - } -} - void ChartView::addSeries(const QString &msg_id, const Signal *sig) { QXYSeries *series = createSeries(series_type); chart()->addSeries(series); @@ -467,11 +452,21 @@ void ChartView::manageSeries() { void ChartView::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); + updatePlotArea(); int x = event->size().width() - close_btn_proxy->size().width() - 11; close_btn_proxy->setPos(x, 8); manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); } +void ChartView::updatePlotArea(int left) { + align_to = left > 0 ? left : align_to; + QRect r = rect(); + background->setRect(r); + chart()->legend()->setGeometry(QRect(r.left(), r.top(), r.width(), 45)); + chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 22, r.height() - 80)); + chart()->layout()->invalidate(); +} + void ChartView::updateTitle() { 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)); @@ -536,7 +531,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even for (auto it = begin; it != events->end(); ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - if (s.source == c.getSrc() && s.address == c.getAddress()) { + if (s.address == c.getAddress() && s.source == c.getSrc()) { 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 @@ -549,46 +544,47 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even s.last_value_mono_time = events->back()->mono_time; } s.series->replace(s.vals); - updateAxisY(); } } + updateAxisY(); } // auto zoom on yaxis void ChartView::updateAxisY() { if (sigs.isEmpty()) return; - double min_y = std::numeric_limits::max(); - double max_y = std::numeric_limits::lowest(); + double min = std::numeric_limits::max(); + double max = std::numeric_limits::lowest(); 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; }); - for (auto it = begin; it != s.vals.end() && it->x() <= axis_x->max(); ++it) { - if (it->y() < min_y) min_y = it->y(); - if (it->y() > max_y) max_y = it->y(); + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); + auto last = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + for (auto it = first; it != last; ++it) { + if (it->y() < min) min = it->y(); + if (it->y() > max) max = it->y(); } } + if (min == std::numeric_limits::max()) min = 0; + if (max == std::numeric_limits::lowest()) max = 0; - if (min_y == std::numeric_limits::max()) min_y = 0; - if (max_y == std::numeric_limits::lowest()) max_y = 0; - if (std::abs(max_y - min_y) < 1e-3) { - applyNiceNumbers(min_y - 1, max_y + 1); - } else { - double range = max_y - min_y; - applyNiceNumbers(min_y - range * 0.05, max_y + range * 0.05); + double delta = std::abs(max - min) < 1e-3 ? 1 : (max - min) * 0.05; + auto [min_y, max_y, tick_count] = getNiceAxisNumbers(min - delta, max + delta, axis_y->tickCount()); + if (min_y != axis_y->min() || max_y != axis_y->max()) { + axis_y->setRange(min_y, max_y); + axis_y->setTickCount(tick_count); + + QFontMetrics fm(axis_y->labelsFont()); + int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; + y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 20; // left margin 20 } - emit axisYUpdated(); } -void ChartView::applyNiceNumbers(qreal min, qreal max) { - int tick_count = axis_y->tickCount(); +std::tuple ChartView::getNiceAxisNumbers(qreal min, qreal max, int tick_count) { qreal range = niceNumber((max - min), true); // range with ceiling qreal step = niceNumber(range / (tick_count - 1), false); min = qFloor(min / step); max = qCeil(max / step); tick_count = int(max - min) + 1; - axis_y->setRange(min * step, max * step); - axis_y->setTickCount(tick_count); - axis_y->setLabelFormat("%.1f"); + return {min * step, max * step, tick_count}; } // nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 8c50993971..f0f9e5cd9c 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -18,6 +17,8 @@ using namespace QtCharts; +const int CHART_MIN_WIDTH = 300; + class ChartView : public QChartView { Q_OBJECT @@ -29,9 +30,8 @@ public: bool hasSeries(const QString &msg_id, const Signal *sig) const; void updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); - void setPlotAreaLeftPosition(int pos); - qreal getYAsixLabelWidth() const; void setSeriesType(QAbstractSeries::SeriesType type); + void updatePlotArea(int left = 0); struct SigItem { QString msg_id; @@ -49,7 +49,6 @@ signals: void zoomIn(double min, double max); void zoomReset(); void remove(); - void axisYUpdated(); private slots: void msgRemoved(uint32_t address); @@ -67,25 +66,30 @@ private: void dropEvent(QDropEvent *event) override; void leaveEvent(QEvent *event) override; void resizeEvent(QResizeEvent *event) override; + QSize sizeHint() const override { return {CHART_MIN_WIDTH, settings.chart_height}; } void updateAxisY(); void updateTitle(); void drawForeground(QPainter *painter, const QRectF &rect) override; - void applyNiceNumbers(qreal min, qreal max); + std::tuple getNiceAxisNumbers(qreal min, qreal max, int tick_count); qreal niceNumber(qreal x, bool ceiling); QXYSeries *createSeries(QAbstractSeries::SeriesType type); void updateSeriesPoints(); + int y_label_width = 50; + int align_to = 0; QValueAxis *axis_x; QValueAxis *axis_y; QVector track_pts; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; + QGraphicsRectItem *background; QList sigs; double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; QAbstractSeries::SeriesType series_type = QAbstractSeries::SeriesTypeLine; QAction *line_series_action; QAction *scatter_series_action; + friend class ChartsWidget; }; class ChartsWidget : public QWidget { @@ -107,7 +111,7 @@ signals: private: void resizeEvent(QResizeEvent *event) override; - void alignCharts(); + void alignCharts(bool force = false); void newChart(); ChartView * createChart(); void removeChart(ChartView *chart); @@ -129,7 +133,6 @@ private: QAction *dock_btn; QAction *reset_zoom_btn; QAction *remove_all_btn; - QTimer *align_charts_timer; QGridLayout *charts_layout; QList charts; uint32_t max_chart_range = 0; @@ -141,7 +144,7 @@ private: QAction *columns_cb_action; QComboBox *columns_cb; int column_count = 1; - const int CHART_MIN_WIDTH = 300; + int align_to = 0; }; class SeriesSelector : public QDialog { From 54f3ca43bb72f697a5a2fc90d3c26f7301a48cd0 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Feb 2023 04:35:30 +0800 Subject: [PATCH 0843/1179] cabana: only relayout charts when needed (#27210) --- tools/cabana/chartswidget.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 87a0e8abd0..8591d67d51 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -231,8 +231,12 @@ void ChartsWidget::updateLayout() { columns_cb_action->setVisible(show_column_cb); n = std::min(column_count, n); - for (int i = 0; i < charts.size(); ++i) { - charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); + if (charts.size() != charts_layout->count() || n != charts_layout->columnCount()) { + charts_layout->parentWidget()->setUpdatesEnabled(false); + for (int i = 0; i < charts.size(); ++i) { + charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); + } + QTimer::singleShot(0, [this]() { charts_layout->parentWidget()->setUpdatesEnabled(true); }); } alignCharts(true); } From 4117986520e539aa2a6288538c940728ccb89884 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Feb 2023 06:50:32 +0800 Subject: [PATCH 0844/1179] cabana: fix incorrect clamp (#27218) * fix incorrect clamp * fix type error --- tools/cabana/chartswidget.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8591d67d51..c6f5c277eb 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -642,8 +642,8 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { double max = chart()->mapToValue(rect.bottomRight()).x(); // Prevent zooming/seeking past the end of the route - min = std::clamp(min, can->routeStartTime(), can->routeStartTime() + can->totalSeconds()); - max = std::clamp(max, can->routeStartTime(), can->routeStartTime() + can->totalSeconds()); + min = std::clamp(min, 0., can->totalSeconds()); + max = std::clamp(max, 0., can->totalSeconds()); double min_rounded = std::floor(min * 10.0) / 10.0; double max_rounded = std::floor(max * 10.0) / 10.0; From f5f14068173fbf8664e682e5b02270ecbc79abdb Mon Sep 17 00:00:00 2001 From: pbkompasz <47194071+pbkompasz@users.noreply.github.com> Date: Mon, 6 Feb 2023 00:52:28 +0200 Subject: [PATCH 0845/1179] docs: update cabana usage in README (#27225) * Add ecam * Update README.md --------- Co-authored-by: Adeeb Shihadeh --- tools/cabana/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cabana/README.md b/tools/cabana/README.md index dd131880a6..db247c39c5 100644 --- a/tools/cabana/README.md +++ b/tools/cabana/README.md @@ -8,13 +8,18 @@ Cabana is a tool developed to view raw CAN data. One use for this is creating an ```bash $ ./cabana -h -Usage: ./cabana [options] route +Usage: ./_cabana [options] route Options: -h, --help Displays this help. --demo use a demo route instead of providing your own --qcam load qcamera + --ecam load wide road camera + --stream read can messages from live streaming + --zmq the ip address on which to receive zmq messages --data_dir local directory with routes + --no-vipc do not output video + --dbc dbc file to open Arguments: route the drive to replay. find your drives at From 0374d4817d4730fb76adcee07252adf39759dd25 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 5 Feb 2023 15:45:01 -0800 Subject: [PATCH 0846/1179] setup pre-built master-ci (#27205) * try this * add as release branch * set the name * build on master-ci --- Jenkinsfile | 18 ++++++++++++++++-- release/build_release.sh | 22 +++++++++++++--------- system/version.py | 2 +- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1841c68bba..30c045e419 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,6 +13,8 @@ export GIT_COMMIT=${env.GIT_COMMIT} export AZURE_TOKEN='${env.AZURE_TOKEN}' export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}' +export GIT_SSH_COMMAND="ssh -i /data/gitkey" + source ~/.bash_profile if [ -f /TICI ]; then source /etc/profile @@ -56,14 +58,26 @@ pipeline { } stages { - stage('build release3') { + stage('build release3-staging') { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } when { branch 'devel-staging' } steps { phone_steps("tici-needs-can", [ - ["build release3-staging & dashcam3-staging", "PUSH=1 $SOURCE_DIR/release/build_release.sh"], + ["build release3-staging & dashcam3-staging", "RELEASE_BRANCH=release3-staging DASHCAM_BRANCH=dashcam3-staging $SOURCE_DIR/release/build_release.sh"], + ]) + } + } + + stage('build nightly') { + agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } } + when { + branch 'master-ci' + } + steps { + phone_steps("tici-needs-can", [ + ["build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"], ]) } } diff --git a/release/build_release.sh b/release/build_release.sh index 80106eefb2..60f81fce06 100755 --- a/release/build_release.sh +++ b/release/build_release.sh @@ -11,15 +11,19 @@ SOURCE_DIR="$(git rev-parse --show-toplevel)" if [ -f /TICI ]; then FILES_SRC="release/files_tici" - RELEASE_BRANCH=release3-staging - DASHCAM_BRANCH=dashcam3-staging else - exit 0 + echo "no release files set" + exit 1 fi +if [ -z "$RELEASE_BRANCH" ]; then + echo "RELEASE_BRANCH is not set" + exit 1 +fi + + # set git identity source $DIR/identity.sh -export GIT_SSH_COMMAND="ssh -i /data/gitkey" echo "[-] Setting up repo T=$SECONDS" rm -rf $BUILD_DIR @@ -27,7 +31,6 @@ mkdir -p $BUILD_DIR cd $BUILD_DIR git init git remote add origin git@github.com:commaai/openpilot.git -git fetch origin $RELEASE_BRANCH git checkout --orphan $RELEASE_BRANCH # do the files copy @@ -48,7 +51,6 @@ echo "#define COMMA_VERSION \"$VERSION-release\"" > common/version.h echo "[-] committing version $VERSION T=$SECONDS" git add -f . git commit -a -m "openpilot v$VERSION release" -git branch --set-upstream-to=origin/$RELEASE_BRANCH # Build panda firmware pushd panda/ @@ -105,10 +107,12 @@ RELEASE=1 selfdrive/test/test_onroad.py selfdrive/car/tests/test_car_interfaces.py rm -rf $TEST_FILES -if [ ! -z "$PUSH" ]; then - echo "[-] pushing T=$SECONDS" - git push -f origin $RELEASE_BRANCH +if [ ! -z "$RELEASE_BRANCH" ]; then + echo "[-] pushing release T=$SECONDS" + git push -f origin $RELEASE_BRANCH:$RELEASE_BRANCH +fi +if [ ! -z "$DASHCAM_BRANCH" ]; then # Create dashcam git rm selfdrive/car/*/carcontroller.py git commit -m "create dashcam release from release" diff --git a/system/version.py b/system/version.py index 6031531556..55f80afa35 100644 --- a/system/version.py +++ b/system/version.py @@ -7,7 +7,7 @@ from functools import lru_cache from common.basedir import BASEDIR from system.swaglog import cloudlog -RELEASE_BRANCHES = ['release3-staging', 'dashcam3-staging', 'release3', 'dashcam3'] +RELEASE_BRANCHES = ['release3-staging', 'dashcam3-staging', 'release3', 'dashcam3', 'nightly'] TESTED_BRANCHES = RELEASE_BRANCHES + ['devel', 'devel-staging'] training_version: bytes = b"0.2.0" From 1ecda86e51ad3dfefa87a9cebd28370d57ed55fb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Feb 2023 02:17:58 +0800 Subject: [PATCH 0847/1179] cabana: concurrently update chart series (#27230) --- tools/cabana/chartswidget.cc | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index c6f5c277eb..34498364c6 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -529,20 +529,38 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz s.last_value_mono_time = 0; } - double route_start_time = can->routeStartTime(); + + struct Chunk { + std::vector::const_iterator first, second; + QVector vals; + }; + // split into one minitue chunks + QVector chunks; Event begin_event(cereal::Event::Which::INIT_DATA, s.last_value_mono_time); auto begin = std::upper_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); - for (auto it = begin; it != events->end(); ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - if (s.address == c.getAddress() && s.source == c.getSrc()) { - 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}); + for (auto it = begin, second = begin; it != events->end(); it = second) { + second = std::lower_bound(it, events->end(), (*it)->mono_time + 1e9 * 60, [](auto &e, uint64_t ts) { return e->mono_time < ts; }); + chunks.push_back({it, second}); + } + + QtConcurrent::blockingMap(chunks, [&](Chunk &chunk) { + chunk.vals.reserve(60 * 100); // 100 hz + double route_start_time = can->routeStartTime(); + for (auto it = chunk.first; it != chunk.second; ++it) { + if ((*it)->which == cereal::Event::Which::CAN) { + for (const auto &c : (*it)->event.getCan()) { + if (s.address == c.getAddress() && s.source == c.getSrc()) { + 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 + chunk.vals.push_back({ts, value}); + } } } } + }); + for (auto &c : chunks) { + s.vals.append(c.vals); } if (events->size()) { s.last_value_mono_time = events->back()->mono_time; From f9de6a0dd876352dacc843ef2b28fb2456771239 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Feb 2023 02:18:44 +0800 Subject: [PATCH 0848/1179] cabana: click on legend to show/hide series (#27231) * click on legend to show/hide series * update axis y * add move icon --- tools/cabana/chartswidget.cc | 27 ++++++++++++++++++++++++--- tools/cabana/chartswidget.h | 4 ++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 34498364c6..845649dfc1 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -317,6 +317,9 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { background->setPen(Qt::NoPen); background->setZValue(chart->zValue() - 1); + move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart); + move_icon->setToolTip(tr("Drag and drop to combine charts")); + QToolButton *remove_btn = new QToolButton(); remove_btn->setIcon(utils::icon("x")); remove_btn->setAutoRaise(true); @@ -460,6 +463,7 @@ void ChartView::resizeEvent(QResizeEvent *event) { int x = event->size().width() - close_btn_proxy->size().width() - 11; close_btn_proxy->setPos(x, 8); manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); + move_icon->setPos(11, 8); } void ChartView::updatePlotArea(int left) { @@ -472,8 +476,12 @@ void ChartView::updatePlotArea(int left) { } void ChartView::updateTitle() { + for (QLegendMarker *marker : chart()->legend()->markers()) { + QObject::connect(marker, &QLegendMarker::clicked, this, &ChartView::handleMarkerClicked, Qt::UniqueConnection); + } 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)); + auto decoration = s.series->isVisible() ? "none" : "line-through"; + s.series->setName(QString("%2%3 %4").arg(decoration).arg(s.sig->name.c_str()).arg(msgName(s.msg_id)).arg(s.msg_id)); } } @@ -578,6 +586,8 @@ void ChartView::updateAxisY() { double min = std::numeric_limits::max(); double max = std::numeric_limits::lowest(); for (auto &s : sigs) { + if (!s.series->isVisible()) continue; + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); auto last = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); for (auto it = first; it != last; ++it) { @@ -634,8 +644,7 @@ void ChartView::leaveEvent(QEvent *event) { } void ChartView::mousePressEvent(QMouseEvent *event) { - if (event->button() == Qt::LeftButton && !chart()->plotArea().contains(event->pos()) && - !manage_btn_proxy->geometry().contains(event->pos()) && !close_btn_proxy->geometry().contains(event->pos())) { + if (event->button() == Qt::LeftButton && move_icon->sceneBoundingRect().contains(event->pos())) { QMimeData *mimeData = new QMimeData; mimeData->setData(mime_type, QByteArray::number((qulonglong)this)); QDrag *drag = new QDrag(this); @@ -810,6 +819,18 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { } } +void ChartView::handleMarkerClicked() { + auto marker = qobject_cast(sender()); + Q_ASSERT(marker); + if (sigs.size() > 1) { + auto series = marker->series(); + series->setVisible(!series->isVisible()); + marker->setVisible(true); + updateAxisY(); + updateTitle(); + } +} + // SeriesSelector SeriesSelector::SeriesSelector(QWidget *parent) { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index f0f9e5cd9c..77f04534a4 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -5,9 +5,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -56,6 +58,7 @@ private slots: void signalUpdated(const Signal *sig); void signalRemoved(const Signal *sig); void manageSeries(); + void handleMarkerClicked(); private: QList::iterator removeItem(const QList::iterator &it); @@ -80,6 +83,7 @@ private: QValueAxis *axis_x; QValueAxis *axis_y; QVector track_pts; + QGraphicsPixmapItem *move_icon; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; QGraphicsRectItem *background; From 68bcdaaff7f9050402d983f460f2c85866b4ca32 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 6 Feb 2023 10:40:45 -0800 Subject: [PATCH 0849/1179] settings: highlight nightly in branch switcher (#27227) --- selfdrive/ui/qt/offroad/software_settings.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 12d62e63fb..6db6a6cdfe 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -54,7 +54,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { connect(targetBranchBtn, &ButtonControl::clicked, [=]() { auto current = params.get("GitBranch"); QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(","); - for (QString b : {current.c_str(), "devel-staging", "devel", "master-ci", "master"}) { + for (QString b : {current.c_str(), "devel-staging", "devel", "nightly", "master-ci", "master"}) { auto i = branches.indexOf(b); if (i >= 0) { branches.removeAt(i); From 9a51275cd246bcbf53da764495a944af8a0b51bd Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 6 Feb 2023 15:43:25 -0800 Subject: [PATCH 0850/1179] setup: fix button label on ethernet (#27235) * setup: continue without wi-fi on ethernet * switch around --- selfdrive/ui/qt/setup/setup.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 69dafcf741..f1ffabf6c6 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -178,8 +178,8 @@ QWidget * Setup::network_setup() { QObject::connect(request, &HttpRequest::requestDone, [=](const QString &, bool success) { cont->setEnabled(success); if (success) { - const bool cell = networking->wifi->currentNetworkType() == NetworkType::CELL; - cont->setText(cell ? tr("Continue without Wi-Fi") : tr("Continue")); + const bool wifi = networking->wifi->currentNetworkType() == NetworkType::WIFI; + cont->setText(wifi ? tr("Continue") : tr("Continue without Wi-Fi")); } else { cont->setText(tr("Waiting for internet")); } From 1a99fd36101fbe4cbe9853b1df5dfe6c59fea5c4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Feb 2023 08:39:16 +0800 Subject: [PATCH 0851/1179] cabana: fixed wrong plot area after changed column count (#27228) --- tools/cabana/chartswidget.cc | 33 +++++++++++++++++---------------- tools/cabana/chartswidget.h | 9 +++++---- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 845649dfc1..a271df9dd7 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -149,7 +149,6 @@ void ChartsWidget::updateState() { for (auto c : charts) { c->updatePlot(cur_sec, range.first, range.second); } - alignCharts(); charts_layout->parentWidget()->setUpdatesEnabled(true); } @@ -186,13 +185,14 @@ ChartView *ChartsWidget::createChart() { auto chart = new ChartView(this); chart->setFixedHeight(settings.chart_height); chart->setMinimumWidth(CHART_MIN_WIDTH); - chart->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); chart->chart()->setTheme(use_dark_theme ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); 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::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); + QObject::connect(chart, &ChartView::axisYLabelWidthChanged, this, &ChartsWidget::alignCharts); charts.push_back(chart); updateLayout(); return chart; @@ -231,14 +231,14 @@ void ChartsWidget::updateLayout() { columns_cb_action->setVisible(show_column_cb); n = std::min(column_count, n); - if (charts.size() != charts_layout->count() || n != charts_layout->columnCount()) { + if (charts.size() != charts_layout->count() || n != current_column_count) { + current_column_count = n; charts_layout->parentWidget()->setUpdatesEnabled(false); for (int i = 0; i < charts.size(); ++i) { charts_layout->addWidget(charts[charts.size() - i - 1], i / n, i % n); } QTimer::singleShot(0, [this]() { charts_layout->parentWidget()->setUpdatesEnabled(true); }); } - alignCharts(true); } void ChartsWidget::resizeEvent(QResizeEvent *event) { @@ -275,16 +275,14 @@ void ChartsWidget::removeAll() { emit seriesChanged(); } -void ChartsWidget::alignCharts(bool force) { +void ChartsWidget::alignCharts() { int plot_left = 0; for (auto c : charts) { plot_left = std::max(plot_left, c->y_label_width); } plot_left = std::max((plot_left / 10) * 10 + 10, 50); - if (std::exchange(align_to, plot_left) != align_to || force) { - for (auto c : charts) { - c->updatePlotArea(align_to); - } + for (auto c : charts) { + c->updatePlotArea(plot_left); } } @@ -459,7 +457,7 @@ void ChartView::manageSeries() { void ChartView::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); - updatePlotArea(); + updatePlotArea(align_to); int x = event->size().width() - close_btn_proxy->size().width() - 11; close_btn_proxy->setPos(x, 8); manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); @@ -467,12 +465,14 @@ void ChartView::resizeEvent(QResizeEvent *event) { } void ChartView::updatePlotArea(int left) { - align_to = left > 0 ? left : align_to; QRect r = rect(); - background->setRect(r); - chart()->legend()->setGeometry(QRect(r.left(), r.top(), r.width(), 45)); - chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 22, r.height() - 80)); - chart()->layout()->invalidate(); + if (align_to != left || r != background->rect()) { + align_to = left; + background->setRect(r); + chart()->legend()->setGeometry(QRect(r.left(), r.top(), r.width(), 45)); + chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 22, r.height() - 80)); + chart()->layout()->invalidate(); + } } void ChartView::updateTitle() { @@ -600,13 +600,14 @@ void ChartView::updateAxisY() { double delta = std::abs(max - min) < 1e-3 ? 1 : (max - min) * 0.05; auto [min_y, max_y, tick_count] = getNiceAxisNumbers(min - delta, max + delta, axis_y->tickCount()); - if (min_y != axis_y->min() || max_y != axis_y->max()) { + if (min_y != axis_y->min() || max_y != axis_y->max() || y_label_width == 0) { axis_y->setRange(min_y, max_y); axis_y->setTickCount(tick_count); QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 20; // left margin 20 + emit axisYLabelWidthChanged(y_label_width); } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 77f04534a4..66ef98991f 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -33,7 +33,7 @@ public: void updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); void setSeriesType(QAbstractSeries::SeriesType type); - void updatePlotArea(int left = 0); + void updatePlotArea(int left); struct SigItem { QString msg_id; @@ -51,6 +51,7 @@ signals: void zoomIn(double min, double max); void zoomReset(); void remove(); + void axisYLabelWidthChanged(int w); private slots: void msgRemoved(uint32_t address); @@ -78,7 +79,7 @@ private: QXYSeries *createSeries(QAbstractSeries::SeriesType type); void updateSeriesPoints(); - int y_label_width = 50; + int y_label_width = 0; int align_to = 0; QValueAxis *axis_x; QValueAxis *axis_y; @@ -115,7 +116,7 @@ signals: private: void resizeEvent(QResizeEvent *event) override; - void alignCharts(bool force = false); + void alignCharts(); void newChart(); ChartView * createChart(); void removeChart(ChartView *chart); @@ -148,7 +149,7 @@ private: QAction *columns_cb_action; QComboBox *columns_cb; int column_count = 1; - int align_to = 0; + int current_column_count = 0; }; class SeriesSelector : public QDialog { From b462463fbfdc3f4336206bf12b2f07e35473ac3a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 6 Feb 2023 17:09:13 -0800 Subject: [PATCH 0852/1179] installer: do not translate git progress strings (#27238) --- selfdrive/ui/installer/installer.cc | 6 +++--- selfdrive/ui/translations/main_de.ts | 12 ------------ selfdrive/ui/translations/main_ja.ts | 12 ------------ selfdrive/ui/translations/main_ko.ts | 12 ------------ selfdrive/ui/translations/main_pt-BR.ts | 12 ------------ selfdrive/ui/translations/main_zh-CHS.ts | 12 ------------ selfdrive/ui/translations/main_zh-CHT.ts | 12 ------------ 7 files changed, 3 insertions(+), 75 deletions(-) diff --git a/selfdrive/ui/installer/installer.cc b/selfdrive/ui/installer/installer.cc index 7d8bbf74e0..1af72c04df 100644 --- a/selfdrive/ui/installer/installer.cc +++ b/selfdrive/ui/installer/installer.cc @@ -141,9 +141,9 @@ void Installer::cachedFetch(const QString &cache) { void Installer::readProgress() { const QVector> stages = { // prefix, weight in percentage - {tr("Receiving objects: "), 91}, - {tr("Resolving deltas: "), 2}, - {tr("Updating files: "), 7}, + {"Receiving objects: ", 91}, + {"Resolving deltas: ", 2}, + {"Updating files: ", 7}, }; auto line = QString(proc.readAllStandardError()); diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 2606df5efe..0bf91bf440 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -312,18 +312,6 @@ Installing... Installiere... - - Receiving objects: - Empfange Objekte: - - - Resolving deltas: - Unterschiede verarbeiten: - - - Updating files: - Dateien aktualisieren: - MapETA diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 16f35dffaa..15f803dd99 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -311,18 +311,6 @@ Installing... インストールしています... - - Receiving objects: - オブジェクトをダウンロードしています: - - - Resolving deltas: - デルタを解決しています: - - - Updating files: - ファイルを更新しています: - MapETA diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index f50d2d9b3f..d0bc63c9e3 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -311,18 +311,6 @@ Installing... 설치중... - - Receiving objects: - 수신중: - - - Resolving deltas: - 델타병합: - - - Updating files: - 파일갱신: - MapETA diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 445de72fc3..75807eebad 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -312,18 +312,6 @@ Installing... Instalando... - - Receiving objects: - Recebendo objetos: - - - Resolving deltas: - Resolvendo deltas: - - - Updating files: - Atualizando arquivos: - MapETA diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 792a918770..ac96d9c711 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -311,18 +311,6 @@ Installing... 正在安装…… - - Receiving objects: - 正在接收: - - - Resolving deltas: - 正在处理: - - - Updating files: - 正在更新文件: - MapETA diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index e8e2ab6bd3..8ccf028f67 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -311,18 +311,6 @@ Installing... 安裝中… - - Receiving objects: - 接收對象: - - - Resolving deltas: - 分析差異: - - - Updating files: - 更新檔案: - MapETA From 8f6521ded3c06b52f0d3c1389e4077be3f184329 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Feb 2023 10:57:37 +0800 Subject: [PATCH 0853/1179] cabana: improve charts toolbar (#27233) * improve toolbar * add text --- tools/cabana/chartswidget.cc | 19 +++++++++++-------- tools/cabana/chartswidget.h | 2 ++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index a271df9dd7..d482b71cb3 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -22,6 +22,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); toolbar->setIconSize({16, 16}); + toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), ""); new_plot_btn->setToolTip(tr("New Plot")); @@ -36,17 +37,16 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->addWidget(stretch_label); - toolbar->addWidget(new QLabel(tr("Range:"))); - toolbar->addWidget(range_lb = new QLabel(this)); + range_lb_action = toolbar->addWidget(range_lb = new QLabel(this)); range_slider = new QSlider(Qt::Horizontal, this); range_slider->setToolTip(tr("Set the chart range")); range_slider->setRange(1, settings.max_cached_minutes * 60); range_slider->setSingleStep(1); range_slider->setPageStep(60); // 1 min - toolbar->addWidget(range_slider); + range_slider_action = toolbar->addWidget(range_slider); reset_zoom_btn = toolbar->addAction(utils::icon("zoom-out"), ""); - reset_zoom_btn->setToolTip(tr("Reset zoom (drag on chart to zoom X-Axis)")); + reset_zoom_btn->setToolTip(tr("Reset zoom")); remove_all_btn = toolbar->addAction(utils::icon("x"), ""); remove_all_btn->setToolTip(tr("Remove all charts")); dock_btn = toolbar->addAction(""); @@ -159,12 +159,15 @@ void ChartsWidget::setMaxChartRange(int value) { } void ChartsWidget::updateToolBar() { - range_lb->setText(QString(" %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); title_label->setText(tr("Charts: %1").arg(charts.size())); - dock_btn->setIcon(utils::icon(docking ? "arrow-up-right" : "arrow-down-left")); - dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); + range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); + range_lb_action->setVisible(!is_zoomed); + range_slider_action->setVisible(!is_zoomed); + reset_zoom_btn->setVisible(is_zoomed); + reset_zoom_btn->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); remove_all_btn->setEnabled(!charts.isEmpty()); - reset_zoom_btn->setEnabled(is_zoomed); + dock_btn->setIcon(utils::icon(docking ? "arrow-up-right-square" : "arrow-down-left-square")); + dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); } void ChartsWidget::settingChanged() { diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 66ef98991f..dc92be89f9 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -134,6 +134,8 @@ private: QLabel *title_label; QLabel *range_lb; QSlider *range_slider; + QAction *range_lb_action; + QAction *range_slider_action; bool docking = true; QAction *dock_btn; QAction *reset_zoom_btn; From ae99a6d15d363ac01f970f266dd7bc7a13ae7366 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Feb 2023 10:58:24 +0800 Subject: [PATCH 0854/1179] cabana: paint points in drawForeground instead of switching opengl mode (#27239) --- tools/cabana/chartswidget.cc | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index d482b71cb3..a5abb8dc64 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -503,7 +503,7 @@ void ChartView::updateSeriesPoints() { // Show points when zoomed in enough 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; }); - auto end = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto end = std::lower_bound(begin, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); int num_points = std::max(end - begin, 1); int pixels_per_point = width() / num_points; @@ -512,21 +512,6 @@ void ChartView::updateSeriesPoints() { ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8)); } else { s.series->setPointsVisible(pixels_per_point > 20); - - // TODO: On MacOS QChartWidget doesn't work with the OpenGL settings that CameraWidget needs. -#ifndef __APPLE - // OpenGL mode lacks certain features (such as showing points), only use when drawing many points - bool use_opengl = pixels_per_point < 1; - s.series->setUseOpenGL(use_opengl); - - // Qt doesn't properly apply device pixel ratio in OpenGL mode - QApplication *application = static_cast(QApplication::instance()); - float scale = use_opengl ? application->devicePixelRatio() : 1.0; - - QPen pen = s.series->pen(); - pen.setWidth(2.0 * scale); - s.series->setPen(pen); -#endif } } } @@ -592,7 +577,7 @@ void ChartView::updateAxisY() { if (!s.series->isVisible()) continue; auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - auto last = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); for (auto it = first; it != last; ++it) { if (it->y() < min) min = it->y(); if (it->y() > max) max = it->y(); @@ -783,6 +768,19 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } } + + // paint points. OpenGL mode lacks certain features (such as showing points) + painter->setPen(Qt::NoPen); + for (auto &s : sigs) { + if (s.series->useOpenGL() && s.series->isVisible() && s.series->pointsVisible()) { + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); + auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + for (auto it = first; it != last; ++it) { + painter->setBrush(s.series->color()); + painter->drawEllipse(chart()->mapToPosition(*it), 4, 4); + } + } + } } QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type) { From 6fb5661abba34971e547941e0f6a6625bef3b75a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 6 Feb 2023 20:02:30 -0800 Subject: [PATCH 0855/1179] setup: add serial to request headers (#27237) * setup: add dongle ID to request headers * rename openpilot * fix str * hardware: get_serial * set serial instead * fix typo * static * fixes --- selfdrive/ui/qt/setup/setup.cc | 5 +++++ system/hardware/base.h | 2 ++ system/hardware/tici/hardware.h | 17 +++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index f1ffabf6c6..231c4c2ad6 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -29,6 +29,9 @@ void Setup::download(QString url) { auto version = util::read_file("/VERSION"); + struct curl_slist *list = NULL; + list = curl_slist_append(list, ("X-openpilot-serial: " + Hardware::get_serial()).c_str()); + char tmpfile[] = "/tmp/installer_XXXXXX"; FILE *fp = fdopen(mkstemp(tmpfile), "w"); @@ -38,6 +41,7 @@ void Setup::download(QString url) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_USERAGENT, (USER_AGENT + version).c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); int ret = curl_easy_perform(curl); @@ -50,6 +54,7 @@ void Setup::download(QString url) { emit finished(false); } + curl_slist_free_all(list); curl_easy_cleanup(curl); fclose(fp); } diff --git a/system/hardware/base.h b/system/hardware/base.h index f6e0b42d73..6cfc1d8743 100644 --- a/system/hardware/base.h +++ b/system/hardware/base.h @@ -16,6 +16,8 @@ public: static int get_voltage() { return 0; }; static int get_current() { return 0; }; + static std::string get_serial() { return "cccccc"; } + static void reboot() {} static void poweroff() {} static void set_brightness(int percent) {} diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index 521a257627..5f6fb2dc50 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -21,6 +21,23 @@ public: static int get_voltage() { return std::atoi(util::read_file("/sys/class/hwmon/hwmon1/in1_input").c_str()); }; static int get_current() { return std::atoi(util::read_file("/sys/class/hwmon/hwmon1/curr1_input").c_str()); }; + static std::string get_serial() { + static std::string serial(""); + if (serial.empty()) { + std::ifstream stream("/proc/cmdline"); + std::string cmdline; + std::getline(stream, cmdline); + + auto start = cmdline.find("serialno="); + if (start == std::string::npos) { + serial = "cccccc"; + } else { + auto end = cmdline.find(" ", start + 9); + serial = cmdline.substr(start + 9, end - start - 9); + } + } + return serial; + } static void reboot() { std::system("sudo reboot"); }; static void poweroff() { std::system("sudo poweroff"); }; From 55ad7ee3cb50256bdc16c6777e2432bcf9f702eb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 7 Feb 2023 13:14:07 +0800 Subject: [PATCH 0856/1179] cabana: remove toolbutton padding (#27240) * remove toolbutton padding * fix incorrect checked state in setSeriesType --- tools/cabana/chartswidget.cc | 18 +++++++++--------- tools/cabana/chartswidget.h | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index a5abb8dc64..3cd2c80326 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -22,7 +21,6 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); toolbar->setIconSize({16, 16}); - toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), ""); new_plot_btn->setToolTip(tr("New Plot")); @@ -45,8 +43,11 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { range_slider->setPageStep(60); // 1 min range_slider_action = toolbar->addWidget(range_slider); - reset_zoom_btn = toolbar->addAction(utils::icon("zoom-out"), ""); + reset_zoom_action = toolbar->addWidget(reset_zoom_btn = new QToolButton()); + reset_zoom_btn->setIcon(utils::icon("zoom-out")); reset_zoom_btn->setToolTip(tr("Reset zoom")); + reset_zoom_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + remove_all_btn = toolbar->addAction(utils::icon("x"), ""); remove_all_btn->setToolTip(tr("Remove all charts")); dock_btn = toolbar->addAction(""); @@ -84,7 +85,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); - QObject::connect(reset_zoom_btn, &QAction::triggered, this, &ChartsWidget::zoomReset); + QObject::connect(reset_zoom_btn, &QToolButton::clicked, this, &ChartsWidget::zoomReset); QObject::connect(columns_cb, SIGNAL(activated(int)), SLOT(setColumnCount(int))); QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged); QObject::connect(dock_btn, &QAction::triggered, [this]() { @@ -163,8 +164,8 @@ void ChartsWidget::updateToolBar() { range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); range_lb_action->setVisible(!is_zoomed); range_slider_action->setVisible(!is_zoomed); - reset_zoom_btn->setVisible(is_zoomed); - reset_zoom_btn->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : ""); + reset_zoom_action->setVisible(is_zoomed); + reset_zoom_btn->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : ""); remove_all_btn->setEnabled(!charts.isEmpty()); dock_btn->setIcon(utils::icon(docking ? "arrow-up-right-square" : "arrow-down-left-square")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); @@ -799,11 +800,10 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type) { } void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { + line_series_action->setChecked(type == QAbstractSeries::SeriesTypeLine); + scatter_series_action->setChecked(type == QAbstractSeries::SeriesTypeScatter); if (type != series_type) { series_type = type; - line_series_action->setChecked(type == QAbstractSeries::SeriesTypeLine); - scatter_series_action->setChecked(type == QAbstractSeries::SeriesTypeScatter); - for (auto &s : sigs) { chart()->removeSeries(s.series); s.series->deleteLater(); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index dc92be89f9..3e32dc069f 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -138,7 +139,8 @@ private: QAction *range_slider_action; bool docking = true; QAction *dock_btn; - QAction *reset_zoom_btn; + QAction *reset_zoom_action; + QToolButton *reset_zoom_btn; QAction *remove_all_btn; QGridLayout *charts_layout; QList charts; From 074e74ad08e199f189d4d84f73b2a9df1061eb97 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Tue, 7 Feb 2023 11:37:03 -0800 Subject: [PATCH 0857/1179] setup: check installer is elf (#27241) --- selfdrive/ui/qt/setup/setup.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 231c4c2ad6..0617214f08 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -20,6 +20,17 @@ const std::string USER_AGENT = "AGNOSSetup-"; const QString DASHCAM_URL = "https://dashcam.comma.ai"; +bool is_elf(char *fname) { + FILE *fp = fopen(fname, "rb"); + if (fp == NULL) { + return false; + } + char buf[4]; + size_t n = fread(buf, 1, 4, fp); + fclose(fp); + return n == 4 && buf[0] == 0x7f && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F'; +} + void Setup::download(QString url) { CURL *curl = curl_easy_init(); if (!curl) { @@ -44,10 +55,9 @@ void Setup::download(QString url) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); int ret = curl_easy_perform(curl); - long res_status = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status); - if (ret == CURLE_OK && res_status == 200) { + if (ret == CURLE_OK && res_status == 200 && is_elf(tmpfile)) { rename(tmpfile, "/tmp/installer"); emit finished(true); } else { From 1a0a6387409203e1a2611eb35882de7a931ca703 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Tue, 7 Feb 2023 11:37:25 -0800 Subject: [PATCH 0858/1179] setup: replace software selection widget with input dialog (#27236) * setup: replace software selection widget with input dialog * revert https://github.com/commaai/openpilot/pull/21617/commits/3f7047651c31b209c9c4a0b8ff7bd408aca3f9e5 --- selfdrive/ui/qt/setup/setup.cc | 116 +++-------------------- selfdrive/ui/qt/setup/setup.h | 1 - selfdrive/ui/translations/main_de.ts | 12 --- selfdrive/ui/translations/main_ja.ts | 12 --- selfdrive/ui/translations/main_ko.ts | 12 --- selfdrive/ui/translations/main_pt-BR.ts | 12 --- selfdrive/ui/translations/main_zh-CHS.ts | 12 --- selfdrive/ui/translations/main_zh-CHT.ts | 12 --- 8 files changed, 14 insertions(+), 175 deletions(-) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 0617214f08..392be68a12 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -185,7 +185,20 @@ QWidget * Setup::network_setup() { QPushButton *cont = new QPushButton(); cont->setObjectName("navBtn"); cont->setProperty("primary", true); - QObject::connect(cont, &QPushButton::clicked, this, &Setup::nextPage); + QObject::connect(cont, &QPushButton::clicked, [=]() { + auto w = currentWidget(); + QTimer::singleShot(0, [=]() { + setCurrentWidget(downloading_widget); + }); + QString url = InputDialog::getText(tr("Enter URL"), this, tr("for Custom Software")); + if (!url.isEmpty()) { + QTimer::singleShot(1000, this, [=]() { + download(url); + }); + } else { + setCurrentWidget(w); + } + }); blayout->addWidget(cont); // setup timer for testing internet connection @@ -212,106 +225,6 @@ QWidget * Setup::network_setup() { return widget; } -QWidget * radio_button(QString title, QButtonGroup *group) { - QPushButton *btn = new QPushButton(title); - btn->setCheckable(true); - group->addButton(btn); - btn->setStyleSheet(R"( - QPushButton { - height: 230; - padding-left: 100px; - padding-right: 100px; - text-align: left; - font-size: 80px; - font-weight: 400; - border-radius: 10px; - background-color: #4F4F4F; - } - QPushButton:checked { - background-color: #465BEA; - } - )"); - - // checkmark icon - QPixmap pix(":/img_circled_check.svg"); - btn->setIcon(pix); - btn->setIconSize(QSize(0, 0)); - btn->setLayoutDirection(Qt::RightToLeft); - QObject::connect(btn, &QPushButton::toggled, [=](bool checked) { - btn->setIconSize(checked ? QSize(104, 104) : QSize(0, 0)); - }); - return btn; -} - -QWidget * Setup::software_selection() { - QWidget *widget = new QWidget(); - QVBoxLayout *main_layout = new QVBoxLayout(widget); - main_layout->setContentsMargins(55, 50, 55, 50); - main_layout->setSpacing(0); - - // title - QLabel *title = new QLabel(tr("Choose Software to Install")); - title->setStyleSheet("font-size: 90px; font-weight: 500;"); - main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop); - - main_layout->addSpacing(50); - - // dashcam + custom radio buttons - QButtonGroup *group = new QButtonGroup(widget); - group->setExclusive(true); - - QWidget *dashcam = radio_button(tr("Dashcam"), group); - main_layout->addWidget(dashcam); - - main_layout->addSpacing(30); - - QWidget *custom = radio_button(tr("Custom Software"), group); - main_layout->addWidget(custom); - - main_layout->addStretch(); - - // back + continue buttons - QHBoxLayout *blayout = new QHBoxLayout; - main_layout->addLayout(blayout); - blayout->setSpacing(50); - - QPushButton *back = new QPushButton(tr("Back")); - back->setObjectName("navBtn"); - QObject::connect(back, &QPushButton::clicked, this, &Setup::prevPage); - blayout->addWidget(back); - - QPushButton *cont = new QPushButton(tr("Continue")); - cont->setObjectName("navBtn"); - cont->setEnabled(false); - cont->setProperty("primary", true); - blayout->addWidget(cont); - - QObject::connect(cont, &QPushButton::clicked, [=]() { - auto w = currentWidget(); - QTimer::singleShot(0, [=]() { - setCurrentWidget(downloading_widget); - }); - QString url = DASHCAM_URL; - if (group->checkedButton() != dashcam) { - url = InputDialog::getText(tr("Enter URL"), this, tr("for Custom Software")); - } - if (!url.isEmpty()) { - QTimer::singleShot(1000, this, [=]() { - download(url); - }); - } else { - setCurrentWidget(w); - } - }); - - connect(group, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *btn) { - btn->setChecked(true); - cont->setEnabled(true); - }); - - return widget; -} - QWidget * Setup::downloading() { QWidget *widget = new QWidget(); QVBoxLayout *main_layout = new QVBoxLayout(widget); @@ -387,7 +300,6 @@ Setup::Setup(QWidget *parent) : QStackedWidget(parent) { addWidget(getting_started()); addWidget(network_setup()); - addWidget(software_selection()); downloading_widget = downloading(); addWidget(downloading_widget); diff --git a/selfdrive/ui/qt/setup/setup.h b/selfdrive/ui/qt/setup/setup.h index 8027e8bd4f..f990b5a6cb 100644 --- a/selfdrive/ui/qt/setup/setup.h +++ b/selfdrive/ui/qt/setup/setup.h @@ -14,7 +14,6 @@ private: QWidget *low_voltage(); QWidget *getting_started(); QWidget *network_setup(); - QWidget *software_selection(); QWidget *downloading(); QWidget *download_failed(); diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 0bf91bf440..b40812af7c 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -674,18 +674,6 @@ location set Waiting for internet Auf Internet warten - - Choose Software to Install - Software zum installieren auswählen - - - Dashcam - Dashcam - - - Custom Software - Spezifische Software - Enter URL URL eingeben diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 15f803dd99..ed08a52df5 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -672,18 +672,6 @@ location set Waiting for internet インターネット接続を待機中 - - Choose Software to Install - インストールするソフトウェアを選択してください - - - Dashcam - ドライブレコーダー - - - Custom Software - カスタムソフトウェア - Enter URL URL を入力 diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index d0bc63c9e3..7b742a5048 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -672,18 +672,6 @@ location set Waiting for internet 네트워크 접속을 기다립니다 - - Choose Software to Install - 설치할 소프트웨어를 선택하세요 - - - Dashcam - Dashcam - - - Custom Software - Custom Software - Enter URL URL 입력 diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 75807eebad..a25c51de3c 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -676,18 +676,6 @@ trabalho definido Waiting for internet Esperando pela internet - - Choose Software to Install - Escolher Software para Instalar - - - Dashcam - Dashcam - - - Custom Software - Sofware Customizado - Enter URL Preencher URL diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index ac96d9c711..68c1bb766f 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -670,18 +670,6 @@ location set Waiting for internet 等待网络连接 - - Choose Software to Install - 选择要安装的软件 - - - Dashcam - Dashcam(行车记录仪) - - - Custom Software - 自定义软件 - Enter URL 输入网址 diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 8ccf028f67..71315e118f 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -672,18 +672,6 @@ location set Waiting for internet 連接至網路中 - - Choose Software to Install - 選擇要安裝的軟體 - - - Dashcam - 行車記錄器 - - - Custom Software - 定制的軟體 - Enter URL 輸入網址 From 01bdf382c4bd8a30444c0bde3b737a95f5813f42 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Feb 2023 12:52:50 -0800 Subject: [PATCH 0859/1179] CI: temporarily remove timeouts --- .github/workflows/prebuilt.yaml | 1 - .github/workflows/release.yaml | 1 - .github/workflows/selfdrive_tests.yaml | 20 -------------------- .github/workflows/tools_tests.yaml | 4 ---- 4 files changed, 26 deletions(-) diff --git a/.github/workflows/prebuilt.yaml b/.github/workflows/prebuilt.yaml index c8b4c51e38..1fd093e2ac 100644 --- a/.github/workflows/prebuilt.yaml +++ b/.github/workflows/prebuilt.yaml @@ -16,7 +16,6 @@ jobs: build_prebuilt: name: build prebuilt runs-on: ubuntu-20.04 - timeout-minutes: 60 if: github.repository == 'commaai/openpilot' env: IMAGE_NAME: openpilot-prebuilt diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8df89dcc38..7f83f61e0a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -8,7 +8,6 @@ jobs: build_masterci: name: build master-ci runs-on: ubuntu-20.04 - timeout-minutes: 60 if: github.repository == 'commaai/openpilot' steps: - name: Wait for green check mark diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index d5be221303..834b2141d0 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -32,7 +32,6 @@ jobs: build_release: name: build release runs-on: ubuntu-20.04 - timeout-minutes: 30 env: STRIPPED_DIR: /tmp/releasepilot steps: @@ -66,7 +65,6 @@ jobs: build_all: name: build all runs-on: ubuntu-20.04 - timeout-minutes: 30 steps: - uses: actions/checkout@v3 with: @@ -84,7 +82,6 @@ jobs: #build_mac: # name: build macos # runs-on: macos-latest - # timeout-minutes: 60 # steps: # - uses: actions/checkout@v3 # with: @@ -141,7 +138,6 @@ jobs: docker_push: name: docker push runs-on: ubuntu-20.04 - 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: @@ -150,14 +146,12 @@ 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 @@ -166,7 +160,6 @@ jobs: static_analysis: name: static analysis runs-on: ubuntu-20.04 - timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -174,13 +167,11 @@ 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: 20 steps: - uses: actions/checkout@v3 with: @@ -198,7 +189,6 @@ jobs: unit_tests: name: unit tests runs-on: ubuntu-20.04 - timeout-minutes: 30 steps: - uses: actions/checkout@v3 with: @@ -207,7 +197,6 @@ jobs: - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - name: Run unit tests - timeout-minutes: 15 run: | ${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \ $UNIT_TEST common && \ @@ -242,7 +231,6 @@ jobs: process_replay: name: process replay runs-on: ubuntu-20.04 - timeout-minutes: 25 steps: - uses: actions/checkout@v3 with: @@ -280,7 +268,6 @@ jobs: test_modeld: name: model tests runs-on: ubuntu-20.04 - timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -293,12 +280,10 @@ jobs: run: | ${{ env.RUN }} "scons -j$(nproc)" - name: Run model replay with ONNX - timeout-minutes: 2 run: | ${{ env.RUN_CL }} "ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \ coverage xml" - name: Run unit tests - timeout-minutes: 5 run: | ${{ env.RUN_CL }} "$UNIT_TEST selfdrive/modeld && \ coverage xml" @@ -308,7 +293,6 @@ jobs: test_longitudinal: name: longitudinal runs-on: ubuntu-20.04 - timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -323,7 +307,6 @@ jobs: 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 @@ -336,7 +319,6 @@ jobs: test_cars: name: cars runs-on: ubuntu-20.04 - timeout-minutes: 20 strategy: fail-fast: false matrix: @@ -355,7 +337,6 @@ jobs: - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - name: Test car models - timeout-minutes: 12 run: | ${{ env.RUN }} "coverage run -m pytest selfdrive/car/tests/test_models.py && \ coverage xml && \ @@ -369,7 +350,6 @@ jobs: car_docs_diff: name: PR comments runs-on: ubuntu-20.04 - timeout-minutes: 20 if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml index 94cc3c2580..3b32d3c790 100644 --- a/.github/workflows/tools_tests.yaml +++ b/.github/workflows/tools_tests.yaml @@ -30,7 +30,6 @@ jobs: plotjuggler: name: plotjuggler runs-on: ubuntu-20.04 - timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -38,7 +37,6 @@ 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 && \ @@ -49,7 +47,6 @@ jobs: simulator: name: simulator runs-on: ubuntu-20.04 - timeout-minutes: 30 env: IMAGE_NAME: openpilot-sim if: github.repository == 'commaai/openpilot' @@ -74,7 +71,6 @@ jobs: docs: name: build docs runs-on: ubuntu-20.04 - timeout-minutes: 25 steps: - uses: actions/checkout@v3 with: From 9af82c090e1bcb0d76b4c2468d538c75b6e9c650 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 7 Feb 2023 15:01:47 -0800 Subject: [PATCH 0860/1179] ublox_day_fix --- selfdrive/locationd/ublox_msg.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 3ff768ba06..33ac2fe088 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -358,9 +358,6 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ eph.setAge(data->e_n()); eph.setP4(data->p4()); eph.setSvURA(glonass_URA_lookup.at(data->f_t())); - if (msg->sv_id() != data->n()) { - LOGE("SV_ID != SLOT_NUMBER: %d %d", msg->sv_id(), data->n()) - } eph.setSvType(data->m()); } @@ -374,6 +371,13 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // the year can be fetched later in laika (note rollovers and leap year) uint8_t n_4 = data->n_4(); uint16_t year = get_glonass_year(n_4, current_day); + if (current_day > 1461) { + // impossible day within last 4 year, reject ephemeris + // TODO: check if this can be detected via hamming code + LOGE("INVALID DATA: current day out of range: %d, %d", current_day, n_4); + glonass_strings[msg->sv_id()].clear(); + return kj::Array(); + } uint16_t last_leap_year = 1996 + 4*(n_4-1); uint16_t days_till_this_year = (year - last_leap_year)*365; From 4f6fbdf590fdcd9e1327cb42905fa17542d64f73 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 7 Feb 2023 15:02:21 -0800 Subject: [PATCH 0861/1179] Revert "ublox_day_fix" This reverts commit 9af82c090e1bcb0d76b4c2468d538c75b6e9c650. --- selfdrive/locationd/ublox_msg.cc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 33ac2fe088..3ff768ba06 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -358,6 +358,9 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ eph.setAge(data->e_n()); eph.setP4(data->p4()); eph.setSvURA(glonass_URA_lookup.at(data->f_t())); + if (msg->sv_id() != data->n()) { + LOGE("SV_ID != SLOT_NUMBER: %d %d", msg->sv_id(), data->n()) + } eph.setSvType(data->m()); } @@ -371,13 +374,6 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // the year can be fetched later in laika (note rollovers and leap year) uint8_t n_4 = data->n_4(); uint16_t year = get_glonass_year(n_4, current_day); - if (current_day > 1461) { - // impossible day within last 4 year, reject ephemeris - // TODO: check if this can be detected via hamming code - LOGE("INVALID DATA: current day out of range: %d, %d", current_day, n_4); - glonass_strings[msg->sv_id()].clear(); - return kj::Array(); - } uint16_t last_leap_year = 1996 + 4*(n_4-1); uint16_t days_till_this_year = (year - last_leap_year)*365; From 6330cdd88513d9dad3e5ab00811c4a5223924423 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 7 Feb 2023 18:49:06 -0700 Subject: [PATCH 0862/1179] GPS: add tow to gps ephemeris (#27246) * add tow to gps ephemeris * bump cereal * update refs --------- Co-authored-by: Kurt Nistelberger --- cereal | 2 +- selfdrive/locationd/ublox_msg.cc | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cereal b/cereal index bdbac40160..fa3e77b7c8 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit bdbac40160a550c88e481a3bf700a1016901bd9b +Subproject commit fa3e77b7c8eee8752f19427b34adcb1ae5c70ec5 diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 3ff768ba06..877ace9a06 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -213,6 +213,7 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m eph.setAf1(subframe_1->af_1() * pow(2, -43)); eph.setAf0(subframe_1->af_0() * pow(2, -31)); eph.setSvHealth(subframe_1->sv_health()); + eph.setTowCount(subframe.how()->tow_count()); iodc_lsb = subframe_1->iodc_lsb(); } diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 2c66c7075c..f98caa80a7 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -7c2a98f4a94b6dded6a90d8913ab85a63069c186 \ No newline at end of file +d862b2c7d383d859db30d6c1cc665c29c7a2a9f3 \ No newline at end of file From 5a0cbc35a544f448e8db1e1578de7607b39a3e76 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 7 Feb 2023 18:49:51 -0700 Subject: [PATCH 0863/1179] Ubloxd: glonass ephem parsing (#27248) temp fix Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/ublox_msg.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 877ace9a06..8fa721a091 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -359,9 +359,6 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ eph.setAge(data->e_n()); eph.setP4(data->p4()); eph.setSvURA(glonass_URA_lookup.at(data->f_t())); - if (msg->sv_id() != data->n()) { - LOGE("SV_ID != SLOT_NUMBER: %d %d", msg->sv_id(), data->n()) - } eph.setSvType(data->m()); } @@ -375,6 +372,13 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // the year can be fetched later in laika (note rollovers and leap year) uint8_t n_4 = data->n_4(); uint16_t year = get_glonass_year(n_4, current_day); + if (current_day > 1461) { + // impossible day within last 4 year, reject ephemeris + // TODO: check if this can be detected via hamming code + LOGE("INVALID DATA: current day out of range: %d, %d", current_day, n_4); + glonass_strings[msg->sv_id()].clear(); + return kj::Array(); + } uint16_t last_leap_year = 1996 + 4*(n_4-1); uint16_t days_till_this_year = (year - last_leap_year)*365; From 9799359ffdc56c379955a892a92961f559f4bc19 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 7 Feb 2023 17:54:23 -0800 Subject: [PATCH 0864/1179] bump laika --- laika_repo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/laika_repo b/laika_repo index b30afe44d2..278b44ba8c 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit b30afe44d283072b6ee0ea17f290cca5d002baf7 +Subproject commit 278b44ba8c2dec28adc5b30cce13dabc195f15fc From 4d05b5b02a706eac246c6f5b545ecfc7513a6525 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 7 Feb 2023 20:11:36 -0800 Subject: [PATCH 0865/1179] Bump panda (#27249) * bumppanda * bumptomaster * bumppandaagain --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index e7f36a2992..82151aaffe 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e7f36a2992b353d7d66fbb697d166d4de8718c99 +Subproject commit 82151aaffefbb460887d09f4f5e29092d3b669ba From fe64e853639e00d6d2cc8910d66b9b8c6f56c808 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 7 Feb 2023 21:25:46 -0800 Subject: [PATCH 0866/1179] readd slot number logging --- selfdrive/locationd/ublox_msg.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 8fa721a091..b746989466 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -359,6 +359,9 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ eph.setAge(data->e_n()); eph.setP4(data->p4()); eph.setSvURA(glonass_URA_lookup.at(data->f_t())); + if (msg->sv_id() != data->n()) { + LOGE("SV_ID != SLOT_NUMBER: %d %d", msg->sv_id(), data->n()) + } eph.setSvType(data->m()); } From 583057aa413f533e761ce869abd69f2fedef39b9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 8 Feb 2023 13:46:59 +0800 Subject: [PATCH 0867/1179] cabana: add space between signal and msg name (#27252) --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3cd2c80326..f3982bb7a2 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -485,7 +485,7 @@ void ChartView::updateTitle() { } for (auto &s : sigs) { auto decoration = s.series->isVisible() ? "none" : "line-through"; - s.series->setName(QString("%2%3 %4").arg(decoration).arg(s.sig->name.c_str()).arg(msgName(s.msg_id)).arg(s.msg_id)); + s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id)); } } From 86d86fa9dafc823a9cccd9c06ba995cd510d5535 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 7 Feb 2023 23:38:05 -0800 Subject: [PATCH 0868/1179] GM: reduce steering message rate (#27201) * Lower active rate and raise limits to compensate * bump panda * bump panda * Update ref_commit * bump panda to master --- panda | 2 +- selfdrive/car/gm/values.py | 6 +++--- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/panda b/panda index 82151aaffe..7d27eb10fb 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 82151aaffefbb460887d09f4f5e29092d3b669ba +Subproject commit 7d27eb10fb32095e73f60c59a123cae08cc53719 diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index e633ec5f62..7628d8420b 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -11,10 +11,10 @@ Ecu = car.CarParams.Ecu class CarControllerParams: STEER_MAX = 300 # GM limit is 3Nm. Used by carcontroller to generate LKA output - STEER_STEP = 2 # Active control frames per command (50hz) + STEER_STEP = 3 # Active control frames per command (~33hz) INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) - STEER_DELTA_UP = 7 # Delta rates require review due to observed EPS weakness - STEER_DELTA_DOWN = 17 + STEER_DELTA_UP = 10 # Delta rates require review due to observed EPS weakness + STEER_DELTA_DOWN = 25 STEER_DRIVER_ALLOWANCE = 50 STEER_DRIVER_MULTIPLIER = 4 STEER_DRIVER_FACTOR = 100 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index f98caa80a7..170beafe88 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -d862b2c7d383d859db30d6c1cc665c29c7a2a9f3 \ No newline at end of file +a6b17ab903022b42677abe2968f3c6e50c331980 From 5b9f2c3fcd09409211f518b9074afa046a1915d6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 8 Feb 2023 00:09:49 -0800 Subject: [PATCH 0869/1179] GM: refactor steering control code (#27251) * hopefully easier to understand? * space * no confusing elif, move comment to relevant part * better --- selfdrive/car/gm/carcontroller.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 56f6ff5a31..affbcdc0fa 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -49,25 +49,26 @@ class CarController: can_sends = [] # Steering (Active: 50Hz, inactive: 10Hz) - # Attempt to sync with camera on startup at 50Hz, first few msgs are blocked - init_lka_counter = not self.sent_lka_steering_cmd - # Also send at 50Hz until we're in sync with camera so counters align when relay closes, preventing a fault - # openpilot can subtly drift, so this is activated throughout a drive to stay synced - out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.camera_lka_steering_cmd_counter + 1) % 4 - sync_steer = (init_lka_counter or out_of_sync) and self.CP.networkLocation == NetworkLocation.fwdCamera + steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP - steer_step = self.params.INACTIVE_STEER_STEP - if CC.latActive or sync_steer: - steer_step = self.params.STEER_STEP + if self.CP.networkLocation == NetworkLocation.fwdCamera: + # Also send at 50Hz: + # - on startup, first few msgs are blocked + # - until we're in sync with camera so counters align when relay closes, preventing a fault. + # openpilot can subtly drift, so this is activated throughout a drive to stay synced + out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.camera_lka_steering_cmd_counter + 1) % 4 + if not self.sent_lka_steering_cmd or out_of_sync: + steer_step = self.params.STEER_STEP - # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just received the - # next Panda loopback confirmation in the current CS frame. if CS.loopback_lka_steering_cmd_updated: self.lka_steering_cmd_counter += 1 self.sent_lka_steering_cmd = True - elif (self.frame - self.last_steer_frame) >= steer_step: + + # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just + # received the ASCMLKASteeringCmd loopback confirmation in the current CS frame + if (self.frame - self.last_steer_frame) >= steer_step and not CS.loopback_lka_steering_cmd_updated: # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus - if init_lka_counter: + if not self.sent_lka_steering_cmd: self.lka_steering_cmd_counter = CS.pt_lka_steering_cmd_counter + 1 if CC.latActive: From 303e21cbccc5bbbc8450d6a09221b77e127631b7 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 9 Feb 2023 04:40:22 +0800 Subject: [PATCH 0870/1179] cabana: improve the welcome page (#27261) --- tools/cabana/detailwidget.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 46f7a148f4..a7ad572dc1 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -232,9 +232,14 @@ WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { return hlayout; }; + auto lb = new QLabel(tr("<-Select a message to to view details")); + lb->setAlignment(Qt::AlignHCenter); + main_layout->addWidget(lb); main_layout->addLayout(newShortcutRow("Pause", "Space")); main_layout->addLayout(newShortcutRow("Help", "Alt + H")); main_layout->addStretch(0); setStyleSheet("QLabel{color:darkGray;}"); + setBackgroundRole(QPalette::Base); + setAutoFillBackground(true); } From 80bf755b075b2b56373b4ca49c2c95d1837e7648 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 9 Feb 2023 04:40:43 +0800 Subject: [PATCH 0871/1179] cabana: set correct geometry for legend (#27260) --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index f3982bb7a2..4f1f293615 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -310,7 +310,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { axis_y->setLabelFormat("%.1f"); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); - chart->legend()->layout()->setContentsMargins(0, 0, 40, 0); + chart->legend()->layout()->setContentsMargins(16, 0, 40, 0); chart->legend()->setShowToolTips(true); chart->setMargins({0, 0, 0, 0}); From 56bc5b39e3eae122d6b8f85c72c023665b32d89f Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 8 Feb 2023 16:00:30 -0500 Subject: [PATCH 0872/1179] VW MQB: Add FW for 2018 Volkswagen Tiguan (#27264) --- selfdrive/car/volkswagen/values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 9f6dee2689..72fcc5d92d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -729,6 +729,7 @@ FW_VERSIONS = { }, CAR.TIGUAN_MK2: { (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8703N906026D \xf1\x893680', b'\xf1\x8704E906027NB\xf1\x899504', b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906027G \xf1\x899893', @@ -746,12 +747,14 @@ FW_VERSIONS = { b'\xf1\x870D9300043 \xf1\x895202', b'\xf1\x870DL300011N \xf1\x892001', b'\xf1\x870DL300011N \xf1\x892012', + b'\xf1\x870DL300012P \xf1\x892103', b'\xf1\x870DL300013A \xf1\x893005', b'\xf1\x870DL300013G \xf1\x892119', b'\xf1\x870DL300013G \xf1\x892120', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AR\xf1\x890317\xf1\x82\02331310031333334313132573732379333313100', + b'\xf1\x875Q0959655BJ\xf1\x890336\xf1\x82\x1312110031333300314232583732379333423100', b'\xf1\x875Q0959655BM\xf1\x890403\xf1\x82\02316143231313500314641011750179333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02312110031333300314240583752379333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02331310031333336313140013950399333423100', @@ -763,6 +766,7 @@ FW_VERSIONS = { b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820529A6060603', b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\x0521A60604A1', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567A6000600', + b'\xf1\x875QF909144A \xf1\x895581\xf1\x82\x0571A60834A1', b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\00571A60634A1', b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1', @@ -771,6 +775,7 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572AA\xf1\x890396', b'\xf1\x872Q0907572J \xf1\x890156', + b'\xf1\x872Q0907572M \xf1\x890233', b'\xf1\x872Q0907572Q \xf1\x890342', b'\xf1\x872Q0907572R \xf1\x890372', b'\xf1\x872Q0907572T \xf1\x890383', From fcaa6fb06fd68a71b129487d80ee00918695fc5b Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 8 Feb 2023 22:03:23 +0100 Subject: [PATCH 0873/1179] cabana: extend color palette, make chart colors match signal view (#27258) * cabana: extend color palette, make chart colors match signal view * vary saturation too * cleanup --- tools/cabana/binaryview.cc | 4 +--- tools/cabana/chartswidget.cc | 1 + tools/cabana/historylog.cc | 2 +- tools/cabana/signaledit.cc | 2 +- tools/cabana/util.cc | 15 +++++++++++++++ tools/cabana/util.h | 8 +++----- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 4d7b3148c6..ddad4cd446 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -173,7 +173,6 @@ void BinaryViewModel::refresh() { if ((dbc_msg = dbc()->msg(msg_id))) { row_count = dbc_msg->size; items.resize(row_count * column_count); - int i = 0; for (auto sig : dbc_msg->getSignals()) { auto [start, end] = getSignalRange(sig); for (int j = start; j <= end; ++j) { @@ -185,10 +184,9 @@ void BinaryViewModel::refresh() { } 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].bg_color = getColor(sig); items[idx].sigs.push_back(sig); } - ++i; } } else { row_count = can->lastMessage(msg_id).dat.size(); diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 4f1f293615..4faca8314b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -525,6 +525,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even s.vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz s.last_value_mono_time = 0; + s.series->setColor(getColor(sig)); } struct Chunk { diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 95bd94e76b..3a3397af42 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -49,7 +49,7 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i } return show_signals ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { - return QBrush(QColor(getColor(section - 1))); + return QBrush(getColor(sigs[section - 1])); } } return {}; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index b871ffa21a..2f1a968645 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -279,7 +279,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } // color label - auto bg_color = QColor(getColor(item->row())); + auto bg_color = getColor(item->sig); QRect rc{option.rect.left() + 3, option.rect.top(), 22, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index f9d19dfda3..d978e4aa12 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -3,6 +3,10 @@ #include #include #include +#include + +#include +#include #include "selfdrive/ui/qt/util.h" @@ -96,6 +100,17 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & } } +QColor getColor(const Signal *sig) { + float h = 19 * (float)sig->lsb / 64.0; + h = fmod(h, 1.0); + + size_t hash = qHash(QString::fromStdString(sig->name)); + float s = 0.25 + 0.25 * (float)(hash & 0xff) / 255.0; + float v = 0.75 + 0.25 * (float)((hash >> 8) & 0xff) / 255.0; + + return QColor::fromHsvF(h, s, v); +} + NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) { } QValidator::State NameValidator::validate(QString &input, int &pos) const { diff --git a/tools/cabana/util.h b/tools/cabana/util.h index b76652f4b0..af5032fd42 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -7,6 +7,8 @@ #include #include +#include "opendbc/can/common_dbc.h" + class ChangeTracker { public: void compute(const QByteArray &dat, double ts, uint32_t freq); @@ -33,11 +35,7 @@ public: inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } -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)]; -} +QColor getColor(const Signal *sig); class NameValidator : public QRegExpValidator { Q_OBJECT From 99f12ca7f31a1d6ac8a54254f30d4a31ce628268 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 9 Feb 2023 05:29:16 +0800 Subject: [PATCH 0874/1179] cabana: fix coredump caused by getColor in updateSeries (#27265) --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 4faca8314b..8debb75153 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -525,7 +525,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even s.vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz s.last_value_mono_time = 0; - s.series->setColor(getColor(sig)); + s.series->setColor(getColor(s.sig)); } struct Chunk { From f4f081c56209a2fc0669e76e881821b43830462c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 9 Feb 2023 07:18:07 +0800 Subject: [PATCH 0875/1179] cabana: imporve series selector dialog (#27266) * imporve series selector dialog * typo --- tools/cabana/chartswidget.cc | 170 +++++++++++++++++------------------ tools/cabana/chartswidget.h | 26 +++--- 2 files changed, 96 insertions(+), 100 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8debb75153..134a162679 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -251,12 +252,14 @@ void ChartsWidget::resizeEvent(QResizeEvent *event) { } void ChartsWidget::newChart() { - SeriesSelector dlg(this); + SeriesSelector dlg(tr("New Chart"), this); if (dlg.exec() == QDialog::Accepted) { - QList series_list = dlg.series(); - if (!series_list.isEmpty()) { + auto items = dlg.seletedItems(); + if (!items.isEmpty()) { auto c = createChart(); - c->addSeries(series_list); + for (auto it : items) { + c->addSeries(it->msg_id, it->sig); + } } } } @@ -425,33 +428,24 @@ void ChartView::msgRemoved(uint32_t address) { } } -void ChartView::addSeries(const QList &series_list) { - for (auto &s : series_list) { - if (auto m = dbc()->msg(s[0])) { - auto it = m->sigs.find(s[2]); - if (it != m->sigs.end() && !hasSeries(s[0], &(it->second))) { - addSeries(s[0], &(it->second)); - } - } - } -} - void ChartView::manageSeries() { - SeriesSelector dlg(this); + SeriesSelector dlg(tr("Mange Chart"), this); for (auto &s : sigs) { - dlg.addSeries(s.msg_id, msgName(s.msg_id), QString::fromStdString(s.sig->name)); + dlg.addSelected(s.msg_id, s.sig); } - - int ret = dlg.exec(); - if (ret == QDialog::Accepted) { - QList series_list = dlg.series(); - if (series_list.isEmpty()) { + if (dlg.exec() == QDialog::Accepted) { + auto items = dlg.seletedItems(); + if (items.isEmpty()) { emit remove(); } else { - addSeries(series_list); + for (auto s : items) { + if (!hasSeries(s->msg_id, s->sig)) { + addSeries(s->msg_id, s->sig); + } + } for (auto it = sigs.begin(); it != sigs.end(); /**/) { - bool exists = std::any_of(series_list.cbegin(), series_list.cend(), [&](auto &s) { - return s[0] == it->msg_id && s[2] == it->sig->name.c_str(); + bool exists = std::any_of(items.cbegin(), items.cend(), [&](auto &s) { + return s->msg_id == it->msg_id && s->sig == it->sig; }); it = exists ? ++it : removeItem(it); } @@ -737,11 +731,9 @@ void ChartView::dropEvent(QDropEvent *event) { event->accept(); } else { ChartView *source_chart = (ChartView *)event->source(); - QList series; for (auto &s : source_chart->sigs) { - series.push_back({s.msg_id, msgName(s.msg_id), QString::fromStdString(s.sig->name)}); + addSeries(s.msg_id, s.sig); } - addSeries(series); emit source_chart->remove(); event->acceptProposedAction(); } @@ -836,40 +828,37 @@ void ChartView::handleMarkerClicked() { // SeriesSelector -SeriesSelector::SeriesSelector(QWidget *parent) { - setWindowTitle(tr("Manage Chart Series")); - QHBoxLayout *contents_layout = new QHBoxLayout(); +SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) { + setWindowTitle(title); + QGridLayout *main_layout = new QGridLayout(this); - QVBoxLayout *left_layout = new QVBoxLayout(); - left_layout->addWidget(new QLabel(tr("Select Signals:"))); - - msgs_combo = new QComboBox(this); + // left column + main_layout->addWidget(new QLabel(tr("Available Signals")), 0, 0); + main_layout->addWidget(msgs_combo = new QComboBox(this), 1, 0); msgs_combo->setEditable(true); - msgs_combo->lineEdit()->setPlaceholderText(tr("Select Msg")); + msgs_combo->lineEdit()->setPlaceholderText(tr("Select a msg...")); msgs_combo->setInsertPolicy(QComboBox::NoInsert); msgs_combo->completer()->setCompletionMode(QCompleter::PopupCompletion); msgs_combo->completer()->setFilterMode(Qt::MatchContains); - left_layout->addWidget(msgs_combo); - sig_list = new QListWidget(this); - sig_list->setSortingEnabled(true); - sig_list->setToolTip(tr("Double click on an item to add signal to chart")); - left_layout->addWidget(sig_list); + main_layout->addWidget(available_list = new QListWidget(this), 2, 0); - QVBoxLayout *right_layout = new QVBoxLayout(); - right_layout->addWidget(new QLabel(tr("Chart Signals:"))); - chart_series = new QListWidget(this); - chart_series->setSortingEnabled(true); - chart_series->setToolTip(tr("Double click on an item to remove signal from chart")); - right_layout->addWidget(chart_series); - contents_layout->addLayout(left_layout); - contents_layout->addLayout(right_layout); + // buttons + QVBoxLayout *btn_layout = new QVBoxLayout(); + QPushButton *add_btn = new QPushButton(utils::icon("chevron-right"), "", this); + QPushButton *remove_btn = new QPushButton(utils::icon("chevron-left"), "", this); + btn_layout->addStretch(0); + btn_layout->addWidget(add_btn); + btn_layout->addWidget(remove_btn); + btn_layout->addStretch(0); + main_layout->addLayout(btn_layout, 0, 1, 3, 1); + + // right column + main_layout->addWidget(new QLabel(tr("Selected Signals")), 0, 2); + main_layout->addWidget(selected_list = new QListWidget(this), 1, 2, 2, 1); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->addLayout(contents_layout); - main_layout->addWidget(buttonBox); + main_layout->addWidget(buttonBox, 3, 2); for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) { if (auto m = dbc()->msg(it.key())) { @@ -877,56 +866,59 @@ SeriesSelector::SeriesSelector(QWidget *parent) { } } msgs_combo->model()->sort(0); + msgs_combo->setCurrentIndex(-1); + QObject::connect(msgs_combo, qOverload(&QComboBox::currentIndexChanged), this, &SeriesSelector::updateAvailableList); + QObject::connect(available_list, &QListWidget::currentRowChanged, [=](int row) { add_btn->setEnabled(row != -1); }); + QObject::connect(selected_list, &QListWidget::currentRowChanged, [=](int row) { remove_btn->setEnabled(row != -1); }); + QObject::connect(available_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::add); + QObject::connect(selected_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::remove); + QObject::connect(add_btn, &QPushButton::clicked, [this]() { if (auto item = available_list->currentItem()) add(item); }); + QObject::connect(remove_btn, &QPushButton::clicked, [this]() { if (auto item = selected_list->currentItem()) remove(item);}); QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - QObject::connect(msgs_combo, SIGNAL(currentIndexChanged(int)), SLOT(msgSelected(int))); - QObject::connect(sig_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::addSignal); - QObject::connect(chart_series, &QListWidget::itemDoubleClicked, [](QListWidgetItem *item) { delete item; }); - - if (int index = msgs_combo->currentIndex(); index >= 0) { - msgSelected(index); - } } -void SeriesSelector::msgSelected(int index) { +void SeriesSelector::add(QListWidgetItem *item) { + auto it = (ListItem *)item; + addItemToList(selected_list, it->msg_id, it->sig, true); + delete item; +} + +void SeriesSelector::remove(QListWidgetItem *item) { + auto it = (ListItem *)item; + if (it->msg_id == msgs_combo->currentData().toString()) { + addItemToList(available_list, it->msg_id, it->sig); + } + delete item; +} + +void SeriesSelector::updateAvailableList(int index) { + if (index == -1) return; + available_list->clear(); QString msg_id = msgs_combo->itemData(index).toString(); - sig_list->clear(); - if (auto m = dbc()->msg(msg_id)) { - for (auto &[name, s] : m->sigs) { - QStringList data({msg_id, m->name, name}); - QListWidgetItem *item = new QListWidgetItem(name, sig_list); - item->setData(Qt::UserRole, data); - sig_list->addItem(item); + auto selected_items = seletedItems(); + for (auto &[name, s] : dbc()->msg(msg_id)->sigs) { + bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); + if (!is_selected) { + addItemToList(available_list, msg_id, &s); } } } -void SeriesSelector::addSignal(QListWidgetItem *item) { - QStringList data = item->data(Qt::UserRole).toStringList(); - addSeries(data[0], data[1], data[2]); -} +void SeriesSelector::addItemToList(QListWidget *parent, const QString id, const Signal *sig, bool show_msg_name) { + QString text = QString(" %1").arg(getColor(sig).name(), sig->name.c_str()); + if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id); -void SeriesSelector::addSeries(const QString &id, const QString &msg_name, const QString &sig_name) { - QStringList data({id, msg_name, sig_name}); - for (int i = 0; i < chart_series->count(); ++i) { - if (chart_series->item(i)->data(Qt::UserRole).toStringList() == data) { - return; - } - } - QListWidgetItem *new_item = new QListWidgetItem(chart_series); - new_item->setData(Qt::UserRole, data); - chart_series->addItem(new_item); - QLabel *label = new QLabel(QString("%0 %1 %2").arg(data[2]).arg(data[1]).arg(data[0]), chart_series); + QLabel *label = new QLabel(text); label->setContentsMargins(5, 0, 5, 0); + auto new_item = new ListItem(id, sig, parent); new_item->setSizeHint(label->sizeHint()); - chart_series->setItemWidget(new_item, label); + parent->setItemWidget(new_item, label); } -QList SeriesSelector::series() { - QList ret; - for (int i = 0; i < chart_series->count(); ++i) { - ret.push_back(chart_series->item(i)->data(Qt::UserRole).toStringList()); - } +QList SeriesSelector::seletedItems() { + QList ret; + for (int i = 0; i < selected_list->count(); ++i) ret.push_back((ListItem *)selected_list->item(i)); return ret; } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 3e32dc069f..953026d935 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -28,7 +28,6 @@ class ChartView : public QChartView { public: ChartView(QWidget *parent = nullptr); void addSeries(const QString &msg_id, const Signal *sig); - void addSeries(const QList &series_list); 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, const std::vector *events = nullptr, bool clear = true); @@ -157,19 +156,24 @@ private: }; class SeriesSelector : public QDialog { - Q_OBJECT - public: - SeriesSelector(QWidget *parent); - void addSeries(const QString &id, const QString& msg_name, const QString &sig_name); - QList series(); + struct ListItem : public QListWidgetItem { + ListItem(const QString &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {} + QString msg_id; + const Signal *sig; + }; -private slots: - void msgSelected(int index); - void addSignal(QListWidgetItem *item); + SeriesSelector(QString title, QWidget *parent); + QList seletedItems(); + inline void addSelected(const QString &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); } private: + void updateAvailableList(int index); + void addItemToList(QListWidget *parent, const QString id, const Signal *sig, bool show_msg_name = false); + void add(QListWidgetItem *item); + void remove(QListWidgetItem *item); + QComboBox *msgs_combo; - QListWidget *sig_list; - QListWidget *chart_series; + QListWidget *available_list; + QListWidget *selected_list; }; From d096ec1329dcf55bdda3125c76b6a89849892dc4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 8 Feb 2023 15:18:27 -0800 Subject: [PATCH 0876/1179] bump opendbc (#27253) --- opendbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc b/opendbc index 0b7439f551..d103b156b3 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 0b7439f551168f202fb033b7e3e177048687e726 +Subproject commit d103b156b36f2bc9d0d6ad9ba1af02a42ecc2b46 From 276586fdf051caa86feef1820e6732567d22c19c Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 9 Feb 2023 00:18:56 +0100 Subject: [PATCH 0877/1179] cabana: bit level change frequency highlighting (#27259) * cabana: bit level change highlighting * change default color --- tools/cabana/binaryview.cc | 25 ++++++++++++++++++++++++- tools/cabana/binaryview.h | 2 +- tools/cabana/streams/abstractstream.cc | 1 + tools/cabana/streams/abstractstream.h | 1 + tools/cabana/util.cc | 8 ++++++++ tools/cabana/util.h | 1 + 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index ddad4cd446..a46c25bdfa 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -7,6 +7,8 @@ #include #include +#include + #include "tools/cabana/commands.h" #include "tools/cabana/streams/abstractstream.h" @@ -212,6 +214,19 @@ void BinaryViewModel::updateState() { for (int i = 0; i < binary.size(); ++i) { for (int j = 0; j < 8; ++j) { items[i * column_count + j].val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0'; + + // Bit update frequency based highlighting + bool has_signal = items[i * column_count + j].sigs.size() > 0; + double offset = has_signal ? 50 : 0; + + double min_f = last_msg.bit_change_counts[i][7 - j] == 0 ? offset : offset + 25; + double max_f = 255.0; + + double factor = 0.25; + double scaler = max_f / log2(1.0 + factor); + + double alpha = std::clamp(offset + log2(1.0 + factor * (double)last_msg.bit_change_counts[i][7 - j] / (double)last_msg.count) * scaler, min_f, max_f); + items[i * column_count + j].bg_color.setAlpha(alpha); } hex[0] = toHex(binary[i] >> 4); hex[1] = toHex(binary[i] & 0xf); @@ -264,10 +279,18 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->setPen(option.palette.color(QPalette::BrightText)); } else if (!item->sigs.isEmpty() && (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig))) { bool sig_hovered = item->sigs.contains(bin_view->hovered_sig); - painter->fillRect(option.rect, sig_hovered ? item->bg_color.darker(125) : item->bg_color); // 4/5x brightness + int min_alpha = item->sigs.contains(bin_view->hovered_sig) ? 255 : 50; + QColor bg = item->bg_color; + if (bg.alpha() < min_alpha) { + bg.setAlpha(min_alpha); + } + painter->fillRect(option.rect, sig_hovered ? bg.darker(125) : bg); // 4/5x brightness painter->setPen(sig_hovered ? option.palette.color(QPalette::BrightText) : Qt::black); + } else { + painter->fillRect(option.rect, item->bg_color); } + painter->drawText(option.rect, Qt::AlignCenter, item->val); if (item->is_msb || item->is_lsb) { painter->setFont(small_font); diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index f697ea28cb..d006672793 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -36,7 +36,7 @@ public: } struct Item { - QColor bg_color = QApplication::style()->standardPalette().color(QPalette::Base); + QColor bg_color = QColor(102, 86, 169, 0); bool is_msb = false; bool is_lsb = false; QString val = "-"; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 8a77e0eb39..94d653bcb0 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -34,6 +34,7 @@ bool AbstractStream::updateEvent(const Event *event) { change_trackers[id].compute(data.dat, data.ts, data.freq); data.colors = change_trackers[id].colors; data.last_change_t = change_trackers[id].last_change_t; + data.bit_change_counts = change_trackers[id].bit_change_counts; } double ts = millis_since_boot(); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 0dbb3d96a6..8c10d959cb 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -16,6 +16,7 @@ struct CanData { QByteArray dat; QVector colors; QVector last_change_t; + QVector> bit_change_counts; }; class AbstractStream : public QObject { diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index d978e4aa12..2806e175d7 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -18,6 +18,7 @@ void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { if (prev_dat.size() != dat.size()) { colors.resize(dat.size()); last_change_t.resize(dat.size()); + bit_change_counts.resize(dat.size()); std::fill(colors.begin(), colors.end(), QColor(0, 0, 0, 0)); std::fill(last_change_t.begin(), last_change_t.end(), ts); } else { @@ -39,6 +40,13 @@ void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { colors[i] = blend(colors[i], QColor(102, 86, 169, start_alpha / 2)); // Greyish/Blue } + // Track bit level changes + for (int bit = 0; bit < 8; bit++){ + if ((cur ^ last) & (1 << bit)) { + bit_change_counts[i][bit] += 1; + } + } + last_change_t[i] = ts; } else { // Fade out diff --git a/tools/cabana/util.h b/tools/cabana/util.h index af5032fd42..5d5b44d63c 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -17,6 +17,7 @@ public: QVector last_change_t; QVector colors; + QVector> bit_change_counts; private: const int periodic_threshold = 10; From ec6a55057ffe381fb65ba946e29cb59f0ee694e7 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 8 Feb 2023 17:51:53 -0800 Subject: [PATCH 0878/1179] Rename GM CS variable to be consistent to the CAN parsers --- selfdrive/car/gm/carcontroller.py | 2 +- selfdrive/car/gm/carstate.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index affbcdc0fa..97f8b60e59 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -56,7 +56,7 @@ class CarController: # - on startup, first few msgs are blocked # - until we're in sync with camera so counters align when relay closes, preventing a fault. # openpilot can subtly drift, so this is activated throughout a drive to stay synced - out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.camera_lka_steering_cmd_counter + 1) % 4 + out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.cam_lka_steering_cmd_counter + 1) % 4 if not self.sent_lka_steering_cmd or out_of_sync: steer_step = self.params.STEER_STEP diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 8ea8ea8874..b73b7e7059 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -19,7 +19,7 @@ class CarState(CarStateBase): self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] self.loopback_lka_steering_cmd_updated = False self.pt_lka_steering_cmd_counter = 0 - self.camera_lka_steering_cmd_counter = 0 + self.cam_lka_steering_cmd_counter = 0 self.buttons_counter = 0 def update(self, pt_cp, cam_cp, loopback_cp): @@ -35,7 +35,7 @@ class CarState(CarStateBase): self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 if self.CP.networkLocation == NetworkLocation.fwdCamera: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] - self.camera_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] + self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] ret.wheelSpeeds = self.get_wheel_speeds( pt_cp.vl["EBCMWheelSpdFront"]["FLWheelSpd"], From 134766fe26443b5f2dca8e9df274229894028035 Mon Sep 17 00:00:00 2001 From: eFini Date: Thu, 9 Feb 2023 10:05:23 +0800 Subject: [PATCH 0879/1179] Toyota: Car Port for Toyota C-HR 2021 (TSS2) (#27212) * Toyota C-HR 2021 TSS2 Port * remove --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 5 +++-- selfdrive/car/tests/routes.py | 1 + selfdrive/car/toyota/interface.py | 2 +- selfdrive/car/toyota/values.py | 26 +++++++++++++++++++++++--- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c48698b84f..b73f09334d 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 233 Supported Cars +# 234 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -174,7 +174,8 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index ce38eeb0de..535d3f5415 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -179,6 +179,7 @@ routes = [ CarTestRoute("0a0de17a1e6a2d15|2020-09-21--21-24-41", TOYOTA.PRIUS_TSS2), CarTestRoute("9b36accae406390e|2021-03-30--10-41-38", TOYOTA.MIRAI), CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR), + CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.CHR_TSS2), CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH), CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V), diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 8e180e2301..438a9c11fc 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -72,7 +72,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.5533 ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max - elif candidate in (CAR.CHR, CAR.CHRH): + elif candidate in (CAR.CHR, CAR.CHRH, CAR.CHR_TSS2): stop_and_go = True ret.wheelbase = 2.63906 ret.steerRatio = 13.6 diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 3046814fac..7e801990a7 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -49,6 +49,7 @@ class CAR: CAMRY_TSS2 = "TOYOTA CAMRY 2021" # TSS 2.5 CAMRYH_TSS2 = "TOYOTA CAMRY HYBRID 2021" CHR = "TOYOTA C-HR 2018" + CHR_TSS2 = "TOYOTA C-HR 2021" CHRH = "TOYOTA C-HR HYBRID 2018" COROLLA = "TOYOTA COROLLA 2017" COROLLA_TSS2 = "TOYOTA COROLLA TSS2 2019" @@ -115,7 +116,8 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CAMRYH: ToyotaCarInfo("Toyota Camry Hybrid 2018-20", video_link="https://www.youtube.com/watch?v=Q2DYY0AWKgk"), CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-22", footnotes=[Footnote.CAMRY]), CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-23"), - CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-21"), + CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), + CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ @@ -633,6 +635,23 @@ FW_VERSIONS = { b'8646FF407000 ', ], }, + CAR.CHR_TSS2: { + (Ecu.abs, 0x7b0, None): [ + b'F1526F4270\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'8965B10091\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x0189663F459000\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821FF410300\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646FF411100\x00\x00\x00\x008646GF409000\x00\x00\x00\x00', + ], + }, CAR.CHRH: { (Ecu.engine, 0x700, None): [ b'\x0289663F405100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00', @@ -2030,6 +2049,7 @@ DBC = { CAR.LEXUS_RX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.LEXUS_RXH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.CHR: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), + CAR.CHR_TSS2: dbc_dict('toyota_nodsu_pt_generated', None), CAR.CHRH: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CAMRY: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CAMRYH: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), @@ -2072,7 +2092,7 @@ EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_I # Toyota/Lexus Safety Sense 2.0 and 2.5 TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, - CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2} + CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2} NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} @@ -2080,7 +2100,7 @@ NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} UNSUPPORTED_DSU_CAR = {CAR.LEXUS_IS, CAR.LEXUS_RC} # these cars have a radar which sends ACC messages instead of the camera -RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022} +RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2} EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, From ccfa73ff12da9ef5d2d939fb9018d9103128d299 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 8 Feb 2023 18:33:19 -0800 Subject: [PATCH 0880/1179] Remove Bolt EV platform from torque params Was merged into EUV --- selfdrive/car/torque_data/override.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 0a49d39914..462ce91b36 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -26,7 +26,6 @@ COMMA BODY: [.nan, 1000, .nan] RAM 1500 5TH GEN: [2.0, 2.0, 0.0] RAM HD 5TH GEN: [1.4, 1.4, 0.0] SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] -CHEVROLET BOLT EV 2022: [2.0, 2.0, 0.05] CHEVROLET BOLT EUV 2022: [2.0, 2.0, 0.05] CHEVROLET SILVERADO 1500 2020: [1.9, 1.9, 0.112] CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05] From 955c1dff454babe200862f0011e639ec500938b3 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 8 Feb 2023 19:06:59 -0800 Subject: [PATCH 0881/1179] ui: dmoji (#27070) * will draw * gradient * bg * add sense of depth * refactor * cleanup * fix endpoint * clean up * use array * 1 matmul * lives in modeldata * standstill only * remove bad pts * do less math * smooth * kind * fix d * lineswidth * fade in and out * hide * quick * gray out * fix joints * offset * rest icon * clean up * circle as state * longlat * new design * gap and g * scaledown, fix jts and unlock not standstill * width * different * intermediate * sand * motion effect * vis * fix bg * clean up * t * btn_size * small speedup * sligh * clean up * facelift * match .2 * .4 is good * size * no ss * rhd compat * less filt * more line * engaged * not white * drop prop * this is fine * independent falg * sg * dont look like hitman * cleanup * little more --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/assets/img_driver_face.png | Bin 24112 -> 19875 bytes selfdrive/ui/qt/onroad.cc | 62 +++++++++++++++++++++++---- selfdrive/ui/qt/onroad.h | 2 + selfdrive/ui/ui.cc | 35 ++++++++++++++- selfdrive/ui/ui.h | 18 ++++++++ 5 files changed, 108 insertions(+), 9 deletions(-) diff --git a/selfdrive/assets/img_driver_face.png b/selfdrive/assets/img_driver_face.png index ddde478cd789ec47ae87593d8d413336de653218..03765a0376dc33e72f88fb68d0f3879bffff90ff 100644 GIT binary patch literal 19875 zcmV)BK*PU@P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O559(&RdhrTJg0=p~4x__Z90q|9aqv;27;dPG)c zRaRHG*<|Fs@m>#ixkLg7=YRm>+W+tW^IiYzfBmoU+`U{+uC4S^ZvOZ5r^mq$?f(6* zpMQt@IsZQYo9oY?g@1kh`o|wcUP}C)e*am=pZ5=5&;Rj(zuytwe|`OGfBq!4KNtG* z2Y)Y^{N~6H>z{9u*W>T?@cg+@-@hM9Z}p#V^^JcX<t^D~X)pO~8T*Uvr{`rNc zvPvuSt`y@=A>HTS?RN*se^MIfcmG{|-}#w8yZ9}nzjwld{LAD0{r$fGd4c|Ak^la5 z{pZ#H$4~!h@#FaOdiqamS^lgMKm6N22>IVH{#oLG`r`DDJBt7M2dk(2UmoYrKi{|7 z_wC=)ji<1p<&Q<(*WcCgGraL-$ilZ=xF?&l?s>obnxTitu6$Q` z!U`jNVV~b;nB3wMcVtguj5DV5T4RrToa_}_xiw%8J{Kvh7^S%9i z-wcg!UV*p9z{SGZ?EmK1^}qYW|C?Xe_f3~5-0dH0#eGFBm)mgX{5S7nL&EoG-||`D zzrX%$|NT$)gQ>EE`7Cqe0muFRF7f8@AGVdwJ}2In`Tge=;i~J;1y~}!J99H3u>*Gr zDTfm78e!+%oa5pq~L+6Vm~|Yvg>ZU@9|-4U;3Uef90!R`}#Njv1@;J^}qc3zu2|#XV>D{Dc@KB zv1`0~)%y1mK{(0o89NrAz>ZgU0E3S1+18+A_|~vtvImbWQJs_wnbujVm_Z zvH2Ot1kcKz-^_KV`+Zj2-~LAA=1QG!>b1ms_6A1gucnXqb$=;uKr^lDV?jsaE_Qg^ z<{Q>x%~s<%OKJBLS=vcR0-GKd_};m-{e(0(Pkld&Z+N-!aK$z9kiyhPH+0c;Qj-9^v%V)#`iodHo#V5s2dmz^BwmFoo2ri+cpazfHB9u z!2G;+uayUB>wE6+&I{arvcYBwDKDN!`>sW)$aGLO`OD>Hv5*# zlUaicOoVG?q7k30YsdI;VSF{j_YL)X6L(&?Mg|r!|HR90XlwB(8cyD0=Dymsb{Q#s zJ>Vg4T63-z*FN`IG2?;F)D_t^o|WuXZI9t9k zpT(zgdibJu&lEG}GxJ;f1TZkrG6~tEE?{M0ChU5u`@LD-c&~!BtPka=OQIwS{o#Xb3RRz2p5T`ka&D?$&(Ojnp6 z_=XdX);`Z32ztaIdbj0%bs zHrCyFuvW^uu+rVqcP{wV4XPLZeZA;#n6wpXbMQGQky- zeoM!V14s$p%z;MvD(i%+-de8K#}yLZ41j2SA7nBBBbD1WG_Kw;JE9Pn!uo!&AY(oF z11Ro-k>S{26ON4yV$(P_IPv@(d*usAe&^mFpb7r67sRJo_-Nd0UGKybya~V>UnWlB zfcLlOHtKL=X|fw@ueq=OrqnZ56ieD=reM6NY;WQY@4oXp+znJ1fBdkAFL7O;hPC9c zJzRt}+Up|F?^SPbDCHp$p3fjIY1=IW2-wBKRURD`I4?Nb_*!6{f$)J5mM?-$&sBIM zW>L7{l&^oi9yrfHQQwfUy}lg*-BRD0&rm*?3HVk%7CRcEp0x_d z)}95@c)zuWjF|04TWK)138soNmy!kJCI)Q)0~=m=2zJ)q`Vh`5Yt8evcVBCeORQnP^@51tNWeM! z&+Qxapnq>1Z6B!z!GutCmU}|U+R&gzUu!DoB+-d4{KVlq-jET zvgEQTR58Z4v1NH0QwZLnfJY4|%o8z)9j*gy&3k_#iNFN$^JN>6HT7nnLM-qEuJnfr zVNJUcTP5sl7(mm0?({%K6L0%Ky6igC1pvKRkhGyXhK^zas0#ofV2l(LZN!|fM zB<}uB^ZK|52o5gjH98@vzB(&JgorTM)^d$}>kA4ekQO84vB>T zSfH`$2Ju0p$+*SFm5J70#2Ma-Q-S>tD-OFtsK9veZ0<3Gwa|w5+E43`-0H=Mp~~&v zs}XfpZK1Xf96_wX0wH^&UEi;dazl>bJ8(8A1Bi@_fM{u;o8@x1->)_-8T%Imv2LOc z23PWl38}JQ2@=2az`2Q@gjrM#&Yv#!i|v+Cf9w)o4T(vm^`Qt6wuzYoe#34AYF%n;hM<~s{FC30t-tvwDVZe7foJYOx)d&B)ISCAK$S3^W zkh|dQy|^J8{z62$2F6T`S_traH$*xZ(dX^voM>-&VWH862nx0&FD!@~#^N^axC^Rv z&Zl0n!nb$|JV~a-<|7IxP=i%1&>k7`p_ATTpcRz>w}=xERTMrHp+k&$Ok5RTVG3Xj>}?okHwYl_6H5Ou)qz~ck-iG|hrv!aHQgP{Hfultf@TG* z^5&+H!$u|86%h9wlfWC})?oU3W#spZawzM0N5dH(^H*>AO(<36eGc=m~xB{8jbb3 zfsOl8(X)p2+%!IDVu1KapqU5j3R(jw=29yBhj%}iCUCS-oaR1J4pDlH`=BsCF9r4d zMPz`WiGt8*?$xliLD*L)W@d5Ba{EZ21PTJ6MkubdF8BvGA^CtoK%M2hfC<60ePy8kV~#5#0I`8) z5(Afp510i7l|e<^6PLmu2M*7TjPZP$aV=n;d4j<6H=rMFhGY!W$o{w$3%2vZL2q%Q zJ~u>yaCspV6VKLaeWZ^G&QFBFDE33R!2_To@cxbLf)ebw%qA4T-~mUc6{jv zYV0+F=zFFL9rv!HM%_aK4u<<4q7gdZ6A4qSTtl`G6bd~jNAhD2Y!6gktA%G)^Iq6Y z$2=hl1AYU=#R5V`y3GAtnlxNw{)90BG5v-3*E?i~CsZm)BHBpvNr4B%2J`VNa06_@ z@b<-4-``LogI(Yu7|M!2Y8ME}oZu^wkd5fgFbvms0SNcsyV*wJ0z9wnVkrpyr9ivP z`pFXETgd2082XSqSPn|KB5R3WbA#ZRR7^PRV0XZHu0;St)ZkGsdh?EWIwW&6w1;+P zByh>Nxp#XBf~7HGoXjFDB_m^?7-&US^^#R0rn(HDzyN~a#0gt~941tZ1e6G}Dtdwo zgaU}&(4z=r<+q&FEC94b3ptT6*1mpG6xzpkJ|Ou9p^WWr&|tCN!d}8D4u%m0@8;8* z_3dmwK^8zoiQw~zr{YnF6Zi!|MjZ*iGq|xO&d-Kus39goefjma(&xH^c|S zB5J%c(H9@!o{2;()!t_Jqe45t)-E&;(W$a_v;KAq&Q5d;<8|dSi-Qmxh>DY0ReuB5 zL|)eISQ0pBdh#O3gHb#&Ot5T}d&Hll8w3TI9R64FFSty>kLv?h1>w2d=@uag0X?~3 zAoiF2@N)%6Baw1J$7Rqj%oI5UQ3HJ+Q|apbjDGOc3tGl1o0~L;841PLi!6BMGXs=v z01LQ-`aJAupA^jw2va<+)CV-sOIB_;FS=)Rh>xc+DO})*nWLwnxeSyzwn->WrbGGx zXN>iU3kZh_o4#b5J5Io#e{ou)6k$>0$J4K4K{yk^V>z-a0W%AL*DOlUx8k_fi|0)``Ca0UwHrl~eU z?yAp)ikp9M@J14qB%fmU(5Ef;4G-ow6T)VPHO-B3U)uMAv=PszDt|p!5x@)frpV*A z5=;2JMC#gWG=@HAH9V23E~Rl4M#K6geD5hlcIDxymvn95{fkHsyY$PdNxJ}aJRp6x zDj;RBmc449DKE5ZOv9V!bNwZH-eyL*fTUlG#Uv3+DA0$<2X1W-hbnKtX9;3#G*84m z;3uz%laB1%0|4Od7qJF*5bDXYa5*+LAASP(a|>n!u;$q0`Hzf%I7ejqB8K7l2X_SM z?05|n8BnL7-^z3J{5_(f5qg0&-W~uz`)cJIE7296zytomI->W(YI)S}V$XTp4kUVl z6pp=mko5)_Hcmo}t}OXtDF`Gy4$twJ^6ZEI&Vk^nM2(9JRD~xV`w=ET$V;pb?0s;j zAo7;vMU|}#0~Bn~h?@`u7LC{RY|V*XxO|`jeh~|Z*vqV5E4O456GuD>gYEcR?0o$7 zEBR*0GjSA&45>wUV@H4**bQ(Pe+U}cTb`dO2@~3K)B;Mu4%0knKUtiB`8+pw+~m0^ z)#u{#xqX@{JBKDB9d+*wjF1509dg4p!SIF?N|Y&_9m zjNC*J!)6g5A0b-Z{{0eUY<50k4ATKW@Q_0i30zrq#J3V=H{p_CA5F=yOX0&=z$-IU z>zJYcVFJ)YD@$L9SV&(5COVfW(#)6Fj5vBQDNn#G!`K5gkK&J_0+#mPo}5j^zzj%_ z{yQ|oT)b~l>e?ONzEP^s7R2Vgvtf7=$BxJ|DUWZBb5h5bXLIGB`W6!3jyS=8OI=sr zC7rD0(NuY$KyjZ0q@!KD26y5)v96=a(1t|4} zs2@kn>REhst{=;;I0+ACbz8hd2saIpO@y_3%L4M1*)xx24B!u|{VgOU$m$_q>XisL zJQVNzDb$%e2g3s^D3C@M!hSKno0eRl+<$%KxWIW3wtT&uk!JR!&6C0o! zEcVwXMuve5$cP6qFuDX+!myx`t~+rU{VX??m%J`0q;=+ac;E|7gg{l)QJ>=^y>Cy+ zO&c^5!pB>14|GV9YT;3y6$KE5n2($FY)*tPAXww?#o_;f=SdqZr-Dc-*Uvl=kN0Bc5hkh!V97= zS(Cgy2Eys^bGE>wFl33vW$|L?Q#a%rtZk=UBY%^J3D-8}4CLi08eof204!lo0w6jU z=3OVT3aJ8Pipf+5RQV2oCt^wzXn_5?wlxDR*xLsrx@@GYnhqNPWGDCe5e#+1bN1tb znxYQLd{+Ntv(uMwkynp|5_-%E*{cx3VMa_z`RCO87X*pco?9YtYa>*$)6ZvKp_n9@ z$ z!{Pu{Gb{Hw$M*!EHG9v)sNd>>>`2E!k*;&?<+1wh_VW|*qj=o>D?%_U4X(h6zN73| zIac|DlV)PULU$t*K*487BC+~6rYqj(XqZ6o5gAt6?Zr@Eg3sWCPxm0_Bl30ZUU+;# z+MLZcTh2+;9|RX7C*rtE7cjeLb?e|v%@Kc=n}*hVq~tAd$#c}>*cD^PJjwZjEK5(K$Ht{TO<~dCb zdmt=kJk($z#R@lZR^aJKPp_22TJ@aP@ZKiQR00 zc@;bwLJOhl%6)iRBINKyEEJ$IJeZ7Tlo5p|p&W0bd^0hz(IOR1fo(%=*VuR(TGwcK zj^y8#%kv=iLI)gII!A63f63;gkU0dEWmW~oMv%P+YiU-wkBZlsHOv4sg3^dK_kwqI zOHvN8wUnZ88G9(d0R*AzFT;JNU%q!dNP%+4N#MWX|$MuZ02ZFnbkpK-Sp(L(ZI(}$b8zBf32+0%% zWX>egQ{w}5YDqecDImyRkBU)U-+!V>*AHL_Y&UVRwAVwFYOY4o;PIJG0@0gRSfS>D zk6Eo(v@oT9SnA2E;(qec5GVgZC=MT#Z}o#DE&fkPa{Z?l03wiNz8@hXW~)CuC+0QcJhpp| z)bRF@EJOLuiO_NO?D-ld_h}yh;`6+}yzmV-`8W{6U2I7=`VlZCrM!gk<#_d5~}Z!yDT!Rd)0;7sOj)X?EFU?<34lyCCMS7KiQ@!%=n zsgRHdo4~k>>3$;nXb>F23{(kf^u<$uR3$$i9^onfbTs_0=FaN=_aXe267-AhEe$qb zd?c;T`o=OQw}eHrnp#|>tF-AX(Qq-J7E65-s}31H%NzR%`AMZc{X!uie~jV zA$<@fbH)fCZPk*8pxVkEc=U*<+}K#VFJxePzmq$KTmEa5{GWagMDV{}di`5B64e>7JBZBVtF*W6JbbqgxIOM54fYD9zJSKCk8Erfkau`2m9mdH* zycTz_YH_EBZ}Mf2@l5Q1*%<1cn@Er5wwWTflHf|^)Z9Rl65Q#DFp0B&9XS3^TiY#} zj2HI%1^p{LfNnXG^|ejFbo==%2;dfZ6p0rEq&|@rQU_0lZg-#nW0FM7VJnlRfE!h3 z+8djH>a0**bB6dE;6(@+B}EqYw&Xe7fHt8te!K!*nO>-vxW{dmxyV!q5w9T`8^)rL zgAnIZiIPD`I7bwd#XuQI5ItGeyRU|wj)(hgvd4%U1y2=bHlNhb4=P*$bA$)hQsFtvPH zO1W&WdHy`@9RD5T_{OPnD?<695k(sD{R;W6h3?41)0P`^^jsYVY0(gI*TSU;qMhKtUM<6ohvSI?3XDz7J8@`HtJJ8C9cyA15exbiS_lXP#pDl zM^J8*+OgJnZe8~BlQ{YJ6{Z*kc1H|)%yu$WMCF%_-^AEsJ^B4>9M^xg5=-&#M>x;rCxXGobH@;_Nen@vd=*w| z4$Q*XQ|=V=Ws2hzF&QKMSbHtw^qADt|KVhJ`Jc7u^{*TJ5{M(J`ZHgCa@P|U8~C;m za723>mesmb>p}|?{6r2Y`PGDu@W=Qv@#I+bXC2*V*9RWD?NNZX=@;c>&`m#?r}C}| zBS?~XJyYWUL{?;57&AQ}2)encwa@TzRL1+?Bt;=o2FY^$ip~3p66;r&?y&|@A}OKe z4Q;Xb!gVl!g6RD_VjOc~(X)~A804?Ee}J@=xuO)iEG)0&4KmK<*xNAC5) zNN?;GOAWbXo1u83bAoRJK>5`W0r2=A&uI^x>~%i`)_bEmS^V#XrC!x;p!|Hq`_~id zVYc->7zt^BD)9DE*~*T^LmdXj{&G(eG!|;z?kXhjl2Yz;Ds?2s5k-ps!Xc%H9{zl< zA>^bso0TMluBpfz#aPKMyXrywmq~rk|LFnrrY{cEDUZpOsB9t+uZIs1iCW(iO6+o zCsCRqqKG}asCPo^Kh;{nei~bna)12o67XQ$;=TfJc#f}~4wkzUz%1ko8`KCN&{&5B ze+a9Uw1odA)&H-W)*rH{9;e5qf)2rDXBMX8J{UdgzGH?84c6_pNvV7IfRp~p#LTdp zKC8r(9`?Ofu$&LO$hI|@oWYi(g_m>i+%`@q&<}Zfg7g~&zb#yV`Bxi_5)e;Z>95@5 zHOWmtwP16cdWE4?Ta9m36@(x1w(|q>5R3@tvn`<3HZMHG!%d4u&8oJ~ZU8GMA9w&p z{PG3+j@t1!N6@xtoHFw7542wY5|P=Odv-f)>is+j(TpUCSnJ*vNuC51>J~8|?D?-y z*Wf8rxV-R(CcuLft?1HDtT@YoL>yKNU}*8^4VZAT|72irw;>0OYJVdBw=Sr3A%L5d zVFgX0cl(2u{SJU6YRyz%!)5K2c(YZjv6<9|Mz{XhKT&FcM7#mZwTcQnYPb?wbhK)z zK6ltz`$Ie?2pV{_#{-NyCj=wSK3Qc$lWUabSL|`fCtro(LmmpY%u7h5usx=K`_rOA z3`jyVSwS!}7;#GF?*+CD|Z3w^93z}YW+G2lMePi-ii%2;nupf-9cc+1|tVRU#kTwjsBeKrG#^L+dN8AH{9CaYS28 zO2l6i!QmoYZfN8UEpwZLV9zXlvZF(v1?Ru`KqBnA^^W2Hga3a6UTTi>-vVKl%-wcv zlvBE}J^z9=d>4`*g=HMP&CN;KAa63}vpse(d?J2ejb3bbty+mHx-!9u0HPkVgQcH* z65%$bc_aq$aWqIZ-bz?x4~6ZeZb^#}86 zWtxe7tTThLcN>k;{g+_tekYs%&hoA8OZN9S z+kV(MnAgW`{mw~`?03>d=Qab&Q7`q4W# z;3-wyr+dQMPj*hkTBkDN3d*K0?uLui{94dx*(`xDbem($Cn4CTZE~epTnGsogNR$g zsdLTG$%S5^N6WAumkH9J<{Ry}B^nkBF$sq7l%DLP7#5Y<@6tVdt1L?X9ib58En+SU zq&9;Mj=vBWds%VRWqQd<&GFQ6;->}Li#UC3)g&9%_u;*-M;BMN0slUS#g8y==`)yO z4QB8}nQ-HYZ2Nk$72P=*C^vQjfz)5S!L9CuXq`+w%)A3r#DNZzXH9rU>z;~-P4Lbt zrCbEHSZrP98H~kTkq0R-e{;3J#LKsC*zC!V#eY6U!jHGccv|eBu+!?_`mkY*XifOD zOu=GLMNKxjVUeHZll)0xrxas7jefioA$RIxZ5BUuvCv5yi^?PNfM#|OUIHZs*c$@5 zHn?mK){V1MaF{YoDx)5%f$IK>SdPzN(7z5gi`UR)Y}nQI2W5eaJTFFP^P08}0$Fba zv0hHJNxEjVu)BP>wM^V~#ZS6rZ}uilFxyiq5Nh}#@B|BLZdiFt{MwFW^WA3{dQQO< zAPZ~5ax2eEgpMeiSi*Jo+lovOdKSLN446_#|EvZM7IIss;`^}xP8K)VawNKn8&I7UUIoKz~qxEQ!28g{a7~U2&oetbn zik>ZNe!`A7KpM;f!Ds5x+UO1F#b<6GNnz0-Bm=K1GAH)Ql({FzES7b~Mgu$oupp8) zs}&H%T(R3=cth`Fx0&F+RLUd#8vH`B8|ha7JIaQaL2KcWl;xa6xSgNYaz{^W2rKn>mG5ZUzgKa5&RGBG z1F!5kc&$RMr@{=THRK6RemhN^ z_k(rvO+9BsjhR8HHzEdP4tC3@f-5CEqa@#VyiW{42zXQieCTzsgwMX6+f&EHdR<3? zCbL>*4b15jh}^>bdk7vRi}~E`cS3d&|FDr4MD1)#v?Z+*-qy7(o2`=i1ebx~Rx84K zv`tF|iX-LcRf7P=fsZarvMhSR{vnVB0)Ujv7sg2JB9L^MIa?fmg`oicgKeJEq|eh8 z%yB@-?q*RG!QlCo78wRX%6MUah@6U>1AqzJM4*D6_F`eeD9T*B!qNPa^?rnu7v{2& zd`^3SKs*yn0*}zMrwS_Ys0J+T1|Odg40DOB&mhLC0J7Z_!M0j^U_w%GzzZ#y1AZ^N zzzY9qBa^T#_rN~F_>Xj1)a7i7Er2SJT&zzgoTIREN;gW<=^h7Sn&UW3reIX#oEAWQ zABSs*%NC~+qPS^Tl8IBM|sj;+xWOe)rP-lTZIxq5i#4A2=Wm4 zV18yNT2hwUx59NB4xnV-cQS-&45&o3@SYcBb)BsOpkDMpC>0RHaQrVLec5B;v`MC5 zC0uf~_qKV?X*iNdHckP3J)-kmAP_u-csf}79pHKn)p!hkj-6luL06M5tytm!OOSF{ z#m5q&;@V}u6f~k#dlZr-k3B_T`*aze{%o_7k?VvrL8mE>u=adPD(AM7(+0!KKIdB>59tXVX_@I#2SDy654Eqxh;(*00I)WIG6p4EG2j@79K3UO*X2Q zY%wJ?u3_-0{;F*)C74dF0t#NcRqfQ{h8{@(B*EG@WQpSevQ-hc=`?G(cSIdIX#=(S z$mmZ*#L~?3(~g$R_HV z2G?3FUW02r{!~+Z%kW7UMO67~TXH^4(J5?7`~; zH1aOnf=%EN$y|3l(&w?XJap@zhV^z6wLi**i~YtNK?$=}IQ@(VV$1ol5nDnH2up(N zPoo6f!yYtO={x<}xWwpS_UQ$$%Fh`4Ik0LDtGKJJh5)do8Slxz13{J?dm8)Mr27%& z#&0lAD}hcS8;$Cc-eD--?m?_MXk3UWY zu;R!{sTq~3M-)1-Z;V5Ab4kK&2I zbBqvox8u~2XMYYZCn0LRUpnPQ(OPYu32bJ~Ev~TL0Bf{6xY(Hl19v>xT$WQg5-XQsp-y+;&22Se zI0R<-9q;K*YrfRjZylcKGi`XfNl!iIYK??3yZ0Co`nMHC=c zW5gnfG?qW!@HuCSbWFJY#v_=k9|@;D=YL0f;5?31$iuNNtgu}YENJbHIx!7VZEUdp zHT*#3v~e`snSB!Y?lPxW0M2$qj9?W0; zQLtWPTN1nPwuMegS@;eO9nt+a?@iV*$G9q+i|(UK@_c&+JIGqYyOm zR0F~W3xM$kFmhc3hf9zMk4GH0*qzG4wJ@P%;~xaY%2oub!v`+HoBV^je%iIZ+J4&^cCD&`aM zLUy`$?GdvfIBkz5^RKEkIS_#RfsLedy)9pU)tT82XT*Ob0ut2iJF?vZ7q(2*U97ft zd0r2QJD)|L*sPJqseo|zIG{S#r2h((5dc#-m4ZhL>!MvFXs>)23`g)F4ct(k_B1sjg;sJ%_3UO=}iU8we}gG#TjkIq&J@f;>C==V)!e(GP)%kr~U$>r|4NbUwP08d6_2b#RsE1f4$C_~_- z1&GB_Af@d)qkoa?<{^JoYPtjB$P|jr0T51L7cuv|5O(J-C?I14pTms9TYuziS$5J+ zS%l{yR{0W(i#236mE4Dro0)hKF&AXE5jSoJxAY8YiO|c_UuGvfss?doQG<sTY2f}9v$n-|o^FAm*KHMobWSNag0Fys1<>1%dI92pq;@As2|^(@_#);aL~ z-;@So5Y{a%#f!@Cx6<)(Rw|c(^`n*G_cpd(0CPCiB>C4j6DncUsP0iE7H&YvF#oq^ z`<_rZ@g}}?`+xE6=72X(!dUElDuDp*d3d%|aozgf=YUh^Ld_A8Me#k;>?+Vb9ON?J zzjMYMGj;*Fz4kL_Y>eP2m1^e$T89VIP3V+J@@Yt0{d0%t2p9+DG zX6N+4UtSo8Q@2z(iIj;A~w z{@+Ohk6)*ZlZvcE>($943q{Yn?MaQMfuJ=`jkNOob!f?w3ph^jY4Oak>wv_@%AV~| z8qdj3Kag+f&T>v)ZrC`!rg}q5C$lt;*)+Jhw^^4m`#CG5YyTOq=s+bKh=HgP&cF~G zatT=%JanP~h_jDJdQgp1{_2zo8$2z!16!QxI$N>y>M@{$7Y??Bh53G9YFu~~H1H%= zoqKcIqm?%fs=}&xflmXU&R|u&wO(L%_rQ_3F9#o-)1Y*niVc{tQ8+so6kQCTmL5pZ zG4N%2<8%JVY4WN*)wHAfakx%Ka>Mn25rF7{3~WA)%@R%_zA(Pu8Q4691cfIw1G`T@ zIo#Kdwfo)D;fN!s7Op4>2F{CWNJBaGg8_RyYV_BpZzzF{Us2r zem#aS6s`T+)=oIn1%M#fydJ~YIBAa0*?Q?TyS&h{X#@U~F(fmf!7>x@Xhu^Er*d1Y z|9CWl<*$49w8JPP5$>vw;@Q*ZEW2fi4Y=^JIrgkw7CrJL6@$lyNB*YvuO{))z;)nZ!L z%)dj22|Z_u8>^VOSIplwd=$eI9uvVlI~UC6LLs9@*uNuvTXLi??)LsPK5-^+JH=yb z%q1Qnb0UEGEoUDccryKFV=k;7uD`5>pLc@&*oI(~d-Cbalv0Cm+2VHNuL)Rh`wZ&k z+QDWiz`ucw3cd2{{Q^jWV?460aj%i*%rUZ23ZY>>a&{9YgvyAmZ=;!$kFH!!6U=Ru zb0#i00)lYq#2lEn&Hac5=gkJETZJHUy!>^Dk;Tl?wtCrTVowM}uRF^!%zs~nWtDq(8Yjr}aMIbwKC^$EQB(EL(6l21H6#Nxif6)OK=V}q zguu)#AbHabyS9+-!7WP$n{6h3{$_@=;~Fkg_sfF5=2+w03ZJ&yTowp02WKz`v*g2m zvSwuy(KdPY`$R?x}6)+RR8L3Q#f2#LM);K)a(Mn!8Vlharn zEnTs2u(w%DVJDt#w2;+y#-LegS|GisSZHI#X#1Apk(4L<*-6-lV|o43u$(?m<0zvBl65ZdQzavuNiZqj~qQ zjMTViPfcZ&A<#XkH%(~c@z$WA8>aP}r{TDs$)REc7keF@1@kqfZ-Fe7_j;V3I-WUs z`xhm}mh_|noq^2=-pLtkmhqkg#kCIn1A{M&pm9_7dyRGq2LQcw^#!*g_O3uiu3F>!l- z=(i_eka)PsgW-;ApMo{$Z?|GNf5yHChWj`6IcK;a8;%IgPd%}Z$U^|P3B3I6(?PGv zm}l(fDp-Ah`lR(?)J_+5tgu5YkXXNBuw=Xno>&`rcK9f`PGOBePb2`9aI8X!P3hm?~(a{6>HKn>7o(lM3@K%O7 zGWAT)n(1=H&1!zsw!dzDDtheiJelJFP6Dka7%))B0Vrw9p56YU@s(&#-Ddlp>V}A! z5y^N)zuW9|JA+lNxxmW{BLv_r7oO)F^5!X?0n*-G2N1RQ zmt!!wz?KqA7I1!#*Fm4HL*cW-Lv5X^d}=$n;=NCz;}qIBAhq5}hI$dX8pdY+2T9;tn008KD*{0Be0l|tjaW1{XG^S&`2EgF#4lA8J z)ELzcpnMIC%jtCQJcXT3xH9|tJ9=b)ECKvju7W~Xzp>r#gfmcI_ELp z!@psKn|8FOb1^odXCdqijOJV{yFh?hSdYU2FR z?R&Zt9I|aC5eme^pYH<(PqA0?XacqV)-$!x9PMd&4c~84bsolK8vr(vZoZF%)-#gn zSIGy|Jgr{A%9YT@FXwnWruVjAB|N{@s@weCnTlw7<1nIseCvJx{a#zD!k-Z-ztW9j z=GM{8koV8WJRgk?);dZ6&awTgeTL;hzse5BskD4Oq4wWslW;qx&5_{fQM^~MLk{Nm z9l<*J?j)7Z!xSizm6+YhTgg(ll-AYk1+$Lzh)oBki$28}ptt8>w-u2mHHrCd+eI8A zVQjY0fY|$(*f=#2S;CjY8K@GR;N%dx?>-OD#@f}lZR+vwXM!IhOFN7jDK#Q5KnbGb z0xw5N!EUip+h3-$fgN!O(E3+W6ohYo%xJ&PM?*R}Ul#F%6g$BwryAh-U%5QRFcBKt znU+wF?6PLRpXNyC+q3$R0R9{&TFwx6=EUZQ@Znz5lEtwvl_U#`bbV2?xWqZmgLRs5 zdaOTl5Ch!Wm?Fr$COICDrnqW&Z5ao_iEB=J;_Z3;CUCYcS9GxRv_fi$j=_eNGOP*B z{-qYtaj7PCyF*GIw=`dP(BG_4_OE$}kJ^4Y)OJ3>iJQ)>N2Op64v({h(-Bz?we(2C z@+XgoFHiT)7t~WMkR8rwiemZ~L4?my;xq5*K+b-|XLj6=$9T5*nG5tJqD2>%Qhp*mR*ztByqP=pGhR%q41dwn9(V5mp;2L~85jjr%`#GnxR}YV ziosV12qAzOOv=pE=Oif!&+&B+A7AfcJj?sspQ9(2HyPj)iD#K^Si~E|Q=68~d7n7K zN^*|)oOr~b3lcwaU2*x1bJ1aeXGV;4YMwYkEEYRh>0nkeRN@KZXin8AU&y$e z+3|z_!S8O(!uXh*6pjO3FSh+L1O#`1X5F^Gk8Qho0{EYSE3NIXHh}3*((7$4dIa=t z0~gnAP1yr3cYyvUT{dJ#^3xOw1>pURz9|dz-2&ZfZf~u9oIU_)>MD5y92^3}Mao|H zcz39?w|~#H`uhQ=0&=`#dS>JR000JJOGiWi000000Qp0^e*gdg32;bRa{vGf6951U z69E94oEQKA00(qQO+^Ri0tf~a55j#+V*mgR2;>2$M`Y&Wt&j^LBCevBPoiefG!tc-LCb1BV&@=bXLQ$NO9Fv)0~gAAw=1YUg_* z0xDnS+_x@7WAru17!i#6sPduvHbgvn zg{G_DLx7W0+^Fwit{|{N_G`#^l#m6i&1R(lq{a-DdcGtv3R)^SmLaJXq!@81xfPg@ z5TL2?mnAegf>Samr9l*H(3V_jCn$s`mCKP76|e{nLCF`O*wX?jr6Re&5-RXw*25A! zDF$dMX#}tmWY$LHQtO(^(MZaQrD$*80hH;4SxbN?)u1dXD;Kk!eFaLP*ETdacv89; zNi{0Oiaj3zQQ6h>YzCK9gR!vl2}-VQNN5anG(pL;U6)0R)qT=dfLvo|YR3{54oYJf zkgjxB!|nHkh3!6N?k%bPVTz6;EbN1!bEHmaa=bg4u;dR^Lfv^ysP{6zh8mr)x49wIO+>$r*rMf6Ow0$MSK?#dL zI7))aLVx;*Z3%hsT7j{&pDpK=Pv8COE2d@6NkVl~K5L?`3~ zOwK!`EdUhTP56psnRBuL&)qc-Oo@*Y$mLQ(C~(FeR;He?HehOa?nVyV&*%2Pk9}Px zOzw~dBP`{^lZ!PM0uvXOfQu(Zz>@ju04sL1z5IBEiWSnv#IY z@iwWrr3!YH$q_Qh9####0oer z#&rk+laEAXaGkAP!wUTn_~kD}ON=MbSW2x!JDdC1Yz{0b2H+RnMG*RNu>__LcuEDQ z?Nlyg$|W%6STB0A#p@|tZ)^=MG7=kmj&MrjI zNBQ3>F< zSimsLFx!+OXJHgzr!(8+lx>`+2I7#;Y?H@-gxl>PTMvE5Prn%JA zQdDjOw#%{56ti|po90rSl=B%X=WOG0DlA1=$TlwK$tbFXY~yk$B$f4OUR<_uF-}5J zC1o3Dxp09RkWoamL8ZH7*6c++0%IjhPp`mD#=VY2%76G`{LCu+ZFw;;J=QL$o z1B%d4w7KO%!{uhG@&Q7t&oo>NpgpENqbNed(T*|>4R6$>Xm6QmD2mWfw8eym7K0)* z6h&w#iXt==MQA9B&``Ej`vMA~p(sK_QG|w~2n|IQ0Sz~qQA1UGs4&w|6rrIgLPJq` zLc>jJRORzHVWy#isr2!c&`=bip$u4=dZ6L88meMTsgt0gD2mWf6rrKNHeqFIo1@8O zXn3uL;vm%mO>K(-90w@cGg>ri{J^P%hGJ$8G@qFSO|J8rzHCE_<_DNsGCDI2!J&LW zQ|e;CrfLzK`m)Rv=fq4yaA?b7K$G+JnjsxbaM%`oj?0bxLJc;J;0$kr8kh5{wPyr} zz)W>aF7^p&Pwdy18K&Q9xv5{QCEL^l&d_@Dxo4G&;M57s9H-<`o!A;UHP3OFVa7Qu zH}?Qs93U{XXH+%d)Cx?WLmHAKT*v|t9G1V@Ov9(tlofcDUw_gl&@kJS6M)Px^OJ+~ zeZU$4U?A3$Ww;Pf*$7U!{UilvjpCdG%5oFTDH~y%0Sy-fm<4OMX5Q^tuGz+Cv8^?M zukw@(-q>WYHRS{)t(HyMmAL6Us>&l<3d0sX}SUWCjf2)aMlbTY!;lko5%*#?Erw^uC!-0 zS;kuscF7VbEjp^IKUUStmb(>)?pjS1tRZm#$@1gM-eNHo!=2UZ= z5sh*Rz)=8~1Nhezznz>BzV1!C?mf5QUI?7uz%_V zx8zl_was~-1n~Kxz^wO+v3kwwG_g)~3?O}!FNcgXr<$sI0>H~GwRx&|%nF)NBbLYV z6$wme*WeSN7_sPLRC-Q>Tb^j)sgl+OjQMYRhMV`YNreI;PM88t~5mP6GH3 zfXAD^{RzNv-vMfgZ;v2f17Ht;Zv*&1Xlpekz+(-p5~9K>GE#?*0r)w9`vLq4z&~PT zh}7Wtu2V~WZUS%xfGeBDl%&}q=Db>#4dUyVQwkpdmgfLG0^p+}a%58whqP5G;E6p5 zte#I*KMUY9F##G9KXaj3Wn^o4K40Jrv1uVjNudxzMjkT+N^j~f~uL-VO~ zLRz;e!S4f@)qkBOOEIPqmTKzoKt~qcr>a{<$~^d?gei|XGq`qPaqX*1KLBvvoFE>1 zb>9~-t8$@&Ixr}!e^&qxcYN(~0J{uA@8xAls=5=vwEzxveB?0z_W*dZuRpEFVK8WX z7I!u-Y+Z){yarT^`OI4Y+zQ~5#xAexha&Q$W{?{+AX=3R>5Hc}!h}XV4B(3` zf4>mG{i?d#nC~x9XE!gPeO30f$3ZgYpxq9Q#dJTiV#fh|qhnsP6Tqdax@ozaVLwlM z0KB|qfhMHGh+@mu`Ea3OnNWeL4ZRKEj~(y5ty$D#stKoaRx-`%p!IJ6H;KsYkp|F^ zb0mmJoK0vWD>Ajx&j5I^x zc&~^&R0=T3QeR+jjsW;u$H;gyfNwJ1=UcO;3tx$qTa{XLs(DSO(i$)({h|kO9szI} znmzw5I!KG=O}hb{+w=Z$5qYj8U`#+UL=%tw&yK^LR@Ez2b!X})$K;S{I$m3<`mLTW zJFTi83mF&HECfs)DJC}3cK|%v^7m~3cLR72v6yDf0GtQl{GRtuHm^yrSkExY?O8x@ zz6;>{9q(NL;A&d5@!i$@yQi^cU3#*4dAH({*)ws2S{R>JZF%KiRrjgtUt11yruq97 zsw%W-qpaC=s`^+@7u}<(7hAFEA>!B#JyGbuVkAuEr)p%7X$|N`A${6RaKwq>5{Jw zy}wUK$XYDB86%E~dCrE%;wlywHGk7{n0olPmB?PD}*vdu-RdV9~;A5hf;%r>3DY7 z+4!n@wyOT2=WD-f?iQ#Hnig1~su!y2Pd7C6mshQ@@4+rLJiYeJiY4=D*IGK_SpdK9 z`P!QS+y>wVtX%P~aBj1#@Ie3t3n|ew&Bq%IBLtt#IY+e6XW!R`tRLvnlq<$}KTtA6oDFz_5Os&%{PQ3gGzx zpF0TPb67mwd#eJQwrtDu(SI}Ms-6IF=alSX?H;np3`7)&`xl^-PGj-B=)2Htm(F?9;9B!+1Nbn2TLA1cVxi5(R&Z#BtjYyGe~4k{J^&8^ z__c`KUBJZuX8^7=Vh33%vTQ|T#h=s;3;`-` z-WEI#w+KvkaMTWv@TcR_WSUaiy%vB<044NA&!EthI#87cP>C5OWIP622=Lhtp^jTC zL{=bKZ?+J{TAst~>RE0hMhzh4w%V0L-)0F-&epH?yAn$1S7F0aB~I2uia*>+rLv9L ami>RG56lgMCO}*O0000 z_rH+*wiKChpTa;7@>Yt(#OfZ<4~tm}M|;4;vhl(^LPY(^dJw{AW#bHtEk=`>iqUzS%50N%{8j- z$}YEbt}VxX))E^I{qB-cj%50y#B^ssZ~#kZ+am187o{8V$4mZA-@bR<;TqMTD5;wl zMQRVR(z%ps6UMbyKKdP1edq!xBn^$!Zt0wz)h33|ebyV9U zXQ@r8YTtjZ*86*kv+;BfP`O7s$9q9g_n=5aShT@)=_vPzrD8X z6F4xs-JHHIcQ(qw-d}iMmn_G?(pTy16akofI-qi4$#ix1?y6iLj0}~Wqq$n|?=?>6 z$h@{*(Qo%LPVexpK9mFKA9N_MXp#83ics5Gvq8OcN2OENzr=L9%JxytG5Y=`gwtur zZVL>4qIw@d!Eg8Vei_V}DLdL8pTpDRG>Fa%b-r`IY&ofPAM|kp<#+ zzKZI)zD{K&AJcQ<6hn;d>Pa=~WglezU7ba{*l=#c!xw8T;8~4&&zlcB(+Vt1^}Sc9kt% zi0RiWvH=pO^YSAouY>r%4A=ZHM}}epDP27~cShu^yRtK;9=-o?80E4f_4YOLPy1~} zWwAH|zwC5Y?&JKjg_SPnEV`P2ko70yMXXfmUEaGTlun7}-V;TN{dv+}L)$+P_wG#; z0BJk%so;41veS(vpP1vOy;HzSzWtnL?r%hYUtd4Ua?ZY4?4Pdnj@Ig;WgOExEbR|< zWiG&av(~E1&L!7ARXM@wxT$ozAK08~?yu8Rb0_=$y}N4*^UA(|bwa&&W|Q8>Qhm5| zq+5Lb#L9EA%>5l_5P0mZ_mSsu`tAFg>vI2Z|L|OC-rWZV1=?@#Ta_1{643Rk(75~P zelxmbefoaGs0ujiJ;$${E*JVi|I(_>%CwZH_aq~<^Xp(fXc;@5k9B3&R^_K;X^9(7=+%RgYM?11Zi&xlDvkUkj_tGyQ}+{2IU_)9zTcY z*8$hNTs!)2yEdn5lsl3t|A<8rV1@=sHX){}*G@4xf8al6a11SO0y8l6L49S%;c|3q z1YG@@ZHGzbp7A?;prkM?r>oiMS2%DY-zw2I?xxQbIy}L{y9GOUqT9~R#(V8{k)ivY8$KH` ztOb93sm(CUum;YvOL@V6BHISwwGQlZKMbc+?(6Hyp51%uu(|CXXLc;uY~<{GKThZ8 zdRWw3gy;i1E^p8=Un$*=mVx!t2oIFK6?uViZ{0zlE2;jr1Uv%lrz}qP2;H{~zc=FV zDph&lg2r#Rh%KFOL;2norbGvazoc@9Tw6a5XM?Wy5{%X6Fwq>NCwhiMx9l-PY>xEo zRIGna5|9P<*~bde__hIUx{9Gzx(y`X!f){Pb!F^&k6C?t$^$=7i^H0Bh3+_g8JHJ|*qtVQEWy`b=0tfN3x~e< zv$NVv9R|I31^q^J{_m}~#syt6`SvO&!Alyy@7pa=CrfpAt-VK`K5uO~bY~d^82{?7 z4|kZpqD8@Rkq^zUpc{Is8M*>Wanv_eyRUcnlH9UKcZ082+2RZ^U$QVoItZ=fhClZ) zFbxO(y+IIRb+_CALPMiIFcIvx`#z-i>z$Po4xeB-0srs5P0RAoH4c0O*DloG;`^{- z8mVql&hdMm^F7iI=8_Z40aidxr`&N-+`rNv;B>LP!u`{=Q$MxR_4(9>?rWCb*_Gr2 zzqt~_6js5xcK`0s)8C1{cWU!={Z**w)Yf}-Ct}~nIzL_HBN>cXV6Nji9kj49-UXwl z(|Ypt+6B|0x{lD<{&j)FqI2si`adbPp??n2OAb3Pb9&J0v>$xcuYt}{+1}~vuxhuk zzFnJg|8}+wiDBDYdqv>>0@be=xNH?%D><-VcDkv|-Ii1C2k7*82`o z0s29qdvZj7Bl_!ntW^f{F4_BSs=H+AeceRLE;!|W08a1g+LSFmblY0`Hhvo0637=P z6^!$%ym1Gb8an5`z0;8&;_G8&aQ8yq=-IjApD1h-vkUdkC|4ii8rN~`FFELM1@!AE zs2DL#k5qe$WL^csr-|f&x1fC=v3M-K>A(UyogBHca{rRq*Q*?2!}bRCZ{hD>V|IbR zq1Odtc8&FN=#oX^+9LTUEE`{k-CD@45qqi48E+r&^L0{ovjO%2P%@&XrU6CT;L;<+#1vy%;h?>0y$w4;fktpG@Tt zgKD`tjBf+>mJlDQzuUL-%i#O#IGnBDuCmj+JZx`NcVxx;@b_-tr^Zs3?e{k}mUFAZ%}4=`c%WE6TVsfRdkMgES&Qf!b1@O}(5 zEa%s&c>XuknRSf)M}Gr*fHMHoTZ!*Qu*kLfx!3NBXZY=@vf-o0Vc9rxmq#!IZzNcl zA)O<1c?fX&DmSkL15EUQ7IItlfGf6feAvKei2R1C{1VHLsl#ArN8kgTuF8Mvx4ANH z{$BNSr*D({eq%g7hVm*7=jqRKx>h-ai#$?u%g8|vrb!?X{xCQcb z7rAok(%NCjxAn^7Dt^>CqCfr&nN#<2+Ri|RA4{SfNCQ?>X!PIUIWlZ_b#U)-L{8UL z4sZX;HO1-tD-Usgo7FzBJ6GWTC+$S$6NKb`9o*Rt>+8EH!`pxGoZkWs$X={RLx?8=GUTrQlzmo&Yi1Pt~IA)ZbT+%r|} za~}hsQIn~sA-&`qJDqZ0A1eb}&Dq2-P4$jfc`k=%v#PW4bVoZ~ZSEO0asIhl2L*tZ zvHULO>R(cgYLoK{qwk*euS8RJo=tLcH^pJKHQ~**(ZMoIJ6l1Z`(Z>s33crBv9q>r-XV#_dfhcy^oP%{Bn&Y?M1YiUV`8YSXU%H3v|hxS8r7Y<&E< z%EY>HSH9@uz%s=wUX50jN@kawO@Aw7IZJ>b)LX&5lz?9V42!mJj#Is zY_`n+L8Rh!W)-$-*8PHKlZ<8HEP&DbksTs&Op`h~&yWc6Rj!Rb{x`CZtM_sgdm{tM z2lx%XK2^r1{~BfrSJDROxh|GmJMe2b8}i=XPu{=ab8S67Dt9=A%Y8@a%vH8N#wt55 zuUDb}GkkF+C;^2smzxVJ*F9d!f~y)M2b?e7%U?Paa{D&iLlp_86@& zV7PekANm1h6tM088QuGbwjKswGzfY;zP_$pIUdOBY}7trFjrYN$IfAVdrMcf z55M8;8>;M#UGBF#U0v?m1m*KmwgI+ZP1*Qu81yHQDX;I^DDT=Qs|v2IpL>A0Ns4~U zT!Hq1=bb@wzZ&8^Ud?&<={hRX`R|7=@&Q%(FhlpazC)wn+)n2P}##R0h zXF&bULEAvp!(BSiP*d^jZb(3nb~xn$uKc?+KA9_5qtx!i9=w}aCgdH>aGug!c*m-g6VvED0`flv25 zqCY^`ALIELDhBog?S5OdJYX?bd2a{~F=4yvKE`S<(ZSV!x^CI|zN&KXbt#8M7apJb z1L`nlUXgvWeyXzmDU}Pa?93lr~FF`BOPtJl2qCwhN;!h*)M*e53F?k z%x_b<->`V`>%z8@y2rDNZ-;(OuT91NtvTi18gU=ry6ig($^5pe{2+(%+nla6k8z;a zD-V9U+UNEge0{7uFdt!oMCj>n#N&vfO6c`pulmaX_#_IP$8jy1gc zK+%h5K%ZTK;1eRL($T&ly6c1b5f13(*L!7uKz-9_*|()Ua6#wVd}DOaMNV)!%E^PQ z!)4`_!>xR9rR!zBUS+?{Du?)3-LegImxi`}yK6(Iw}y-ETAgh&_nlGxjRi(Ov>G?C zQ&mfMUV%IU(IRyHqx$zE{mB%{X0m)r7l8W*&KSP29!H0I&hGGu(7)8LtBlUvojs0{ z;?QXkHKXrc^f{bte5~qSq}nUXmQKFo+5gll z_lk6G`%o9u`y0ydJa+!NuE1o9ss#ERWZ;5_dOx{PQEcy&PN&@Ilm~h}l03=R&AT!k zI8YrU^*cg&dnuIs4pHsTANcwOUG9xSFc1s6!{hE8WBZM2kk3i^b{oRWkFUY+Q(^x> z-pRVpl)qV9MzANS*K>rDZ1IMsSmEH|TkXxsK-nf9<961p=a2f}Sxb(v47m@!=#Yel9 zzLBz7Fm3c)%UJZB(0_=tLC-QQGvn!Rp4Sv6zSS$>-17AL&{%#8=9c`B*VamQpj`2=RANC}uFV{9O z`1If3uMBu6U42B`e#xFr#4cLZzt4B!!{X>aRj?Yn($RsH;EFxO-+C$KJOhdZMy^C5y-hR*_O~lJvIRR`hdVEu8n$KAFaANN5%lNpl_+pW$w;PCV!`xjVt z=$AuuI@`o*AFGZabOC849T^%Y2({!WH<^=4jh%O3NZ?P)4IbR9n!3c+db=U}Xw=ki z(vF~3uIYUC-2*(iE08{x463FPKiXg?AU7a&NzXb?M)pP;&;DZDe~pB4DrH?`L2zM$ zvP>-?o;arPz9J)io_+oW}d38-d zL;vKoOLzssChzio9G-Sx?d_{Exafi_py$}DSsFBfNaP(9Lv{r@T6D+=3 z!wCbdn9(&l%|*DR9(avD)@5-0S8xKZZDTfleP9r)Zr(RA3Na%Cnx%s8TNY=Q@dQD{ z{Dm&#hU-R)58ZvNZlcebpc`84HFWr?9=2?QlcBYTp5viqXs%5`yRx6Re28P+O2!_r z`EDm&?sTmtW2hBoR~ntt{{*tGA)-qF;rOn$3F%P=U%m>*$z^Y}o3m~C9&9AMRw}w^ zvzbS$CFo78z}tGYIHim6()5s6o24H*Qdl6TW3NgrY<)g0E#*Ye6;7Nd7OT{>yW zb^n(3rn!FJRs$Q~oSy-%B?8&0zf(ZypMNwt^kw8}*-ZDi$C(CJhp4LzeW}WNecsvu zOL<3)UwwoQo?&o5n{C$LrbfG_2=oy14ak{@pAHcRr>~8UC+X zakb$bhb=LGeUx!q+~~}Cn+P^k?=dhgVXIM(PBs}>sg4?O(4qpD9(NC=7L;Q#9SV3( z@w={^L)ZTvi0{kd_uC`oA6s^fbU3)T<)jf=!pQQ0?x_iri8n=JZu^<9fqq4N>^T4$ zcZHz#vjXcn4t!V-!Jw5hASFsR3oQ|&9yO&tGlHe9UG^WQA~Tk#fbP4LszaMV7;55 z_Z(vBT`|^(!3HsWQ+>qGsZIGtWk;M_Sh0@6pXCSLI-xIg)-Am=Kbyk62W(tRT|Qvs zRU&qs&mrJPbM{txnHSDPiv*|tS!1QYbR8H@4znDEe!#41;SAl9qdtwB8UUyID~0Vs zM}D35`#W%uCm*%@9Jyuq&kcO|)n#*eMu8&`bLoHr9Faf2@2>pDm@fbyL&9bM&aV3y zW6oj$w$bD3IsKm4g|SV4?(G{x`B)WqfbzIvC{PjC8l%$Jt8A&jY8fYA$f0G4|Pj-MWo#2^&6Fb3rBY zM=!BxUrP8<(@5`z;E!Fi3{66UJzW7A>42h9FbFKwf5u1w`~NS;x9#-lp!`E_z0Tcv`Bt~y9F>Hw4)b*u-z23vfn&boLKE68S#`!PJbA6Zc z*5Yye*r8rj3TI4JZ=s(P!{z85mz86mnvlz(w=mIvDr|uZbo$Q#18^18vm?gJ6q67|C}{8)SkTgn!?q3?{tb-xH-qc_s( z`l&m`X?zOfEW7UMEO$M7R9(|+tad*;m4^bF6*Oc(QiV4Uk=f#`RtVHPYy}S zzNignr$!upri2KNx}(NDbNC{$yeP+Zl$c0dL(d^%F<_s%hT1-67wX|z53#-x-u21g!5~rqWH8JqCLiMo+P@6V(x9tA{MuKg{T8 zsQPl)$q-Q0TTfDjeo}ROzBdxb&@DYU^Zk{;{tGq!%on37j?brT$I?b1Zwxx*S5Geu z0%Ltk(>xdY#FTZE=q*?Y^!;k7?m}&IvsB z6&3Y+g}UIu=m=6W*y8omo9le!v_qKuh58N?<*Y@}3H!009&^T}2t&v8q&1eVC?fN~ z5bFN^${6vK=@)sS7ZvG8>Kf#@BC=@#)2Xek4HSzH?5})$3}@-FTLFnZZ}DkIRn~NL z_PSKC;j@|O5fiNSnWP)6aad3~I(|D6rnh$0Nr=}%UWEK6bdpim2G?f@ACCM>7coVA zuGCD@E67THx9smIeR=;~y#B5bLuwfaq?t@D|p>Ne5Oh z-X4Lhoxps`;2e6}8%*rt`nd^ipL*XIZl(`LfKkg{y$sfTKO~^k&Y)lYPzrIX1KMW@ zh$4awFCu%U7Ivm(Ng>|x%<>70 zK)5kfx57ZZz1qTLVWk6Stq?mnhM(!DYy{YVTD$Q|WUW|ew3&ARF}%}bw-fRtSD)nz zYy{Z2&qTD^>nF%E3#@yy?zjkFT>!zhHl=g=FLvQ zMhU;{wn}95FEsRBe4^mR25(eFy#DJ5)A0{vqtVXO2IJ5jyUkp&0Bb?_w}uGdX$IK( zki1Sa*3;qSD-f2?N$KXrk%B=sf9dFl7Oe0QGV{xHVEeBWHXLkgl~nAs^kc)vlMLNd zs^-N`!G^voGJ4SmX9j*>LuaWArQ z{JM%$E2zy^9IN&)i(XFv3|E|Gzh;;l`@F-2qene@PN(f)10TEI82eZdn?4XSlwyGZ zeC!aI7mj22rABWIid5Ui2Ef2?9m7sSPkiA&`!#QI6`Ro)sSce)+*9R~LHLF>IH@4P zAA;y*8S{f|Dcfj---PgyFy#^ZQTZIlBi1;abQRstQ zxy$~-sk?{ukmn#DK`uv9Np}TWQnxp7Y5+@`*b$wh^zkH z>O76_c7Q6s-NNPS;Mfouc;hVKZ&UpP#@ir`b`88!Id+}w(RGgK;BUZeVd3!ong$X^$6pdEPn6Tv?SIT+EeIGMm)h4^Xcb3GveU|s2#Buz8F zGUORW9Y4=Tterg-uWogd>sV;dUOlFMf!9*S14q%vVom}%2=UX0>PP_VS6@3l4Q3;s zIHUZwI^UygC%&DLJ2T>RkmNHCK%aL&^1Bi9G>d-V2s+9>W^sE#`^6t*87DxH)lDop ze}AKpbx2OQ>$Hh@bVqcG3os)$H+Ef6l^=_KvY$P&BC2#3)^*Bi$9DMyr{8oL6>~j< z#XBh-F@DPrI#GUFNsREsK6fA&r07={tPF{!>QiacnC;l~L>I0c@&o=-P9PZk&^L;d z_srq)G4SYu?W+;KrfOaIZsPmNDPyyKhQr#a{Thz<EUhz<)QxdGtCXVLN?G4G7jfxA5am{^vb_siTZ|Uhi-4R2i(k zf*aoQiep^qiK+PfHUfHRMo{LC5wV;6DZ}reUnXGxHcIi|$8Yz`wB02@B4s}Xgv0+D zU4nAtO}F7;MZce^GT4FJNh7+U9RtiK1Ka~rKAN-*IgODJ$bPixEva`g&HBd#PMn*A zIU|9&mNxVK3iNkjTRW*GZem(Qc9F^r(qFJS8TmEhUliYqx;|O7LzR;ir?=6E+BqAs z(uZ@&9+mL03|s>Xj<8uC{Kn|dN!az8z`mWrM#x*hcef4$;&4(%lPM3a3&?86?vF?; z{mrtmbP&8TMq=powDGM-^sBa(4_}Av^N^C$)A_!AstoT}kZ4NT#@Zk|&LDhx3}2*& zIQ9~beCnE@;1%=**~Jk?RZF|1s>HD*GWI z23l1XOVQUSa^vjdVjevG@A}|K0j!p^#ZvYi1_V!yk$C!zBVlx^#-ASH*Bw1h%XJD@ zYG?m!iU-@e`3oS6YqwL%$3PooFA-x+()EU!u+yrjSi0FXGL#V9D@Ic3-(i@IT!n9a zvpbbuoErorsW}_-gDT=qIj`EZG@$!b6L7TSsentOgeP^io_!iC@mYdR#aGCan!7P? z4pL)G+mmacW)AgrxxHd!wCS81OXfB563eiJOlFJU8E zp;7djXqw6t>3i)1udp-lXgQ&kq7#TAN9#J?ACG7X`XVGX)0XswZ7kKUx(bOQ()S>S zQiz+TI>G*6C}0##VzhWFUG_DZ^NXF{+Pek$nbRe6fQt|-6}`&=r!gm1^ES0ftZ?a7M=NC=c`)1*xyB->jR&K;2TQktsa^48IhU?BfCwPM_v#3I zYSfXqS7{O;TpD{T-8;qy_yv}Mud{5!RmFd`K%P#|4*ucQhl)6iEuhr{wJy^yx+EJT zSJTJb4~oQSPD-&Iw5_rhIYoHq)DY=5vo@tjV#X<(y0!@C{p#!{-5!bi1x@3E&wX<% zqz-@Fn&JG95M=hWB4$q$j;fw4@1JGc6-JMj6JcZis5tg5NJi!P|C5LG-fF1ImMA};)23l zt!8n84e#2HvT%)cI9NMnOndCq^NEyQT^qdSOF?yZ)6h=rRw|yj^ZNqfmKG_xr}#Km zM!&qo)yJCS*t`vG8w9-OBlotv3mfL@7GiDcDKP$GLcYe$;b*!$R9By6DgAt>I%kY-j09b-kSevS%TFI-kk` zNbVX1^EQjC+Y?Fy3h{6x=S4#NJgB!mQZOd5Bk(D8{b!p#5&0~lxAR>Z9%I*%$UmKO z7PCv)l(a?oqceFW+@r)s;(lEhKH>hH#UJAad$)!6bW0{KQLgVbq>9mxengBu6brCa zAK`y|DbKj^k+>h%MI3OiAK@Q5m4o|51UsM}h-;uFUU|`gQB?sRyA_ST2xRf3bdiwE z^JQ`p?P>nWYmv0bW&|;={fK9omlN1=pNev$H*uc zar4csFjz9-hsL;={}G6B`DNF>B7EzkzcSLM1vuN%7M>-p zBEIu`HUN%6QfYV!wDN|L`NB#pm^ONRHCuSv#%V)aV*R)^pbhDgW|kjxuds~J?;OGR z)w0vx@?wj?)9Ed**n_Qcp3}QsAmVj!1jX$~z*$21zzFy|5q)3Hw*Gc_28bm ztB&)6rn}eZUG$^NH!`R%H*}*?9z!YC@^7Bhe#84o|C{BH>^Z3t(d3 z-Asfru_kN6&pgkMC_>ABwyRO?6i>>IARjoj-=Z+OFqUgAj>sz+zV-IpZI(V)XYLd@ z)7R{tk9-F)A4b(U*s-R)N%M_Oj3#7bT@;VvPVL#b{bM`o(+J-~K8idh%MRdAkZ6jL zU~q|L6vH>wS=7iBoVZ21bg!R%z=DxDVe4lgE782C-k2%V`8 z;F&(il`U)=9lWu%ps#AfI|^Gj20{Lou6+gkt~&IriiX&i_MDCKPxj-ZqA#lDq}Wbj zJ`{tn^C|FHkp0d~L4g>}Z&ZyUw8(hu75a+chSYsKTFke)LyNwFQ3$bB{f!2+l?q<- zaEboZR>U0{6UPo!--oh}T=Z#hu;P%DIYnqS<69q9uym8<8fAp#H!T`X!~92?$+iUbqA~R2qI-4&-&n zCy;Go#4$ZK??Q%B4BtkNlcRZ~)?7%w!63ds6ROkCz#k|-}$taJ#oh1c+07;3j=UJ37>p*rY2e2Z9l$k0J9Jv`1Wnf@WoCC(G8muD46suGk^~zi2jeZb?Z6@ra1UIPQM-g|4ziH zrfq84ho*sjeya>$>bfO$(RnGhoh%N5=TDJ-J;;jL>9Bci#IC1yxMU78yqbS?(!gkh zBlZvIli$uVsCp{+wnF}l)TJlO08riS;=y3nM6_-sCaci4Cz47(uKcAiuI(KZ8m+#< z?!k^E%zFcr@drEI!hbig|8R!s90bGkA*F^1`{>bvw%UOKvjOsTq$CYIGA=P}i0!Yg z!d{OEN|NpXo>nuA{pJL5qjjI~b$V*+2U=Ia@tY%^xyiBxyB2ar#HLO?^!6AAvHSTt zuB`U34;Z~M%WxQ^?`KDsFVdzj3t4I4M-av{wRNi}m9Br-qOONBZPLlH0f038K4=?1 zzU?ZOPXIdQv`NSKyb!IEAe*`=ZJi$e=mq>{zca2(`^p|BEb1KFMM}HY?=$`F3fAiWUXxrV;6D&qUL2;mMEz7rh|>n{BEi8+b{Tc^GozlI z1K*VjI1)>z6Jsg=skTULE5>ZV?~H_>GK|pl)Vn3Pev&e*+IETA7wI93J^ges+$>BT zDVW`zfsyN|ut^<<+QDf;C`_m1*p3oIK&yp8sh;B#m{vj6t<9)in*zsskz~q=Ckqqt zqI3LuSp*dbe5&JL&*6f@e9)6)J4y_3oq!CbT%Q@%LJU;JqaPZA4j z_@M03NrOZqT&WAb+Rp`JADbAvcf#$+oBWaY%17on2LDpe#wre6SLJXD1JSoVGIM?? zmuuuWFHoyk`*N&hgzmE=4?N-k-^)f~s(sFa-KQhAPQ6jY?fg*FigFDfazHlmF-S;GaA~5qX23{AJ zx>COYG2dB5Uos_rDEL@fH5q)%#+Xy|4?uQFw1-WPutEW(>#b9etC686p6FuhH-2OB zjZH^j{-au|@mopStVJ(xhy@Eic4(HLtQ6yJtH*ilzxVw;E3i4xO=Qv2g~2m)Gy(G@ z1GjnG{G#Vc%pVNx zz^&t9|2=G<+PW8XSiCtWXpFWG4GZdbfL$iXPaOuHy4lCNu#T{~NOc1>=hocQ9 zdiZKX>f6#e-9yLxtib2}Zujx2GF-2u{ZlDSMw>oW@B`#`h>mW5L8Q~O0j;XiQoA*g zM(%I2x7yHc0oQLMZPTr$W7cDC)V;Jp)9A6@t>T#W z>{tSf{UB<)k8O0;v(|W80f{Z9U!R$<*#{Yzs4{^l!D$8f?Z~txbBa3b2SM+P>=5ex zdZJ@b_Hpy39O=;Otqy<YX`qnk2;#3L7~t)wqPwomk?bA8^#>ar4Z{?>e$WvyoG5$0<65ve zoqkX_LaKMwVW>1|wiR+XqNRVO>1!D1Re_behzXwkjR3MQxVwm9>Nyx7w+6!>tC4=^ zVUmMFCu66CfoCR@jB%pA8K6!5J;5uRhh^HI<6(X|(clf|#P(<}zH1CfPX*>o59f;0 z^$0u`{HXPAG=ltRmR~Td1UOZ{X<;X&Gvd1<7K?$EYLgg#snJ^l6YD%!^KG*PUJs`< z5!G3OFZzuR+7=;0DdrsD_lLl|bQQxdHF{%Ej*oTTz)E$Bg%7b7rbGu{__={sSoWdc zs(yrpmCnE)5W_AtdIm)kIQx3HAOHu$wfH~-d!5pF!>y=492?c{IP3yIXK;>4kXtW<^!N5 zm7!Zynx43%d7!jT$m!QXj&%Kp?`y%72Znb^Wq+%KOPU8tLq~#v)+Lpl3pmZmxFu8r zr86wvnXcgoFtp(mcyF|0bOW1WNoDyEzocoP6x-3Phf}@pNEp1~x25D@-h6qclXV8+ zpmbg5G4UM+XKaI*uQbBZcB5EpA0K1HrT_M49c}isu+ylU7dwRpj)B%>)@jus9!52` z?Cd2Krt9qJLPA{tYrV#G$achgLZSV{;N}9`iA7W6n1Ov_4MfdaEE6UzsA-k(eJZDb zY!2|Z0@gyES(=6s7`Q^1tC-)<$ z$f`c9#zv3jUy00{Q*Ww2v$kLa*s$T#%3lYNS#>r7^J4_qnYDOnJ*3rho$5z%40$a5 znuhyzF)Hw^i74hy__~N`#xWa#1vdixz@CNNip0`kC7p&uXHM&q%HmI6X2twMbeKg} z>C~5J#cXH#*$B)=pl}5ELG73L!TC);%B99=d*8689KA`8`GfDrHJq+_zZl0%KRqKb zuckAnXV~f^;a8yb`g(C?Q{;ijS;%*o=4`U8Y7w?M=_&Z#93Q{U0gno!7~sx*Q)y9? zIPkFtcF#vPMD$=x&p(c&?-!HL(rg5#dj!~lAA`icrcYBZeY&I4=!ycHj~8%nlM}DQzYS1T$05 zMqqLyzz)3$Qj)TsC_uPI0qJ+@MgXqW3;3+Xrlt!xzf-`whDj1A;d^KSr=X7vC}!1` zBQU$72nLXyY*i%rLQ-HdP~}W^E{fLF*<_|#-xbeSt3D-Z8Jl|oI3)=hY*f5|7*yrgwC$1E3t9O?w)7y`G4@67 zMyzChnyYSfAo`+37SUy|`p5n=5e}z5sxG#$9YeiFyC%_P$ zJzV!ic0^u|?2HV(3~AYoQ>U1!*c78;y>E$s@arPE>Hh%gHL;?EP2E!z`G0#6=?uK^ zMu455?tgS^M^QSlwD;KPQ-7(|l;TzTMJe~vf@f?_?~PFUkH&c2(lNp2#58TcHT#OM zG=>>|o{RvyLdoQ#`BAo1SK-$`vUxwE=lfy04#m8A13lHxQMPG}5No-)##FaUn#U+g z*!&F1O|$oai$-^Wg4tViu&{o}){gXBl*O003v}q_UAMID5N*Spq+5$f-P4fp-)_pMR@QDeuI)SXQ;h(Fz77(5q)Agh>Awr^m^*M_^~1$>^j)`C zt27_|_LlhH82LL=nsiI3lff)aVgwlc<&YngZZ+_l@T`5$qHUk>p~=9vAlAQvKs`$> zM&MLz^}`*@)iHiP+%Q&s#Ax28u?+6GMu!ckw-NQFqmsv3TW}fJ=@+4h)43473^{{-Y8*OC z^mkXtN>^#>-{kHc za~EGg9#a>?($vm)tcB=t=7mVt>CX`A$w#Av?Ng8+BI3Cc`4Xb1DA@_T=B>h$B&wnG zjBS+qv;2SlhrEr6v6#Rkaw$eM_5ZQQMxwNLz$cJ<*}Vec%#r+ej(GzrGA z(JD&K{*NW$>t2Y~X6Q;qXRHg5oXc8ZohD5ppNxC}*&S(od0#qk_|l5ngODyJN_9)I zYH1819uB=rb2id6y*cDuYU_;P4oH&)EO%h%&V-G}PaMdZNZa%k2u6B)1i#i~ybw77 z>EZ_g%~;c)@b+G02&^lu+I0XHVm-eKqGtHrNn&4a(`FP90Jrw(_0|vOKWcbp_aZ#roUE0VPz?UFbd4sL9&&LqG z%u|%GSsiI}xdHwi0pk7v?C)9Rw17N&_5c7K+et)0R0a&6cHH+PZ4O+RFX*KCf-P%? zvbY&e-SW0sB&Yqb_JAP_@>ayZdcBRh-hf{E)=ALmJ&>CaD`_>}$Sy5YdkKCup>&BA zREACmmR(Z(P1@jmF5)i)%Lt_yawisNA)i8ChHQc?+azAg1}+_VcR~(AzJutctx=~F zanR{%RQOgxzTG15vA;G>tdCB_tl!`s);62Cj=)Yua+7vo{eOza^9wm0hF?!HPC}Zb zzhd;L96u!(IN#AEn1qd<8l8;14(Z}iZb^5NSmM$6>#VIaug0^>bTMRl$E33apH|y` zzG0Bs4r_N7Oh5$pdWe2A`t9VVp9VCOtrE2!&9zB4W2~9*&c49_*V7vYq#dx)XV6kx z0nP&(#^amm_C#mC9a6rgy^Z+qha7-(F&A?MJe~eP;nS_cN0BD!LX28pwZX9hqThsm z8*S3^Q?)Rg2D(U{-!gYL#`NwH$k$u;@=Z+w!sq@C z{N91hQ=9m!vw`=+4dRiB9;t0#$G;HU>9?*<{~KwNG@sPzB0P;ToLalmWYLr+VT-OV zz`qG;ll0r$c;4+B1g(42(+Ya7+2Eo}N$|S2ya*{xA05?z5{O((VHLQ)pAmx((Y(l5UP>w*-)X=zHgE6;E3>@gsA9+eA(=7wFfHk? zeU$2A2K!b-zlkvEx1--sHkadEYI6qb@Ng6}>aD+Xks5IPm+nOGO!3Xy=0<>V)uUKV zT;?V{9ni~eBS~=U%wPIASdYV}YjSZUqcbI>47RRJeub2zYXFbzDndg8f9ciDY(0O$ zKE?Phk6eP}rf(I{H-Zw#p}E0$xD6XQn=eLmbU9?A_t5yiCsKMO|I#?dn7B#~UV80( zmI_Be`yZkS=-jk>p^IWTfoy^3MXr+c++s&94G2yr*w!ymnqfe^7m^x;U(^0-(uBP0~de9fWkYa0#wek&>i))JJqO5E&%++PfgQ+0{hG zn8qNCv#xAYCog|fTovOPg&xP>@SSIr-_Rxw__YS*wa6J6zAVT|ZT$CaVLj7gZlHUA zn_%##w@FKq9$~H4#%HN5{=QHU;DTO2RXTP}@Qn2-1>@cMQv6iR#Pz{~*aST=#b>o) z^V~uoF}SYK+fA@SpvN#>r9-R^*XeMs%c#`lQyAX`D8~LVUVQ#E3?xzS{PpR&aa?Ha zjO~$$@eP}H9(Vr<;NUQbntJxrIC#4JT^^bE9MPGpeuNm5s6`h(OTrm~y&z6O*Q#>^M!${o1kOx<0;f2NRy^0mQQS@d zdStl^asuL3lj(Nh7f9|=a=auIL<7!RR`C76+(5yd*3#X~oDpCgA73!$ zUzp^e5$ER%V$Gg2fOA7cD?a~G@hjI0W&0o#UB)n$@urgxM@mxXUq348D1mNJ5bTdi zxMx^<1Q_o}7mWG;+AQPK604RGEQdI!WWC?G$HgT>T*Pjl#9d4gMo&b$m+57B|-PsrKG zIdpcU1CDP^im{AV(47CFJph@m9#KNNM^j246;=9B0pKf#dW7=daCU9S@4Q zZ^?}PZ{vw*VS8b$U!FPMf*m|9qd_cMRjQ|exvBU`1;m>mA4e`kN?&=vWU($3h7%3< zL)^@%fNj#dhCS44aQK)4r{~o(ju%1fdcu>Nir18kw>Q)8je-6|?qGx4b((raJTESY z{kYuN;e18`Zyj`Cj>OGT=w3*dBVD9-6Twp&5S2XZetiS}QJeg>z`9u-ZV`U;YLA+yljR>@T@L$~Iw@+P ziZT0E639mQSL8=X?n*mi6{OE*LGpTG2$ z=I@acI0}82yePq`81BwA(mNb0<42F0rY_N!>j-Mq%)lN+G8-U5^Q|ZC}t29UPb5#6ay_Fjz02=8>Ww zTNd+i5J*my$=NMRx#Q_E)zOlTN!81aN8rcI;3t>9mym z!c50{9K3NRb_QEA0xw!ptSuc|iy5HHBYP7+qK zbM8CIK|adh(XN1|gGk6tI#tK@S{706Cn!1BHID$lH+XkSiDFGh0L`+SuX%gtr<6G4|8C>~lGp?;f)exs#H z#{wM_=6;_Po>|He!C!*DWc|IqDX?sW%Tk|EI!Kek6Z{XX4n%Z2O)Ad$=9lq1IWmTp z`YH3Fe+0g%6?{bZAGv+PUf-G3Z?cQ@OkGiYD%W`pPM;gg?nuS8Yz?R1e63%Z^78iz z;(K@jc4>#^j@3W7n)vZN8LZn2;>^985~Y5N`b~C`KBWUimzVUVTqPZ!PX~(g3${-2 zi=nbcxo*hhO&ND1LOz zQ$&APL~p6@XDO#tcTquH>la{`X6T}V&i`KlcGA$214ZrXOxKy}x0t&q&6!!bjtx&; z7D5Hun~dbB{V>XpL)JvK*Q$$?^x2*)(4S1AZ;K1{e3bZ2DHl5raO zf354VmnHLhCBGMa|KbSZJc8e~Rts-~=yAL*4(ifX0Dg)6pB!*tj-YDjH#*P=^OBcX z=F@>9=RoU*^$u5<<;f8!8K}+ zv6F_C94IcCbg=Wmf3>gtH8a*#*jGv>$}?$40xLOC=wLaKG|>Y^)#GCedcI=;c9PJN zIf|Pm8R$IoePcnq6Idyrc=-VE%R5JqXSGq#TeTnWuepI*CP)L7YyQUVCTza z^2COmF?vVAn0|a>ffhKXKl-1bxvBPQ3ZkFnk|l8ZmjdzsnL^|F3FFeH-3!J`?|iIN z;NTY}+>^r6pA!oD)abF-r1~~)zl@{)b5=>(eB3dX`lBnsb}bwzRSx{ihI*!;G@$9&ikR;NFA6!htDVCU0gy>Jtbq|TVUt6&TT{m4iH z>6nx_Oa2$>hB@xxJQ?XK?QQymU6&kf)2AUQoulZ*gWcl_od3}5#FQ!N&yEFsa!_4~ zMCXpCtcxQHhcVFn*bQz_GV|YqoBFXMMtuY~Hx<2J0qHA|CLh@K6u%<>$|8$agUz5S9Y(6kGov8_gcuQ`j^rM~^2fvzb zci+swe6HH~IoaXeM=&}@I#lxiOTzx^Xur?sq8mRm{kcE#)3Bojbsc;+8h_-?JQC}M z1$`4#FLTY3H3AII3WbCDT#IK~b@c6?$Tti77{cE=t^Lc1i_WZpH2FN68wbtG@0jCj znlQwyIh5SA?=;0el2{lCJ*v@%Mj9n-pPf6J;52cQH7ndGm=PHfvo5#akF-huHlpxG zLQ6+iMb2x{;VZD+VkE(hn3TA`RM2nz2eIs14zSB3i;(G@$R)6cBHGz6M`B46C&i1T zu=!Yw(9mlKiqF!HcqeE}PwYn-eacm7d`sRJXd7;^J@M%(>f5;;GH^dbcfVrCQ({2u zZ#VjsQr*8Ubc{DcQuAIn(XPqMC)9Cu+K$7m5$(_lph+s4O~rxExPLBi^y^MLJSH;w zS8_m14afh{ICb~5#PrHk(3x#JjcIdq?uPz7E3=OdruRRR3E-0*xG=v9ybjpUL9(w{ zlEJt}2=xz(yGSQG&fFZQdf%iZ&8ve29s6!c=Q6Q}5h?0N8Ti3nUjWXU* zaMPh(>N*v)XU$7sb8ukSw5qRkx4%+@Z((Ju%H9F6fc?B zs_S#uu5}0#dm4c6!@__%s?VFJT=Z9G?UHnC?!gMuRgkMo$P?I0bNxnfke{A#kkfQ4 zp#70n>m9H!K3HJW?WI+8l=2#gM-zD;L^NYxlCA=rngdF4eUHYm&E4Q@8>F;EVQ@N;=<8*< z`A~V|Y_`duE{4FnETW~c+A%cOpp~Lsrf-EoLB0i|g;xt9X=m=g&P@4! zNXZVKGX}Z^`#SO(WKlStUDxrUW%niND}XyWNW}UA|Julbh)z2CJt%3p`(81d1)-;d ztEs1j=}k>LkDrGlhaeXe`fLL~C>AfIx>`A@4fzz02idfAie6@&X| z+MkB#OWao?-{A9Q+5hAPd&T}$q;v`QF8I-{f>w^|N<)v`)|llUb;7`OK&L|1<3ZUBb+Dgk16SQh^3F3$okzB^;MIT znyBne#)k3c)Uo}~De8|Oiat71dey1FV z)GsaRIAr%lCOOG>6aICT@*l{K$cl=eT=(3$abnLu9x_ESjl zr|<$FPvjD-by@utWM4tPN_>CKAttVmfqQ)hR+qF7fcN?gY%zp5 z^l{dQBl_6T>d5_((zCt(_vLlSwUzvdc<-Rxc_Q9@Av`v~o z(;5gZXvv;nv;x9@JtQ~1$KqHTbqv^fnS*vl+wsAV_L+kbynCt~c@Mf6)} zn|{}JY&x~4H+lx%WOiDs_&$Pk_DMZ;3_e}9ehO)lPQj?{716->!uRFOK<)&mGyPJX z7=xE&j+bDae-aT+?LRtjG`Vfj@1W7dw6)RUS_9E*B7*2EY1d zXVZP=zq*bmFVO&kk2Cji@Y7#c#;9)|4m5K^k)oP zAK2hHvLJw6COKY{^vxI@RWMFZ>MB-zzO%q@2)!7^L>{r@R}J8wc3+ke4GbM&{+0x^nwEHXH+~d$Ti;SkekQ&E6L!Z1jWG zi#TnPt`4%EiTlA}qZh?;(|Nw_LN7BYIy2@b9Y|~c#a?X8u-zQ_zg%YqPA845s~K>b z@6fzgEa{sawI8dA^<}BmYtRr4UQW`zY}1)#y)*Hd9485kCYW@ommLGxPbT=nrln%O zf==sQiNA-PPt>1U`U8P$1LWrk&YY&d0eW1CZ}30OAqJxbYFcGGOQ{iHkoK$wi>xRu zO7Z5j;q9Ozk2Y94(F-&E{n(~3wa4Xf&Q}aQUIn?v?76LcZEjyNUky3lrYX{D4nk{C ziW7EM7kQcke}F9e@%eIM=o;YEpoj{7<~tYHeJn>T>927 zChBq=#>K@Ltc~P8;Q+e$!*#KNSsnQ_ayQa8y$ym^KUnPdXc5Hsuw9|9&kMSp0eB#y zd%Y&0ND7x-1j{VW%{C9OpQ%$ zIw2M}1bQ@oUM^7$P7{<5iTP@xhwnbfcWeBnnxEFh?}D&lRQ@M5GLbgD0^Z5mhTK8K z->S&(Bk?p*-+<9Uh%UMBg_K-b=q&k^+}NiTM;}Ta6$4*h7Qvk;A(aC z;Kvv%|RoX`25mAz(zCZXCOIAa|y*~5!oPHAtf{Qz&lT`DjlCm;OX_Uh^_{w zAstH)jh5(R_n?9f90Rs?-vaX(dlB zE;ZkBYN_Ln@VCRWLz6KZhYhiHHP_R0xO5`Y)$1~C`wNFoY^7vs; z?Pj>l5nxdFN1CMn$aIknBM2?%+6%e0NkA=abkNWN>j>l}i0{+oxr!;ZlAGazm3rVEbt<>tIB;1Ah7ym7r(zXh~CFP z8_^~Gr;tZBi3Ph4BRT0UP58UAAwW%9Bkf`7Lr1qWy8A-(*R}o6|Ot4VDwwBrt4DEo^ytrti(T>^vtE zJ5d<@(stHFs@@yWcP?~)ugiITY(<~mlU|~$B&~eaf}uN+TalZq{I;sB2|0;A0{nMG z7=6rDw^SpaNW@R$#5in+@lP`eK23i#K{`u}!0bR#?FQ^bU!s`%n(rR$M8}uxLGZ5v zUOTF0%&$YvLr$9Z9~UuBMXC;Vddl?(L|@N7138uPyOBIQ!K054eKphIIQX;P2+ri2 z!RGS_u=9Ki$xS&kV@VqQ1+t3^}np6VXJT#?B?xpPm~dSWVd0 zJ*9Bm$~VpB77n~ViITCqM83A^#w|hHVUGe-}uMj=4j?8QSXbvy_=imhJM=uUjIjIPz|UK%;lZoW+O265nxwc0jay}c6;<)6ts>ZD}nv2 zGt9^zQ%4HNwi!GQ^42;&*N(wv&L|^4%GuTBaIKAK%yN=$7iN$C>jt%;eLlbIQP9ot zKzZh_MM>vodfOfRl{r{;dM%cEQ4SW&Iq;s9fi2ng*;st*T^dPF+NXZ7Gl^C*h=be%XfgN9V95x~t|*p_#Yjq=-R?r}Y)O7N_BkB; z;j3s#bIZ6)^D2h@%*H{b`lP-!PWbvqW8<0OYy=kK2ypg%8FE>0n%3**MC#I&PHH10uvemeylm)8ZCPHZ9-j{xt)!`Yy?I< z0vs^3+*%)vy%f>v#*+|zNM?3xI_klnC;a~($l!l-5Gjji00000NkvXXu0mjfm8BqG diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 7a4b4240c3..33b1ea8e27 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -231,7 +231,7 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* par experimental_btn = new ExperimentalButton(this); main_layout->addWidget(experimental_btn, 0, Qt::AlignTop | Qt::AlignRight); - dm_img = loadPixmap("../assets/img_driver_face.png", {img_size, img_size}); + dm_img = loadPixmap("../assets/img_driver_face.png", {img_size + 5, img_size + 5}); } void AnnotatedCameraWidget::updateState(const UIState &s) { @@ -275,7 +275,7 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { setProperty("speed", cur_speed); setProperty("setSpeed", set_speed); setProperty("speedUnit", s.scene.is_metric ? tr("km/h") : tr("mph")); - setProperty("hideDM", cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE); + setProperty("hideDM", (cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE)); setProperty("status", s.status); // update engageability/experimental mode button @@ -286,6 +286,9 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { setProperty("dmActive", sm["driverMonitoringState"].getDriverMonitoringState().getIsActiveMode()); setProperty("rightHandDM", sm["driverMonitoringState"].getDriverMonitoringState().getIsRHD()); } + + // DM icon transition + dm_fade_state = fmax(0.0, fmin(1.0, dm_fade_state+0.2*(0.5-(float)(dmActive)))); } void AnnotatedCameraWidget::drawHud(QPainter &p) { @@ -435,12 +438,6 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { configFont(p, "Inter", 66, "Regular"); drawText(p, rect().center().x(), 290, speedUnit, 200); - // dm icon - if (!hideDM) { - int dm_icon_x = rightHandDM ? rect().right() - btn_size / 2 - (bdr_s * 2) : btn_size / 2 + (bdr_s * 2); - drawIcon(p, dm_icon_x, rect().bottom() - footer_h / 2, - dm_img, blackColor(70), dmActive ? 1.0 : 0.2); - } p.restore(); } @@ -544,6 +541,49 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) { painter.restore(); } +void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) { + const UIScene &scene = s->scene; + + painter.save(); + + // base icon + int x = rightHandDM ? rect().right() - (btn_size - 24) / 2 - (bdr_s * 2) : (btn_size - 24) / 2 + (bdr_s * 2); + int y = rect().bottom() - footer_h / 2; + float opacity = dmActive ? 0.65 : 0.2; + drawIcon(painter, x, y, dm_img, blackColor(0), opacity); + + // circle background + painter.setOpacity(1.0); + painter.setPen(Qt::NoPen); + painter.setBrush(blackColor(70)); + painter.drawEllipse(x - btn_size / 2, y - btn_size / 2, btn_size, btn_size); + + // face + QPointF face_kpts_draw[std::size(default_face_kpts_3d)]; + float kp; + for (int i = 0; i < std::size(default_face_kpts_3d); ++i) { + kp = (scene.face_kpts_draw[i].v[2] - 8) / 120 + 1.0; + face_kpts_draw[i] = QPointF(scene.face_kpts_draw[i].v[0] * kp + x, scene.face_kpts_draw[i].v[1] * kp + y); + } + + painter.setPen(QPen(QColor::fromRgbF(1.0, 1.0, 1.0, opacity), 5.2, Qt::SolidLine, Qt::RoundCap)); + painter.drawPolyline(face_kpts_draw, std::size(default_face_kpts_3d)); + + // tracking arcs + const int arc_l = 133; + const float arc_t_default = 6.7; + const float arc_t_extend = 12.0; + QColor arc_color = QColor::fromRgbF(0.09, 0.945, 0.26, 0.4*(1.0-dm_fade_state)*(s->engaged())); + float delta_x = -scene.driver_pose_sins[1] * arc_l / 2; + float delta_y = -scene.driver_pose_sins[0] * arc_l / 2; + painter.setPen(QPen(arc_color, arc_t_default+arc_t_extend*fmin(1.0, scene.driver_pose_diff[1] * 5.0), Qt::SolidLine, Qt::RoundCap)); + painter.drawArc(QRectF(std::fmin(x + delta_x, x), y - arc_l / 2, fabs(delta_x), arc_l), (scene.driver_pose_sins[1]>0 ? 90 : -90) * 16, 180 * 16); + painter.setPen(QPen(arc_color, arc_t_default+arc_t_extend*fmin(1.0, scene.driver_pose_diff[0] * 5.0), Qt::SolidLine, Qt::RoundCap)); + painter.drawArc(QRectF(x - arc_l / 2, std::fmin(y + delta_y, y), arc_l, fabs(delta_y)), (scene.driver_pose_sins[0]>0 ? 0 : 180) * 16, 180 * 16); + + painter.restore(); +} + void AnnotatedCameraWidget::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd) { painter.save(); @@ -654,6 +694,12 @@ void AnnotatedCameraWidget::paintGL() { } } + // DMoji + if (!hideDM && (sm.rcv_frame("driverStateV2") > s->scene.started_frame)) { + update_dmonitoring(s, sm["driverStateV2"].getDriverStateV2(), dm_fade_state, rightHandDM); + drawDriverState(painter, s); + } + drawHud(painter); double cur_draw_t = millis_since_boot(); diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 73c2e03795..73c2a37892 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -80,6 +80,7 @@ private: bool dmActive = false; bool hideDM = false; bool rightHandDM = false; + float dm_fade_state = 1.0; bool has_us_speed_limit = false; bool has_eu_speed_limit = false; bool v_ego_cluster_seen = false; @@ -97,6 +98,7 @@ protected: void drawLaneLines(QPainter &painter, const UIState *s); void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd); void drawHud(QPainter &p); + void drawDriverState(QPainter &painter, const UIState *s); inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 4df963167a..6c850b8ca4 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -112,6 +112,39 @@ void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { update_line_data(s, model_position, 0.9, 1.22, &scene.track_vertices, max_idx, false); } +void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd) { + UIScene &scene = s->scene; + const auto driver_orient = is_rhd ? driverstate.getRightDriverData().getFaceOrientation() : driverstate.getLeftDriverData().getFaceOrientation(); + for (int i = 0; i < std::size(scene.driver_pose_vals); i++) { + float v_this = (i == 0 ? (driver_orient[i] < 0 ? 0.7 : 0.9) : 0.4) * driver_orient[i]; + scene.driver_pose_diff[i] = fabs(scene.driver_pose_vals[i] - v_this); + scene.driver_pose_vals[i] = 0.8 * v_this + (1 - 0.8) * scene.driver_pose_vals[i]; + scene.driver_pose_sins[i] = sinf(scene.driver_pose_vals[i]*(1.0-dm_fade_state)); + scene.driver_pose_coss[i] = cosf(scene.driver_pose_vals[i]*(1.0-dm_fade_state)); + } + + const mat3 r_xyz = (mat3){{ + scene.driver_pose_coss[1]*scene.driver_pose_coss[2], + scene.driver_pose_coss[1]*scene.driver_pose_sins[2], + -scene.driver_pose_sins[1], + + -scene.driver_pose_sins[0]*scene.driver_pose_sins[1]*scene.driver_pose_coss[2] - scene.driver_pose_coss[0]*scene.driver_pose_sins[2], + -scene.driver_pose_sins[0]*scene.driver_pose_sins[1]*scene.driver_pose_sins[2] + scene.driver_pose_coss[0]*scene.driver_pose_coss[2], + -scene.driver_pose_sins[0]*scene.driver_pose_coss[1], + + scene.driver_pose_coss[0]*scene.driver_pose_sins[1]*scene.driver_pose_coss[2] - scene.driver_pose_sins[0]*scene.driver_pose_sins[2], + scene.driver_pose_coss[0]*scene.driver_pose_sins[1]*scene.driver_pose_sins[2] + scene.driver_pose_sins[0]*scene.driver_pose_coss[2], + scene.driver_pose_coss[0]*scene.driver_pose_coss[1], + }}; + + // transform vertices + for (int kpi = 0; kpi < std::size(default_face_kpts_3d); kpi++) { + vec3 kpt_this = default_face_kpts_3d[kpi]; + kpt_this = matvecmul3(r_xyz, kpt_this); + scene.face_kpts_draw[kpi] = (vec3){{(float)kpt_this.v[0], (float)kpt_this.v[1], (float)(kpt_this.v[2] * (1.0-dm_fade_state) + 8 * dm_fade_state)}}; + } +} + static void update_sockets(UIState *s) { s->sm->update(0); } @@ -213,7 +246,7 @@ void UIState::updateStatus() { UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", - "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", + "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "gnssMeasurements", }); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 9e1c54948b..e3eb97a762 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -25,6 +25,16 @@ typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert; const mat3 DEFAULT_CALIBRATION = {{ 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0 }}; +const vec3 default_face_kpts_3d[] = { + {-5.98, -51.20, 8.00}, {-17.64, -49.14, 8.00}, {-23.81, -46.40, 8.00}, {-29.98, -40.91, 8.00}, {-32.04, -37.49, 8.00}, + {-34.10, -32.00, 8.00}, {-36.16, -21.03, 8.00}, {-36.16, 6.40, 8.00}, {-35.47, 10.51, 8.00}, {-32.73, 19.43, 8.00}, + {-29.30, 26.29, 8.00}, {-24.50, 33.83, 8.00}, {-19.01, 41.37, 8.00}, {-14.21, 46.17, 8.00}, {-12.16, 47.54, 8.00}, + {-4.61, 49.60, 8.00}, {4.99, 49.60, 8.00}, {12.53, 47.54, 8.00}, {14.59, 46.17, 8.00}, {19.39, 41.37, 8.00}, + {24.87, 33.83, 8.00}, {29.67, 26.29, 8.00}, {33.10, 19.43, 8.00}, {35.84, 10.51, 8.00}, {36.53, 6.40, 8.00}, + {36.53, -21.03, 8.00}, {34.47, -32.00, 8.00}, {32.42, -37.49, 8.00}, {30.36, -40.91, 8.00}, {24.19, -46.40, 8.00}, + {18.02, -49.14, 8.00}, {6.36, -51.20, 8.00}, {-5.98, -51.20, 8.00}, +}; + struct Alert { QString text1; QString text2; @@ -103,6 +113,13 @@ typedef struct UIScene { // lead QPointF lead_vertices[2]; + // DMoji state + float driver_pose_vals[3]; + float driver_pose_diff[3]; + float driver_pose_sins[3]; + float driver_pose_coss[3]; + vec3 face_kpts_draw[std::size(default_face_kpts_3d)]; + float light_sensor; bool started, ignition, is_metric, map_on_left, longitudinal_control; uint64_t started_frame; @@ -183,6 +200,7 @@ public slots: void ui_update_params(UIState *s); int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height); void update_model(UIState *s, const cereal::ModelDataV2::Reader &model); +void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd); void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::ModelDataV2::XYZTData::Reader &line); void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert); From a522dce0173c1f73d36b2d287f71cccc705305a1 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 8 Feb 2023 19:14:24 -0800 Subject: [PATCH 0882/1179] add dmoji to release notes --- RELEASES.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 9103fbc4b5..2e8dbb44bd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,8 +1,10 @@ -Version 0.9.1 (2022-12-XX) +Version 0.9.1 (2023-2-20) ======================== * Adjust alert volume using ambient noise level * Removed driver monitoring timer resetting on interaction if face detected and distracted -* New German translation thanks to Vrabetz and CzokNorris! +* UI updates + * Driver monitoring icon shows driver's head pose + * German translation thanks to Vrabetz and CzokNorris! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support From d74470252dc9c30dee3fc001d8d6ab4871cb8780 Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Wed, 8 Feb 2023 19:18:36 -0800 Subject: [PATCH 0883/1179] Chrysler: torque tuning + increased steer rate (#26934) * increase chrysler steer rate * use torque control * update offline values for chrysler, jeep * bump panda * add blacklist * add lag buffer to the torque vals --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/car/chrysler/interface.py | 22 ++++++++++++++-------- selfdrive/car/chrysler/values.py | 13 +++++++++++-- selfdrive/car/torque_data/params.yaml | 14 +++++++------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index da086105e3..2b2fde8dc3 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from selfdrive.car import STD_CARGO_KG, get_safety_config -from selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags +from selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, CHRYSLER_OLD_TUNING_BLACKLIST, ChryslerFlags from selfdrive.car.interfaces import CarInterfaceBase @@ -24,6 +24,7 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_DT ret.minSteerSpeed = 3.8 # m/s + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) if candidate not in RAM_CARS: # Newer FW versions standard on the following platforms, or flashed by a dealer onto older platforms have a higher minimum steering speed. new_eps_platform = candidate in (CAR.PACIFICA_2019_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE_2019) @@ -36,9 +37,12 @@ class CarInterface(CarInterfaceBase): ret.mass = 2242. + STD_CARGO_KG ret.wheelbase = 3.089 ret.steerRatio = 16.2 # Pacifica Hybrid 2017 - ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] - ret.lateralTuning.pid.kf = 0.00006 + + if candidate in CHRYSLER_OLD_TUNING_BLACKLIST: + ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] + ret.lateralTuning.pid.kf = 0.00006 # Jeep elif candidate in (CAR.JEEP_CHEROKEE, CAR.JEEP_CHEROKEE_2019): @@ -46,9 +50,12 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.71 ret.steerRatio = 16.7 ret.steerActuatorDelay = 0.2 - ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] - ret.lateralTuning.pid.kf = 0.00006 + + if candidate in CHRYSLER_OLD_TUNING_BLACKLIST: + ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] + ret.lateralTuning.pid.kf = 0.00006 # Ram elif candidate == CAR.RAM_1500: @@ -56,7 +63,6 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 3.88 ret.steerRatio = 16.3 ret.mass = 2493. + STD_CARGO_KG - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) ret.minSteerSpeed = 14.5 # Older EPS FW allow steer to zero if any(fw.ecu == 'eps' and fw.fwVersion[:4] <= b"6831" for fw in car_fw): diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 7629a2f086..e932238e6a 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -46,8 +46,12 @@ class CarControllerParams: self.STEER_DELTA_DOWN = 6 self.STEER_MAX = 261 # EPS allows more, up to 350? else: - self.STEER_DELTA_UP = 3 - self.STEER_DELTA_DOWN = 3 + if CP.carFingerprint in CHRYSLER_OLD_TUNING_BLACKLIST: + self.STEER_DELTA_UP = 3 + self.STEER_DELTA_DOWN = 3 + else: + self.STEER_DELTA_UP = 6 + self.STEER_DELTA_DOWN = 6 self.STEER_MAX = 261 # higher than this faults the EPS STEER_THRESHOLD = 120 @@ -56,6 +60,11 @@ RAM_DT = {CAR.RAM_1500, } RAM_HD = {CAR.RAM_HD, } RAM_CARS = RAM_DT | RAM_HD +# the increased steer rate hasn't been verified on these cars. +# remove from this list once it's been tested and confirmed to not fault +CHRYSLER_OLD_TUNING_BLACKLIST = {CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018, CAR.PACIFICA_2018_HYBRID, + CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE} + @dataclass class ChryslerCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC)" diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 7da508a156..6f8cfe0ce6 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -4,11 +4,11 @@ ACURA RDX 2020: [1.4314459806646749, 0.33874701282109954, 0.18048847083897598] AUDI A3 3RD GEN: [1.5122414863077502, 1.7443517531719404, 0.15194151892450905] AUDI Q3 2ND GEN: [1.4439223359448605, 1.2254955789112076, 0.1413798895978097] CHEVROLET VOLT PREMIER 2017: [1.5961527626411784, 1.8422651988094612, 0.1572393918005158] -CHRYSLER PACIFICA 2018: [1.593387270257916, 1.3366521181047952, 0.13776367250652022] -CHRYSLER PACIFICA 2020: [1.4323553627965695, 1.509076559398423, 0.14328246159386085] -CHRYSLER PACIFICA HYBRID 2017: [1.3032470208409048, 1.06831764583744, 0.13287170990024627] -CHRYSLER PACIFICA HYBRID 2018: [1.6068280248761635, 1.2943025830995154, 0.1358557824293823] -CHRYSLER PACIFICA HYBRID 2019: [1.4624643614072217, 1.1958788168371808, 0.15748488008472716] +CHRYSLER PACIFICA 2018: [2.07140, 1.3366521181047952, 0.13776367250652022] +CHRYSLER PACIFICA 2020: [1.86206, 1.509076559398423, 0.14328246159386085] +CHRYSLER PACIFICA HYBRID 2017: [1.79422, 1.06831764583744, 0.116237] +CHRYSLER PACIFICA HYBRID 2018: [2.08887, 1.2943025830995154, 0.114818] +CHRYSLER PACIFICA HYBRID 2019: [1.90120, 1.1958788168371808, 0.131520] GENESIS G70 2018: [3.8520195946707947, 2.354697063349854, 0.06830285485626221] GMC ACADIA DENALI 2018: [1.3181430320331884, 1.1853735340610179, 0.3450592280031644] HONDA ACCORD 2018: [1.7135052593468778, 0.3461280068322071, 0.21579936052863807] @@ -39,8 +39,8 @@ HYUNDAI SONATA 2019: [2.2200457811703953, 1.2967330275895228, 0.1403992098658639 HYUNDAI SONATA 2020: [2.9638737459977467, 2.1259108157250735, 0.07813665616927593] HYUNDAI SONATA HYBRID 2021: [2.8990264092395734, 2.061410192222139, 0.0899805488717382] HYUNDAI TUCSON HYBRID 4TH GEN: [2.035545, 2.035545, 0.110272] -JEEP GRAND CHEROKEE 2019: [1.7321233388827006, 1.289689569171081, 0.15046331002097185] -JEEP GRAND CHEROKEE V6 2018: [1.8776598027756923, 1.4057367824262523, 0.11725947414922003] +JEEP GRAND CHEROKEE 2019: [2.30972, 1.289689569171081, 0.117048] +JEEP GRAND CHEROKEE V6 2018: [2.27116, 1.4057367824262523, 0.11725947414922003] KIA EV6 2022: [3.2, 2.093457, 0.05] KIA K5 2021: [2.405339728085138, 1.460032270828705, 0.11650989850813716] KIA NIRO EV 2020: [2.9215954981365337, 2.1500583840260044, 0.09236802474810267] From dae133181701f5f1cc84daa081a8c71d8c7e084a Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 8 Feb 2023 22:21:50 -0500 Subject: [PATCH 0884/1179] HKG: Car Port for Kia Niro Hybrid 2023 (HDA1) (#26827) * HKG: Car Port for Kia Niro Hybrid 2023 (HDA1) * bump opendbc * bump * Found gear signal * Only set one flag * bump opendbc * Update CARS.md * Update routes.py * bump opendbc * Update CARS.md * some values cleanup * new route with rlogs * set from data * merge (3854+3391+3227+3336)/4 * fine move back down here for now fine move back down here for now * Update selfdrive/car/hyundai/interface.py --------- Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/hyundai/carstate.py | 8 ++++++-- selfdrive/car/hyundai/interface.py | 11 +++++++---- selfdrive/car/hyundai/values.py | 17 +++++++++++++++-- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 7 files changed, 33 insertions(+), 9 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 2e8dbb44bd..d99fe8183f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -9,6 +9,7 @@ Version 0.9.1 (2023-2-20) * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support * Kia K5 Hybrid 2020 support thanks to sunnyhaibin! +* Kia Niro Hybrid 2023 support thanks to sunnyhaibin! * Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! * Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607! diff --git a/docs/CARS.md b/docs/CARS.md index b73f09334d..a72bf74278 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 234 Supported Cars +# 235 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -107,6 +107,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|| |Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| +|Kia|Niro Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[1](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| |Kia|Niro Plug-in Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| |Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|| diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index da1a7bfa78..06efa54605 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -21,7 +21,9 @@ class CarState(CarStateBase): self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES) self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES) - self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else "GEAR_SHIFTER" + self.gear_msg_canfd = "GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \ + "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \ + "GEAR_SHIFTER" if CP.carFingerprint in CANFD_CAR: self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"] elif self.CP.carFingerprint in FEATURES["use_cluster_gears"]: @@ -425,7 +427,9 @@ class CarState(CarStateBase): def get_can_parser_canfd(CP): cruise_btn_msg = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else "CRUISE_BUTTONS" - gear_msg = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else "GEAR_SHIFTER" + gear_msg = "GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \ + "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \ + "GEAR_SHIFTER" signals = [ ("WHEEL_SPEED_1", "WHEEL_SPEEDS"), ("WHEEL_SPEED_2", "WHEEL_SPEEDS"), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index c708e2b78e..d3a29dc0cb 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -35,9 +35,12 @@ class CarInterface(CarInterfaceBase): # non-HDA2 if 0x1cf not in fingerprint[4]: ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value - # ICE cars do not have 0x130; GEARS message on 0x40 instead + # ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead if 0x130 not in fingerprint[4]: - ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value + if 0x40 not in fingerprint[4]: + ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value + else: + ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value if candidate not in CANFD_RADAR_SCC_CAR: ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value @@ -129,8 +132,8 @@ class CarInterface(CarInterfaceBase): ret.mass = 1985. + STD_CARGO_KG ret.wheelbase = 2.78 ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable - elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021): - ret.mass = 1737. + STD_CARGO_KG + elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_NIRO_HEV_2ND_GEN): + ret.mass = 3452. * CV.LB_TO_KG + STD_CARGO_KG # average of all the cars ret.wheelbase = 2.7 ret.steerRatio = 13.9 if CAR.KIA_NIRO_HEV_2021 else 13.73 # Spec tire_stiffness_factor = 0.385 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4c8e924c49..af0bc18af9 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -61,6 +61,8 @@ class HyundaiFlags(IntFlag): ENABLE_BLINKERS = 32 + CANFD_ALT_GEARS_2 = 64 + class CAR: # Hyundai @@ -100,6 +102,7 @@ class CAR: KIA_NIRO_EV = "KIA NIRO EV 2020" KIA_NIRO_PHEV = "KIA NIRO HYBRID 2019" KIA_NIRO_HEV_2021 = "KIA NIRO HYBRID 2021" + KIA_NIRO_HEV_2ND_GEN = "KIA NIRO HYBRID 2ND GEN" KIA_OPTIMA_G4 = "KIA OPTIMA 4TH GEN" KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT" KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019" @@ -208,6 +211,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Niro Hybrid 2021", harness=Harness.hyundai_f), # TODO: could be hyundai_d, verify HyundaiCarInfo("Kia Niro Hybrid 2022", harness=Harness.hyundai_h), ], + CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", harness=Harness.hyundai_a), CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control", harness=Harness.hyundai_b), # TODO: may support 2016, 2018 CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", harness=Harness.hyundai_g), CAR.KIA_OPTIMA_H: [ @@ -1627,6 +1631,14 @@ FW_VERSIONS = { b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ', ], }, + CAR.KIA_NIRO_HEV_2ND_GEN: { + (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.08 99211-AT000 220531', + ], + (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', + ], + }, } CHECKSUM = { @@ -1644,7 +1656,7 @@ FEATURES = { "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020}, } -CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN} +CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN} # The radar does SCC on these cars when HDA I, rather than the camera CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_SORENTO_4TH_GEN} @@ -1652,7 +1664,7 @@ CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, C # The camera does SCC on these cars, rather than the radar CAMERA_SCC_CAR = {CAR.KONA_EV_2022, } -HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_K5_HEV_2020} # these cars use a different gas signal +HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_K5_HEV_2020, CAR.KIA_NIRO_HEV_2ND_GEN} # these cars use a different gas signal EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5, CAR.GENESIS_GV60_EV_1ST_GEN} # these cars require a special panda safety mode due to missing counters and checksums in the messages @@ -1714,4 +1726,5 @@ DBC = { CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None), CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None), CAR.KIA_SORENTO_4TH_GEN: dbc_dict('hyundai_canfd', None), + CAR.KIA_NIRO_HEV_2ND_GEN: dbc_dict('hyundai_canfd', None), } diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 535d3f5415..98db2520c3 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -127,6 +127,7 @@ routes = [ CarTestRoute("50c6c9b85fd1ff03|2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV), CarTestRoute("173219cf50acdd7b|2021-07-05--10-27-41", HYUNDAI.KIA_NIRO_PHEV), CarTestRoute("34a875f29f69841a|2021-07-29--13-02-09", HYUNDAI.KIA_NIRO_HEV_2021), + CarTestRoute("db04d2c63990e3ba|2023-02-08--16-52-39", HYUNDAI.KIA_NIRO_HEV_2ND_GEN), CarTestRoute("50a2212c41f65c7b|2021-05-24--16-22-06", HYUNDAI.KIA_FORTE), CarTestRoute("192283cdbb7a58c2|2022-10-15--01-43-18", HYUNDAI.KIA_SPORTAGE_5TH_GEN), CarTestRoute("c5ac319aa9583f83|2021-06-01--18-18-31", HYUNDAI.ELANTRA), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 462ce91b36..52c9e8d547 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -38,6 +38,7 @@ GENESIS GV70 1ST GEN: [2.42, 2.42, 0.1] KIA SORENTO PLUG-IN HYBRID 4TH GEN: [2.5, 2.5, 0.1] GENESIS GV60 ELECTRIC 1ST GEN: [2.5, 2.5, 0.1] KIA SORENTO 4TH GEN: [2.5, 2.5, 0.1] +KIA NIRO HYBRID 2ND GEN: [2.42, 2.5, 0.12] # Dashcam or fallback configured as ideal car mock: [10.0, 10, 0.0] From 542345a7c2606e0c2ea9b88c7d91a22c3a97f88a Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Thu, 9 Feb 2023 00:25:31 -0500 Subject: [PATCH 0885/1179] Hyundai CAN-FD: use common PT bus function (#27268) * Hyundai CAN-FD: PT bus detection cleanup * Do this when ICE CAN-FD is supported! * Only needs to be checked for non-HDA2, HDA2 uses 0x1cf * Unused Co-authored-by: Shane Smiskol * Keep it the same for now --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/carstate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 06efa54605..0bab188790 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -6,6 +6,7 @@ from cereal import car from common.conversions import Conversions as CV from opendbc.can.parser import CANParser from opendbc.can.can_define import CANDefine +from selfdrive.car.hyundai.hyundaicanfd import get_e_can_bus from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, FEATURES, CAMERA_SCC_CAR, CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams from selfdrive.car.interfaces import CarStateBase @@ -515,8 +516,7 @@ class CarState(CarStateBase): ("ACCELERATOR_BRAKE_ALT", 100), ] - bus = 5 if CP.flags & HyundaiFlags.CANFD_HDA2 else 4 - return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, bus) + return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, get_e_can_bus(CP)) @staticmethod def get_cam_can_parser_canfd(CP): From 1e49c54ffb274a7987626ebfaa8eb3e75ac6fe7c Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Wed, 8 Feb 2023 22:21:31 -0800 Subject: [PATCH 0886/1179] new model: improved height estimation (#27234) * 07a3a2b2-6dbe-43c3-9bb9-a8023932e054/449 c3d7d18a-6207-42e7-84d9-601ecb3c6f0e/700 * 07a3a2b2-6dbe-43c3-9bb9-a8023932e054/449 db92e7f3-3f4b-4f0f-95ff-76cb6ed6894a/700 * update 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 2daf01ea14..a483fa4db4 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:3d8f2f9d53908e7a5496412956548dab1aa08ed0b5fb9d1c685f275369f07a57 +oid sha256:736ddc08497d7596bae4d9515a8efb996676be80e67a6d34d632bb8af2ed3fa9 size 45962515 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index fa4fa9540d..c64f522352 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -2a255ecea3665a3d295210195fd8ef0791ab49a0 +ba947edbb131a2a36ced7c490dfcf3280ad5b167 From 37abe3711788d87255b6b1719ea2dc30f0b57522 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 10 Feb 2023 02:37:37 +0800 Subject: [PATCH 0887/1179] cabana: set series color in createSeries (#27270) * set color in createSeries * fix --- tools/cabana/chartswidget.cc | 9 +++++---- tools/cabana/chartswidget.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 134a162679..e31e437280 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -365,7 +365,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { } void ChartView::addSeries(const QString &msg_id, const Signal *sig) { - QXYSeries *series = createSeries(series_type); + QXYSeries *series = createSeries(series_type, getColor(sig)); chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); @@ -519,8 +519,8 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even s.vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz s.last_value_mono_time = 0; - s.series->setColor(getColor(s.sig)); } + s.series->setColor(getColor(s.sig)); struct Chunk { std::vector::const_iterator first, second; @@ -777,13 +777,14 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } -QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type) { +QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor color) { QXYSeries *series = nullptr; if (type == QAbstractSeries::SeriesTypeLine) { series = new QLineSeries(this); } else { series = new QScatterSeries(this); } + series->setColor(color); // TODO: Due to a bug in CameraWidget the camera frames // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed #ifndef __APPLE__ @@ -802,7 +803,7 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { s.series->deleteLater(); } for (auto &s : sigs) { - auto series = createSeries(series_type); + auto series = createSeries(series_type, getColor(s.sig)); chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 953026d935..25949dd654 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -76,7 +76,7 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; std::tuple getNiceAxisNumbers(qreal min, qreal max, int tick_count); qreal niceNumber(qreal x, bool ceiling); - QXYSeries *createSeries(QAbstractSeries::SeriesType type); + QXYSeries *createSeries(QAbstractSeries::SeriesType type, QColor color); void updateSeriesPoints(); int y_label_width = 0; From b2d9a24d99407b3eb3a63b68404f60496c007c02 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 9 Feb 2023 11:43:34 -0800 Subject: [PATCH 0888/1179] Chrysler: remove Pacifica 2018 ICE from tuning blacklist (#27272) remove Pacifica 2018 ICE from blacklist --- selfdrive/car/chrysler/values.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index e932238e6a..49f8a080cb 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -62,8 +62,7 @@ RAM_CARS = RAM_DT | RAM_HD # the increased steer rate hasn't been verified on these cars. # remove from this list once it's been tested and confirmed to not fault -CHRYSLER_OLD_TUNING_BLACKLIST = {CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018, CAR.PACIFICA_2018_HYBRID, - CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE} +CHRYSLER_OLD_TUNING_BLACKLIST = {CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE} @dataclass class ChryslerCarInfo(CarInfo): From be6f5c6a3392a170c266254898c1bc7c7b182502 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Thu, 9 Feb 2023 15:34:08 -0500 Subject: [PATCH 0889/1179] VW MQB: Add FW for 2023 Volkswagen Tiguan (#27273) * VW MQB: Add FW for 2023 Volkswagen Tiguan * regen CARS.md --- docs/CARS.md | 2 +- selfdrive/car/volkswagen/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a72bf74278..c00bd4f324 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -241,7 +241,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 72fcc5d92d..cd30bef73b 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -222,7 +222,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { ], CAR.TAOS_MK1: VWCarInfo("Volkswagen Taos 2022"), CAR.TCROSS_MK1: VWCarInfo("Volkswagen T-Cross 2021", footnotes=[Footnote.VW_MQB_A0]), - CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2019-22"), + CAR.TIGUAN_MK2: VWCarInfo("Volkswagen Tiguan 2018-23"), CAR.TOURAN_MK2: VWCarInfo("Volkswagen Touran 2017"), CAR.TRANSPORTER_T61: [ VWCarInfo("Volkswagen Caravelle 2020"), @@ -734,6 +734,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906027G \xf1\x899893', b'\xf1\x875N0906259 \xf1\x890002', + b'\xf1\x875NA906259H \xf1\x890002', b'\xf1\x875NA907115E \xf1\x890005', b'\xf1\x8783A907115B \xf1\x890005', b'\xf1\x8783A907115F \xf1\x890002', @@ -751,6 +752,7 @@ FW_VERSIONS = { b'\xf1\x870DL300013A \xf1\x893005', b'\xf1\x870DL300013G \xf1\x892119', b'\xf1\x870DL300013G \xf1\x892120', + b'\xf1\x870DL300014C \xf1\x893703', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AR\xf1\x890317\xf1\x82\02331310031333334313132573732379333313100', @@ -761,6 +763,7 @@ FW_VERSIONS = { b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140013750379333423100', b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\x1331310031333334313140573752379333423100', b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1316143231313500314647021750179333613100', + b'\xf1\x875Q0959655CG\xf1\x890421\xf1\x82\x1331310031333300314240024050409333613100', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820529A6060603', @@ -768,6 +771,7 @@ FW_VERSIONS = { b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567A6000600', b'\xf1\x875QF909144A \xf1\x895581\xf1\x82\x0571A60834A1', b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\00571A60634A1', + b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571A62A32A1', b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\00521A60804A1', From cd37231666f7758697cbdeece7db6067ee37dd75 Mon Sep 17 00:00:00 2001 From: ClockeNessMnstr Date: Thu, 9 Feb 2023 15:51:50 -0500 Subject: [PATCH 0890/1179] add g++-12 dependancy for Ubuntu 22.04 (#27263) add g++-12 dependancy for 22.04 scons -u -j8 gave clang++ not finding iostream and others. https://askubuntu.com/questions/1449769/clang-cannot-find-iostream solution at the bottom of the page worked. installed g++-12 and built fine after that. --- tools/ubuntu_setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ubuntu_setup.sh b/tools/ubuntu_setup.sh index 09296ef94d..71bad2e8a2 100755 --- a/tools/ubuntu_setup.sh +++ b/tools/ubuntu_setup.sh @@ -86,6 +86,7 @@ function install_ubuntu_lts_latest_requirements() { install_ubuntu_common_requirements $SUDO apt-get install -y --no-install-recommends \ + g++-12 \ qtbase5-dev \ qtchooser \ qt5-qmake \ From 9aac0806e3c25c374b67770086cdfd67ffafaf07 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 9 Feb 2023 13:24:52 -0800 Subject: [PATCH 0891/1179] GM: increase min steer speed to avoid temporary faults (#27274) * increase min steer speed to avoid temp volt faults * actually 10.15 is safe * Update ref_commit --- selfdrive/car/gm/interface.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 3c2a12ef86..f7473d88fc 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -101,7 +101,7 @@ class CarInterface(CarInterfaceBase): # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below. # Some GMs need some tolerance above 10 kph to avoid a fault - ret.minSteerSpeed = 10.1 * CV.KPH_TO_MS + ret.minSteerSpeed = 10.2 * CV.KPH_TO_MS ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]] ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 170beafe88..8a75a72483 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a6b17ab903022b42677abe2968f3c6e50c331980 +35a3dbcbcd8504388ea2a70965be0b4e0869b06a From ab6bb8a2fadcbd2e0f34c2ec4df5801419500cc9 Mon Sep 17 00:00:00 2001 From: chaichuansheng88 <124353026+chaichuansheng88@users.noreply.github.com> Date: Fri, 10 Feb 2023 05:50:53 +0800 Subject: [PATCH 0892/1179] Hyundai: add IONIQ 5 fwdCamera FW version (#27209) Update values.py Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index af0bc18af9..2241b871a1 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1557,6 +1557,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', + b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206', ], }, CAR.TUCSON_4TH_GEN: { From cb0522379d85cdf41cdb8ebd11b9119a0b7a364e Mon Sep 17 00:00:00 2001 From: N0VA-DKW <40765867+N0VA-DKW@users.noreply.github.com> Date: Thu, 9 Feb 2023 16:16:07 -0600 Subject: [PATCH 0893/1179] Subaru: add Crosstrek 2022 FW versions (#27222) * Update values.py * Revert "Update values.py" This reverts commit cd9f841c7a97ca800564605e68ea15d611abb3bc. * do clean up later --------- Co-authored-by: Shane Smiskol --- selfdrive/car/subaru/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 6ac2637fa2..5c7d3f5e4d 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -253,6 +253,7 @@ FW_VERSIONS = { b'\xca!f@\x07', b'\xca!fp\x07', b'\xf3"f@\x07', + b'\xe6!fp\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\xe6\xf5\004\000\000', @@ -262,6 +263,7 @@ FW_VERSIONS = { b'\xf1\x00\xd7\x10@', b'\xe6\xf5D0\x00', b'\xe9\xf6F0\x00', + b'\xe9\xf5B0\x00', ], }, CAR.FORESTER: { From a1e5ab1f0756b2955d8970fbbb47c90ec7bede8a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 9 Feb 2023 14:21:41 -0800 Subject: [PATCH 0894/1179] Add C-HR 2021 to release notes --- RELEASES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASES.md b/RELEASES.md index d99fe8183f..cce7207ab0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,6 +12,7 @@ Version 0.9.1 (2023-2-20) * Kia Niro Hybrid 2023 support thanks to sunnyhaibin! * Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! +* Toyota C-HR 2021 support thanks to eFiniLan! * Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607! Version 0.9.0 (2022-11-21) From 95fc84e0b78843a7c8b1a3c42a751d072378960d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 10 Feb 2023 06:52:44 +0800 Subject: [PATCH 0895/1179] cabana: catch exceptions thrown from opendbc (#27242) * catch exceptions thrown from opendbc * Update tools/cabana/mainwin.cc Co-authored-by: Cameron Clough * Update tools/cabana/mainwin.cc Co-authored-by: Cameron Clough * show error line in detailed text --------- Co-authored-by: Cameron Clough --- tools/cabana/dbcmanager.cc | 14 ++++++++++---- tools/cabana/dbcmanager.h | 2 +- tools/cabana/mainwin.cc | 24 ++++++++++++++++++------ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 83f5fdb74a..3d565e7067 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -13,10 +13,16 @@ void DBCManager::open(const QString &dbc_file_name) { initMsgMap(); } -void DBCManager::open(const QString &name, const QString &content) { - std::istringstream stream(content.toStdString()); - dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); - initMsgMap(); +bool DBCManager::open(const QString &name, const QString &content, QString *error) { + try { + std::istringstream stream(content.toStdString()); + dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); + initMsgMap(); + return true; + } catch (std::exception &e) { + if (error) *error = e.what(); + } + return false; } void DBCManager::initMsgMap() { diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 03bd16f2a5..41471a6169 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -22,7 +22,7 @@ public: ~DBCManager(); void open(const QString &dbc_file_name); - void open(const QString &name, const QString &content); + bool open(const QString &name, const QString &content, QString *error = nullptr); QString generateDBC(); void addSignal(const QString &id, const Signal &sig); void updateSignal(const QString &id, const QString &sig_name, const Signal &sig); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index b24c4e6dc4..bce6d313c8 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -220,9 +220,16 @@ void MainWindow::loadFile(const QString &fn) { QFile file(fn); if (file.open(QIODevice::ReadOnly)) { auto dbc_name = QFileInfo(fn).baseName(); - dbc()->open(dbc_name, file.readAll()); - setCurrentFile(fn); - statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); + QString error; + bool ret = dbc()->open(dbc_name, file.readAll(), &error); + if (ret) { + setCurrentFile(fn); + statusBar()->showMessage(tr("DBC File %1 loaded").arg(fn), 2000); + } else { + QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC file"), tr("Failed to parse DBC file %1").arg(fn)); + msg_box.setDetailedText(error); + msg_box.exec(); + } } } } @@ -251,11 +258,16 @@ void MainWindow::loadDBCFromOpendbc(const QString &name) { void MainWindow::loadDBCFromClipboard() { remindSaveChanges(); QString dbc_str = QGuiApplication::clipboard()->text(); - dbc()->open("from_clipboard.dbc", dbc_str); - if (dbc()->messages().size() > 0) { + QString error; + bool ret = dbc()->open("clipboard", dbc_str, &error); + if (ret && dbc()->messages().size() > 0) { QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); } else { - QMessageBox::warning(this, tr("Load From Clipboard"), tr("Failed to parse dbc from clipboard!\nMake sure that you paste the text with correct format.")); + QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC from clipboard"), tr("Make sure that you paste the text with correct format.")); + if (!error.isEmpty()) { + msg_box.setDetailedText(error); + } + msg_box.exec(); } } From 8f5057ff2dbea4ebc85bc8f55bc7a37e4d5969b6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 9 Feb 2023 15:37:39 -0800 Subject: [PATCH 0896/1179] GM: enforce steering command message timing (#27250) * draft * bump opendbc * still draft * that's not right * superset of the changes, 33hz * cleanup * this should work * remove line * pass it in again * actually no need to check updated now * now_nanos * consistent name * fix replay * one line isn't that bad switch switch * fix CarController tests * Update ref_commit --- selfdrive/car/body/carcontroller.py | 2 +- selfdrive/car/body/interface.py | 4 ++-- selfdrive/car/chrysler/carcontroller.py | 2 +- selfdrive/car/chrysler/interface.py | 4 ++-- selfdrive/car/ford/carcontroller.py | 2 +- selfdrive/car/ford/interface.py | 4 ++-- selfdrive/car/gm/carcontroller.py | 11 +++++++---- selfdrive/car/gm/carstate.py | 2 ++ selfdrive/car/gm/interface.py | 4 ++-- selfdrive/car/honda/carcontroller.py | 2 +- selfdrive/car/honda/interface.py | 4 ++-- selfdrive/car/hyundai/carcontroller.py | 2 +- selfdrive/car/hyundai/interface.py | 4 ++-- selfdrive/car/interfaces.py | 2 +- selfdrive/car/mazda/carcontroller.py | 2 +- selfdrive/car/mazda/interface.py | 4 ++-- selfdrive/car/mock/interface.py | 2 +- selfdrive/car/nissan/carcontroller.py | 2 +- selfdrive/car/nissan/interface.py | 4 ++-- selfdrive/car/subaru/carcontroller.py | 2 +- selfdrive/car/subaru/interface.py | 4 ++-- selfdrive/car/tesla/carcontroller.py | 2 +- selfdrive/car/tesla/interface.py | 4 ++-- selfdrive/car/tests/test_car_interfaces.py | 8 ++++---- selfdrive/car/tests/test_models.py | 2 +- selfdrive/car/toyota/carcontroller.py | 2 +- selfdrive/car/toyota/interface.py | 4 ++-- selfdrive/car/volkswagen/carcontroller.py | 2 +- selfdrive/car/volkswagen/interface.py | 4 ++-- selfdrive/controls/controlsd.py | 6 +++++- selfdrive/test/process_replay/ref_commit | 2 +- 31 files changed, 57 insertions(+), 48 deletions(-) diff --git a/selfdrive/car/body/carcontroller.py b/selfdrive/car/body/carcontroller.py index 00673a7e28..bcaf6f6f93 100644 --- a/selfdrive/car/body/carcontroller.py +++ b/selfdrive/car/body/carcontroller.py @@ -35,7 +35,7 @@ class CarController: torque -= deadband return torque - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): torque_l = 0 torque_r = 0 diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index a90c4cfb87..850a3538ad 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -43,5 +43,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index ba6aaf8250..20a44bce21 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -19,7 +19,7 @@ class CarController: self.packer = CANPacker(dbc_name) self.params = CarControllerParams(CP) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): can_sends = [] lkas_active = CC.latActive and self.lkas_control_bit_prev diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 2b2fde8dc3..657b018c00 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -106,5 +106,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/ford/carcontroller.py b/selfdrive/car/ford/carcontroller.py index 00fb461223..99072ae975 100644 --- a/selfdrive/car/ford/carcontroller.py +++ b/selfdrive/car/ford/carcontroller.py @@ -21,7 +21,7 @@ class CarController: self.lkas_enabled_last = False self.steer_alert_last = False - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): can_sends = [] actuators = CC.actuators diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 8ce30e5d68..9e1366618c 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -78,5 +78,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 97f8b60e59..73085d30b0 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -13,6 +13,8 @@ LongCtrlState = car.CarControl.Actuators.LongControlState # Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s CAMERA_CANCEL_DELAY_FRAMES = 10 +# Enforce a minimum interval between steering messages to avoid a fault +MIN_STEER_MSG_INTERVAL_MS = 15 class CarController: @@ -37,7 +39,7 @@ class CarController: self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis']) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl hud_alert = hud_control.visualAlert @@ -64,9 +66,10 @@ class CarController: self.lka_steering_cmd_counter += 1 self.sent_lka_steering_cmd = True - # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we just - # received the ASCMLKASteeringCmd loopback confirmation in the current CS frame - if (self.frame - self.last_steer_frame) >= steer_step and not CS.loopback_lka_steering_cmd_updated: + # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we + # received the ASCMLKASteeringCmd loopback confirmation too recently + last_lka_steer_msg_ms = (now_nanos - CS.loopback_lka_steering_cmd_ts_nanos) * 1e-6 + if (self.frame - self.last_steer_frame) >= steer_step and last_lka_steer_msg_ms > MIN_STEER_MSG_INTERVAL_MS: # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus if not self.sent_lka_steering_cmd: self.lka_steering_cmd_counter = CS.pt_lka_steering_cmd_counter + 1 diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index b73b7e7059..3ddec13ced 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -18,6 +18,7 @@ class CarState(CarStateBase): can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] self.loopback_lka_steering_cmd_updated = False + self.loopback_lka_steering_cmd_ts_nanos = 0 self.pt_lka_steering_cmd_counter = 0 self.cam_lka_steering_cmd_counter = 0 self.buttons_counter = 0 @@ -33,6 +34,7 @@ class CarState(CarStateBase): # Variables used for avoiding LKAS faults self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 + self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] if self.CP.networkLocation == NetworkLocation.fwdCamera: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index f7473d88fc..5ad1776f97 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -236,5 +236,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index ab944a30aa..4dc1dc8131 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -124,7 +124,7 @@ class CarController: self.brake = 0.0 self.last_steer = 0.0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl hud_v_cruise = hud_control.setSpeed * CV.MS_TO_KPH if hud_control.speedVisible else 255 diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 98243d81dd..66c0ce4275 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -348,5 +348,5 @@ class CarInterface(CarInterfaceBase): # pass in a car.CarControl # to be called @ 100hz - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 6f043fddbb..7c31a48ba5 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -54,7 +54,7 @@ class CarController: self.car_fingerprint = CP.carFingerprint self.last_button_frame = 0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index d3a29dc0cb..b746680930 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -330,5 +330,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index e75067da7e..249818369c 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -233,7 +233,7 @@ class CarInterfaceBase(ABC): return reader @abstractmethod - def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]: + def apply(self, c: car.CarControl, now_nanos: int) -> Tuple[car.CarControl.Actuators, List[bytes]]: pass def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True, diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 027822cc3f..524a02a370 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -15,7 +15,7 @@ class CarController: self.brake_counter = 0 self.frame = 0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): can_sends = [] apply_steer = 0 diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 65444ff6e0..2930b002d4 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -69,5 +69,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 3ac487dbb7..13210c86d5 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -57,7 +57,7 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): + def apply(self, c, now_nanos): # in mock no carcontrols actuators = car.CarControl.Actuators.new_message() return actuators, [] diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py index ff13812398..45c3dd720c 100644 --- a/selfdrive/car/nissan/carcontroller.py +++ b/selfdrive/car/nissan/carcontroller.py @@ -18,7 +18,7 @@ class CarController: self.packer = CANPacker(dbc_name) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 2e769cf662..074cd1cc57 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -56,5 +56,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index a56e63408e..24d85877d7 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -19,7 +19,7 @@ class CarController: self.p = CarControllerParams(CP) self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index f94333baab..733482ef82 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -112,5 +112,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py index 6e2869d1c2..1f18c3d0ea 100644 --- a/selfdrive/car/tesla/carcontroller.py +++ b/selfdrive/car/tesla/carcontroller.py @@ -14,7 +14,7 @@ class CarController: self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt']) self.tesla_can = TeslaCAN(self.packer, self.pt_packer) - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 6a73472108..70d49896cb 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -58,5 +58,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 24c995a2d0..78ecbe425e 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -59,15 +59,15 @@ class TestCarInterfaces(unittest.TestCase): CC = car.CarControl.new_message() for _ in range(10): car_interface.update(CC, []) - car_interface.apply(CC) - car_interface.apply(CC) + car_interface.apply(CC, 0) + car_interface.apply(CC, 0) CC = car.CarControl.new_message() CC.enabled = True for _ in range(10): car_interface.update(CC, []) - car_interface.apply(CC) - car_interface.apply(CC) + car_interface.apply(CC, 0) + car_interface.apply(CC, 0) # Test radar interface RadarInterface = importlib.import_module(f'selfdrive.car.{car_params.carName}.radar_interface').RadarInterface diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 4627b9a570..6fbe1436f1 100755 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -149,7 +149,7 @@ class TestCarModelBase(unittest.TestCase): for i, msg in enumerate(self.can_msgs): CS = self.CI.update(CC, (msg.as_builder().to_bytes(),)) - self.CI.apply(CC) + self.CI.apply(CC, msg.logMonoTime) if CS.canValid: can_valid = True diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 222cf70613..2e0d7009c8 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -34,7 +34,7 @@ class CarController: self.gas = 0 self.accel = 0 - def update(self, CC, CS): + def update(self, CC, CS, now_nanos): actuators = CC.actuators hud_control = CC.hudControl pcm_cancel_cmd = CC.cruiseControl.cancel diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 438a9c11fc..a09b0e5265 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -263,5 +263,5 @@ class CarInterface(CarInterfaceBase): # pass in a car.CarControl # to be called @ 100hz - def apply(self, c): - return self.CC.update(c, self.CS) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, now_nanos) diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 4b19f4d13c..5d00b5a52f 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -24,7 +24,7 @@ class CarController: self.hcaSameTorqueCount = 0 self.hcaEnabledFrameCount = 0 - def update(self, CC, CS, ext_bus): + def update(self, CC, CS, ext_bus, now_nanos): actuators = CC.actuators hud_control = CC.hudControl can_sends = [] diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 1e620b4f73..521c68184d 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -244,5 +244,5 @@ class CarInterface(CarInterfaceBase): return ret - def apply(self, c): - return self.CC.update(c, self.CS, self.ext_bus) + def apply(self, c, now_nanos): + return self.CC.update(c, self.CS, self.ext_bus, now_nanos) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index fff6bcf576..1bb5be9a56 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -187,6 +187,7 @@ class Controls: # TODO: no longer necessary, aside from process replay self.sm['liveParameters'].valid = True + self.can_log_mono_time = 0 self.startup_event = get_startup_event(car_recognized, controller_available, len(self.CP.carFw) > 0) @@ -425,6 +426,8 @@ class Controls: # Update carState from CAN can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True) CS = self.CI.update(self.CC, can_strs) + if len(can_strs) and REPLAY: + self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime self.sm.update(0) @@ -731,7 +734,8 @@ class Controls: if not self.read_only and self.initialized: # send car controls over can - self.last_actuators, can_sends = self.CI.apply(CC) + now_nanos = self.can_log_mono_time if REPLAY else int(sec_since_boot() * 1e9) + self.last_actuators, can_sends = self.CI.apply(CC, now_nanos) self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid)) CC.actuatorsOutput = self.last_actuators if self.CP.steerControlType == car.CarParams.SteerControlType.angle: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 8a75a72483..d334792c48 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -35a3dbcbcd8504388ea2a70965be0b4e0869b06a +9bfd30202a9e70d9d7459cc02f86c3e55d7c864c From 37f3fe5eadf41a070bb59a62ce2913c77250afe7 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:37:34 -0600 Subject: [PATCH 0897/1179] Add several missing CHR_TSS2 firmwares (#27278) `@Dk#3633` 2021 C-HR DongleID/route 4930c054f086c108|2023-02-09--18-39-48 Verified working great, per user. Hot off the heels of @eFiniLan's https://github.com/commaai/openpilot/pull/27212 :wink: --- selfdrive/car/toyota/values.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 7e801990a7..b28059ae23 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -233,7 +233,7 @@ FW_QUERY_CONFIG = FwQueryConfig( # FIXME: On some models, abs can sometimes be missing Ecu.abs: [CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.SIENNA, CAR.LEXUS_IS], # On some models, the engine can show on two different addresses - Ecu.engine: [CAR.CAMRY, CAR.COROLLA_TSS2, CAR.CHR, CAR.LEXUS_IS, CAR.LEXUS_RC], + Ecu.engine: [CAR.CAMRY, CAR.COROLLA_TSS2, CAR.CHR, CAR.CHR_TSS2, CAR.LEXUS_IS, CAR.LEXUS_RC], } ) @@ -637,18 +637,25 @@ FW_VERSIONS = { }, CAR.CHR_TSS2: { (Ecu.abs, 0x7b0, None): [ + b'F152610260\x00\x00\x00\x00\x00\x00', b'F1526F4270\x00\x00\x00\x00\x00\x00', ], (Ecu.eps, 0x7a1, None): [ b'8965B10091\x00\x00\x00\x00\x00\x00', + b'8965B10110\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x0189663F459000\x00\x00\x00\x00', ], + (Ecu.engine, 0x7e0, None): [ + b'\x0331014000\x00\x00\x00\x00\x00\x00\x00\x00A0202000\x00\x00\x00\x00\x00\x00\x00\x00895231203402\x00\x00\x00\x00', + ], (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821FF410200\x00\x00\x00\x00', b'\x018821FF410300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646FF410200\x00\x00\x00\x008646GF408200\x00\x00\x00\x00', b'\x028646FF411100\x00\x00\x00\x008646GF409000\x00\x00\x00\x00', ], }, From 29ca52bc48dbcfb5e0f74a889229cf44f7a686a6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 9 Feb 2023 16:53:16 -0800 Subject: [PATCH 0898/1179] GM: split steering speeds (#27277) * split steering speeds * update docs * Update ref_commit --- docs/CARS.md | 6 +++--- selfdrive/car/gm/interface.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c00bd4f324..be4163d457 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -17,11 +17,11 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| -|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|Chevrolet|Volt 2017-18[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|| @@ -36,7 +36,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Genesis|GV60 (Advanced Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Genesis|GV60 (Performance Trim) 2023[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Genesis|GV70 2022-23[5](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| -|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| +|GMC|Acadia 2018[3](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| |Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|| diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 5ad1776f97..8bfc067b48 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -67,6 +67,7 @@ class CarInterface(CarInterfaceBase): ret.pcmCruise = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.minEnableSpeed = 5 * CV.KPH_TO_MS + ret.minSteerSpeed = 10 * CV.KPH_TO_MS # Tuning for experimental long ret.longitudinalTuning.kpV = [2.0, 1.5] @@ -89,6 +90,7 @@ class CarInterface(CarInterfaceBase): ret.pcmCruise = False # stock non-adaptive cruise control is kept off # supports stop and go, but initial engage must (conservatively) be above 18mph ret.minEnableSpeed = 18 * CV.MPH_TO_MS + ret.minSteerSpeed = 7 * CV.MPH_TO_MS # Tuning ret.longitudinalTuning.kpV = [2.4, 1.5] @@ -100,8 +102,6 @@ class CarInterface(CarInterfaceBase): ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below. - # Some GMs need some tolerance above 10 kph to avoid a fault - ret.minSteerSpeed = 10.2 * CV.KPH_TO_MS ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]] ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d334792c48..dc7f985eb3 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -9bfd30202a9e70d9d7459cc02f86c3e55d7c864c +9c5d75e9255a5a19d28f4317c382f00f4bc0ac61 From 5ee47408218d0e36681a0ec300e455972db5ef64 Mon Sep 17 00:00:00 2001 From: Manu Date: Fri, 10 Feb 2023 01:54:25 +0100 Subject: [PATCH 0899/1179] Toyota: C-HR Hybrid 2022 support (#27269) * Added C-HR 2022 * add harness link * Revert "add harness link" This reverts commit 54eaf4a5d83b2e844175cdcf4637329490e1a5b0. * Revert "Added C-HR 2022" This reverts commit b75a54886fbd0236a309b5c89bf74fd748a5b9e2. * Added Toyota C-HR Hybrid 2022 Added Toyota C-HR Hybrid 2022 * another year * it's a hybrid * fix platform name * new route * add to releases * right right, it's a hybrid --------- Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + selfdrive/car/toyota/interface.py | 2 +- selfdrive/car/toyota/values.py | 26 ++++++++++++++++++++--- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index cce7207ab0..29fa14aad4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,7 @@ Version 0.9.1 (2023-2-20) * Kia Sorento 2022-23 support thanks to sunnyhaibin! * Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin! * Toyota C-HR 2021 support thanks to eFiniLan! +* Toyota C-HR Hybrid 2022 support thanks to Korben00! * Volkswagen Crafter and MAN TGE 2017-23 support thanks to jyoung8607! Version 0.9.0 (2022-11-21) diff --git a/docs/CARS.md b/docs/CARS.md index be4163d457..74e64b969f 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 235 Supported Cars +# 236 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -178,6 +178,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 98db2520c3..a4d2f55581 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -182,6 +182,7 @@ routes = [ CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.CHR), CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.CHR_TSS2), CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.CHRH), + CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.CHRH_TSS2), CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.PRIUS_V), CarTestRoute("202c40641158a6e5|2021-09-21--09-43-24", VOLKSWAGEN.ARTEON_MK1), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 1ac43efc39..61243424f0 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -9,6 +9,7 @@ TOYOTA ALPHARD 2020: TOYOTA SIENNA 2018 TOYOTA PRIUS v 2017 : TOYOTA PRIUS 2017 TOYOTA RAV4 2022: TOYOTA RAV4 HYBRID 2022 TOYOTA C-HR HYBRID 2018: TOYOTA C-HR 2018 +TOYOTA C-HR HYBRID 2022: TOYOTA C-HR 2021 LEXUS IS 2018: LEXUS NX 2018 LEXUS CT HYBRID 2018 : LEXUS NX 2018 LEXUS ES HYBRID 2018: TOYOTA CAMRY HYBRID 2018 diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index a09b0e5265..8b3fd048d9 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -72,7 +72,7 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.5533 ret.mass = 4481. * CV.LB_TO_KG + STD_CARGO_KG # mean between min and max - elif candidate in (CAR.CHR, CAR.CHRH, CAR.CHR_TSS2): + elif candidate in (CAR.CHR, CAR.CHRH, CAR.CHR_TSS2, CAR.CHRH_TSS2): stop_and_go = True ret.wheelbase = 2.63906 ret.steerRatio = 13.6 diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index b28059ae23..b6a556438d 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -51,6 +51,7 @@ class CAR: CHR = "TOYOTA C-HR 2018" CHR_TSS2 = "TOYOTA C-HR 2021" CHRH = "TOYOTA C-HR HYBRID 2018" + CHRH_TSS2 = "TOYOTA C-HR HYBRID 2022" COROLLA = "TOYOTA COROLLA 2017" COROLLA_TSS2 = "TOYOTA COROLLA TSS2 2019" # LSS2 Lexus UX Hybrid is same as a TSS2 Corolla Hybrid @@ -119,6 +120,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), + CAR.CHRH_TSS2: ToyotaCarInfo("Toyota C-HR Hybrid 2022"), CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ ToyotaCarInfo("Toyota Corolla 2020-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), @@ -712,6 +714,23 @@ FW_VERSIONS = { b'8646FF407000 ', ], }, + CAR.CHRH_TSS2: { + (Ecu.eps, 0x7a1, None): [ + b'8965B10092\x00\x00\x00\x00\x00\x00', + ], + (Ecu.abs, 0x7b0, None): [ + b'F152610041\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x0189663F438000\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 15): [ + b'\x018821FF410500\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 109): [ + b'\x028646FF413100\x00\x00\x00\x008646GF411100\x00\x00\x00\x00', + ], + }, CAR.COROLLA: { (Ecu.engine, 0x7e0, None): [ b'\x0230ZC2000\x00\x00\x00\x00\x00\x00\x00\x0050212000\x00\x00\x00\x00\x00\x00\x00\x00', @@ -2058,6 +2077,7 @@ DBC = { CAR.CHR: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CHR_TSS2: dbc_dict('toyota_nodsu_pt_generated', None), CAR.CHRH: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), + CAR.CHRH_TSS2: dbc_dict('toyota_nodsu_pt_generated', None), CAR.CAMRY: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CAMRYH: dbc_dict('toyota_nodsu_pt_generated', 'toyota_adas'), CAR.CAMRY_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), @@ -2099,7 +2119,7 @@ EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_I # Toyota/Lexus Safety Sense 2.0 and 2.5 TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, - CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2} + CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2, CAR.CHRH_TSS2} NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} @@ -2107,9 +2127,9 @@ NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} UNSUPPORTED_DSU_CAR = {CAR.LEXUS_IS, CAR.LEXUS_RC} # these cars have a radar which sends ACC messages instead of the camera -RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2} +RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2, CAR.CHRH_TSS2} -EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, +EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.CHRH_TSS2, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} From 79789011019e923c66a9db05c2da362237ce96b3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 9 Feb 2023 18:54:17 -0800 Subject: [PATCH 0900/1179] controlsd: revert CAN timeout threshold (#27275) * controlsd: revert CAN timeout threshold * dt_ctrl doesn't make sense there --- selfdrive/controls/controlsd.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 1bb5be9a56..63395adf64 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -167,11 +167,11 @@ class Controls: self.state = State.disabled self.enabled = False self.active = False - self.can_rcv_timeout = False self.soft_disable_timer = 0 self.mismatch_counter = 0 self.cruise_mismatch_counter = 0 - self.can_rcv_timeout_counter = 0 + self.can_rcv_timeout_counter = 0 # conseuctive timeout count + self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count self.last_blinker_frame = 0 self.last_steering_pressed_frame = 0 self.distance_traveled = 0 @@ -349,9 +349,10 @@ class Controls: self.events.add(EventName.canError) # generic catch-all. ideally, a more specific event should be added above instead + can_rcv_timeout = self.can_rcv_timeout_counter >= 5 has_disable_events = self.events.any(ET.NO_ENTRY) and (self.events.any(ET.SOFT_DISABLE) or self.events.any(ET.IMMEDIATE_DISABLE)) no_system_errors = (not has_disable_events) or (len(self.events) == num_events) - if (not self.sm.all_checks() or self.can_rcv_timeout) and no_system_errors: + if (not self.sm.all_checks() or can_rcv_timeout) and no_system_errors: if not self.sm.all_alive(): self.events.add(EventName.commIssue) elif not self.sm.all_freq_ok(): @@ -363,7 +364,7 @@ class Controls: 'invalid': [s for s, valid in self.sm.valid.items() if not valid], 'not_alive': [s for s, alive in self.sm.alive.items() if not alive], 'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok], - 'can_rcv_timeout': self.can_rcv_timeout, + 'can_rcv_timeout': can_rcv_timeout, } if logs != self.logged_comm_issue: cloudlog.event("commIssue", error=True, **logs) @@ -445,9 +446,9 @@ class Controls: # Check for CAN timeout if not can_strs: self.can_rcv_timeout_counter += 1 - self.can_rcv_timeout = True + self.can_rcv_cum_timeout_counter += 1 else: - self.can_rcv_timeout = False + self.can_rcv_timeout_counter = 0 # When the panda and controlsd do not agree on controls_allowed # we want to disengage openpilot. However the status from the panda goes through @@ -785,7 +786,7 @@ class Controls: controlsState.cumLagMs = -self.rk.remaining * 1000. controlsState.startMonoTime = int(start_time * 1e9) controlsState.forceDecel = bool(force_decel) - controlsState.canErrorCounter = self.can_rcv_timeout_counter + controlsState.canErrorCounter = self.can_rcv_cum_timeout_counter controlsState.experimentalMode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl lat_tuning = self.CP.lateralTuning.which() From 5ab2d35f7b7d1f224b531e245db7e35925da5e33 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 9 Feb 2023 19:27:51 -0800 Subject: [PATCH 0901/1179] controlsd: higher default set speed in experimental mode (#27279) * controlsd: higher default set speed in experimental mode * update tests * update tests --- selfdrive/controls/controlsd.py | 6 +++-- selfdrive/controls/lib/drive_helpers.py | 26 ++++++++++-------- selfdrive/controls/tests/test_cruise_speed.py | 27 ++++++++++--------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 63395adf64..2c359ec32a 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -183,6 +183,7 @@ class Controls: self.steer_limited = False self.desired_curvature = 0.0 self.desired_curvature_rate = 0.0 + self.experimental_mode = False self.v_cruise_helper = VCruiseHelper(self.CP) # TODO: no longer necessary, aside from process replay @@ -544,7 +545,7 @@ class Controls: else: self.state = State.enabled self.current_alert_types.append(ET.ENABLE) - self.v_cruise_helper.initialize_v_cruise(CS) + self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode) # Check if openpilot is engaged and actuators are enabled self.enabled = self.state in ENABLED_STATES @@ -787,7 +788,7 @@ class Controls: controlsState.startMonoTime = int(start_time * 1e9) controlsState.forceDecel = bool(force_decel) controlsState.canErrorCounter = self.can_rcv_cum_timeout_counter - controlsState.experimentalMode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl + controlsState.experimentalMode = self.experimental_mode lat_tuning = self.CP.lateralTuning.which() if self.joystick_mode: @@ -838,6 +839,7 @@ class Controls: self.prof.checkpoint("Ratekeeper", ignore=True) self.is_metric = self.params.get_bool("IsMetric") + self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl # Sample data from sockets and get a carState CS = self.data_sample() diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index 3d5ec8ac1d..a332d06765 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -8,10 +8,12 @@ from selfdrive.modeld.constants import T_IDXS # WARNING: this value was determined based on the model's training distribution, # model predictions above this speed can be unpredictable -V_CRUISE_MAX = 145 # kph -V_CRUISE_MIN = 8 # kph -V_CRUISE_ENABLE_MIN = 40 # kph -V_CRUISE_INITIAL = 255 # kph +# V_CRUISE's are in kph +V_CRUISE_MIN = 8 +V_CRUISE_MAX = 145 +V_CRUISE_UNSET = 255 +V_CRUISE_INITIAL = 40 +V_CRUISE_INITIAL_EXPERIMENTAL_MODE = 105 IMPERIAL_INCREMENT = 1.6 # should be CV.MPH_TO_KPH, but this causes rounding errors MIN_SPEED = 1.0 @@ -39,15 +41,15 @@ CRUISE_INTERVAL_SIGN = { class VCruiseHelper: def __init__(self, CP): self.CP = CP - self.v_cruise_kph = V_CRUISE_INITIAL - self.v_cruise_cluster_kph = V_CRUISE_INITIAL + self.v_cruise_kph = V_CRUISE_UNSET + self.v_cruise_cluster_kph = V_CRUISE_UNSET self.v_cruise_kph_last = 0 self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0} self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers} @property def v_cruise_initialized(self): - return self.v_cruise_kph != V_CRUISE_INITIAL + return self.v_cruise_kph != V_CRUISE_UNSET def update_v_cruise(self, CS, enabled, is_metric): self.v_cruise_kph_last = self.v_cruise_kph @@ -62,8 +64,8 @@ class VCruiseHelper: self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH self.v_cruise_cluster_kph = CS.cruiseState.speedCluster * CV.MS_TO_KPH else: - self.v_cruise_kph = V_CRUISE_INITIAL - self.v_cruise_cluster_kph = V_CRUISE_INITIAL + self.v_cruise_kph = V_CRUISE_UNSET + self.v_cruise_cluster_kph = V_CRUISE_UNSET def _update_v_cruise_non_pcm(self, CS, enabled, is_metric): # handle button presses. TODO: this should be in state_control, but a decelCruise press @@ -125,16 +127,18 @@ class VCruiseHelper: self.button_timers[b.type.raw] = 1 if b.pressed else 0 self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled} - def initialize_v_cruise(self, CS): + def initialize_v_cruise(self, CS, experimental_mode: bool) -> None: # initializing is handled by the PCM if self.CP.pcmCruise: return + initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode else V_CRUISE_INITIAL + # 250kph or above probably means we never had a set speed if any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents) and self.v_cruise_kph_last < 250: self.v_cruise_kph = self.v_cruise_kph_last else: - self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, V_CRUISE_ENABLE_MIN, V_CRUISE_MAX))) + self.v_cruise_kph = int(round(clip(CS.vEgo * CV.MS_TO_KPH, initial, V_CRUISE_MAX))) self.v_cruise_cluster_kph = self.v_cruise_kph diff --git a/selfdrive/controls/tests/test_cruise_speed.py b/selfdrive/controls/tests/test_cruise_speed.py index cd1d31cf07..b83116af45 100755 --- a/selfdrive/controls/tests/test_cruise_speed.py +++ b/selfdrive/controls/tests/test_cruise_speed.py @@ -3,7 +3,7 @@ import numpy as np from parameterized import parameterized_class import unittest -from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_ENABLE_MIN, IMPERIAL_INCREMENT +from selfdrive.controls.lib.drive_helpers import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT from cereal import car from common.conversions import Conversions as CV from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver @@ -53,16 +53,16 @@ class TestVCruiseHelper(unittest.TestCase): for _ in range(2): self.v_cruise_helper.update_v_cruise(car.CarState(cruiseState={"available": False}), enabled=False, is_metric=False) - def enable(self, v_ego): + def enable(self, v_ego, experimental_mode): # Simulates user pressing set with a current speed - self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego)) + self.v_cruise_helper.initialize_v_cruise(car.CarState(vEgo=v_ego), experimental_mode) def test_adjust_speed(self): """ Asserts speed changes on falling edges of buttons. """ - self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) for btn in (ButtonType.accelCruise, ButtonType.decelCruise): for pressed in (True, False): @@ -86,7 +86,7 @@ class TestVCruiseHelper(unittest.TestCase): CS.buttonEvents = [ButtonEvent(type=ButtonType.decelCruise, pressed=pressed)] self.v_cruise_helper.update_v_cruise(CS, enabled=enabled, is_metric=False) if pressed: - self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) # Expected diff on enabling. Speed should not change on falling edge of pressed self.assertEqual(not pressed, self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last) @@ -96,7 +96,7 @@ class TestVCruiseHelper(unittest.TestCase): Asserts we don't increment set speed if user presses resume/accel to exit cruise standstill. """ - self.enable(0) + self.enable(0, False) for standstill in (True, False): for pressed in (True, False): @@ -116,7 +116,7 @@ class TestVCruiseHelper(unittest.TestCase): for v_ego in np.linspace(0, 100, 101): self.reset_cruise_speed_state() - self.enable(V_CRUISE_ENABLE_MIN * CV.KPH_TO_MS) + self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False) # first decrement speed, then perform gas pressed logic expected_v_cruise_kph = self.v_cruise_helper.v_cruise_kph - IMPERIAL_INCREMENT @@ -137,13 +137,14 @@ class TestVCruiseHelper(unittest.TestCase): Asserts allowed cruise speeds on enabling with SET. """ - for v_ego in np.linspace(0, 100, 101): - self.reset_cruise_speed_state() - self.assertFalse(self.v_cruise_helper.v_cruise_initialized) + for experimental_mode in (True, False): + for v_ego in np.linspace(0, 100, 101): + self.reset_cruise_speed_state() + self.assertFalse(self.v_cruise_helper.v_cruise_initialized) - self.enable(float(v_ego)) - self.assertTrue(V_CRUISE_ENABLE_MIN <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) - self.assertTrue(self.v_cruise_helper.v_cruise_initialized) + self.enable(float(v_ego), experimental_mode) + self.assertTrue(V_CRUISE_INITIAL <= self.v_cruise_helper.v_cruise_kph <= V_CRUISE_MAX) + self.assertTrue(self.v_cruise_helper.v_cruise_initialized) if __name__ == "__main__": From 1f85f84027015ee20fa4affff23e121f4388d93c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 9 Feb 2023 20:44:29 -0800 Subject: [PATCH 0902/1179] UI: fix old frame shown on startup (#27283) Co-authored-by: Comma Device --- selfdrive/ui/qt/widgets/cameraview.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 4a7874b160..8c7a7072e2 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -382,6 +382,10 @@ void CameraWidget::vipcThread() { } } emit vipcThreadFrameReceived(); + } else { + if (!isVisible()) { + vipc_client->connected = false; + } } } From 429311a2cc17ac4d50e28574c1ea35d42a725dc9 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 02:12:33 +0800 Subject: [PATCH 0903/1179] cabana: fix the text of signal value being clipped (#27292) fix value be clipped --- tools/cabana/util.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 2806e175d7..20f4c58423 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -82,6 +82,12 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QStyleOptionViewItemV4 opt = option; initStyleOption(&opt, index); + auto byte_list = opt.text.split(" "); + if (byte_list.size() <= 1) { + QStyledItemDelegate::paint(painter, option, index); + return; + } + if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { painter->setPen(option.palette.color(QPalette::HighlightedText)); } else { @@ -98,7 +104,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & QList colors = index.data(Qt::UserRole).toList(); int i = 0; - for (auto &byte : opt.text.split(" ")) { + for (auto &byte : byte_list) { if (i < colors.size()) { painter->fillRect(pos.marginsAdded(margins), colors[i].value()); } From 237428d0fd42bd0d00156029b38afced3222280e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 02:13:15 +0800 Subject: [PATCH 0904/1179] cabana: dont reset filter after seek (#27290) --- tools/cabana/messageswidget.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 359fe10f50..8279d08a5c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -182,11 +182,10 @@ void MessageListModel::sortMessages() { void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); - bool update_all = new_msgs->size() == can->can_msgs.size(); - if (update_all || (filter_str.isEmpty() && msgs.size() != can->can_msgs.size())) { + if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { msgs = can->can_msgs.keys(); } - if (update_all || msgs.size() != prev_row_count) { + if (msgs.size() != prev_row_count) { sortMessages(); return; } From 409c1c9c6558850bbced8ba05bf125102e6543bb Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 02:13:28 +0800 Subject: [PATCH 0905/1179] cabana: set pen width in createSeries (#27288) --- tools/cabana/chartswidget.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index e31e437280..b228a56973 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -789,6 +789,10 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor colo // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed #ifndef __APPLE__ series->setUseOpenGL(true); + // Qt doesn't properly apply device pixel ratio in OpenGL mode + QPen pen = series->pen(); + pen.setWidth(2.0 * qApp->devicePixelRatio()); + series->setPen(pen); #endif return series; } From d19b6683655813d18c4e485b613dd32666197232 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 02:13:39 +0800 Subject: [PATCH 0906/1179] cabana: fix incorrect bit color after seek (#27287) --- tools/cabana/streams/abstractstream.cc | 1 + tools/cabana/util.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 94d653bcb0..13b154a7ea 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -72,6 +72,7 @@ void AbstractStream::updateLastMsgsTo(double sec) { m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); m.last_change_t = QVector(m.dat.size(), m.ts); + m.bit_change_counts.resize(m.dat.size()); } else { m.freq = m.count / std::max(1.0, m.ts); } diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 20f4c58423..454dd29b87 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -62,6 +62,7 @@ void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { void ChangeTracker::clear() { prev_dat.clear(); last_change_t.clear(); + bit_change_counts.clear(); colors.clear(); } From fae5553838f87b61619c7ba5e673f91dd836401c Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 10 Feb 2023 19:14:45 +0100 Subject: [PATCH 0907/1179] cabana: add include to fix macos build (#27291) * cabana: add include to fix macos build * Update util.h --------- Co-authored-by: Adeeb Shihadeh --- tools/cabana/util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 5d5b44d63c..8ec4cda90c 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include From 7cfa236ff2a40e80eef8b779131184eea5778242 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 03:31:54 +0800 Subject: [PATCH 0908/1179] cabana: improve SignalItemDelegate::paint (#27295) --- tools/cabana/signaledit.cc | 12 ++++++------ tools/cabana/signaledit.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 2f1a968645..7988037c34 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -266,6 +266,7 @@ void SignalModel::handleSignalRemoved(const Signal *sig) { SignalItemDelegate::SignalItemDelegate(QObject *parent) { name_validator = new NameValidator(this); double_validator = new QDoubleValidator(this); + small_font.setPointSize(8); double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system } @@ -280,20 +281,19 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // color label auto bg_color = getColor(item->sig); - QRect rc{option.rect.left() + 3, option.rect.top(), 22, option.rect.height()}; + QRect rc{option.rect.left(), option.rect.top(), 18, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); - painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 5, 5); + painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 3, 3); painter->setPen(item->highlight ? Qt::white : Qt::black); + painter->setFont(small_font); painter->drawText(rc, Qt::AlignCenter, QString::number(item->row() + 1)); // signal name - QFont font; - font.setBold(true); - painter->setFont(font); + painter->setFont(option.font); painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); QString text = index.data(Qt::DisplayRole).toString(); - QRect text_rect = option.rect.adjusted(rc.width() + 9, 0, 0, 0); + QRect text_rect = option.rect.adjusted(rc.width() + 6, 0, 0, 0); text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index ae88a5b13a..6a904e7328 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -68,6 +68,7 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QValidator *name_validator, *double_validator; + QFont small_font; }; class SignalView : public QWidget { From 152f1bf4858bf8e21d4a059baa5ec5fb4239c8fa Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 04:57:20 +0800 Subject: [PATCH 0909/1179] cabana: fix inconsistent size for play button (#27298) --- tools/cabana/videowidget.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index d8d89a708c..cd3dc0b516 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -32,6 +32,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { // btn controls QHBoxLayout *control_layout = new QHBoxLayout(); play_btn = new QPushButton(); + play_btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); control_layout->addWidget(play_btn); QButtonGroup *group = new QButtonGroup(this); From 3d2c156bbdfe455b97e6852882c5576600c6a600 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 05:40:39 +0800 Subject: [PATCH 0910/1179] cabana: fix y axis precision (#27299) --- tools/cabana/chartswidget.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index b228a56973..5063ec9dea 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -310,7 +310,6 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->setBackgroundVisible(false); axis_x = new QValueAxis(this); axis_y = new QValueAxis(this); - axis_y->setLabelFormat("%.1f"); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); chart->legend()->layout()->setContentsMargins(16, 0, 40, 0); From 0fdcf4efc0740b3caf2cf4683be301edc5bf3fe4 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 11 Feb 2023 06:50:52 +0800 Subject: [PATCH 0911/1179] cabana: fix text-overflow for long msg name (#27297) --- tools/cabana/detailwidget.cc | 3 ++- tools/cabana/detailwidget.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index a7ad572dc1..25d9b3b9ca 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -32,7 +32,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart time_label = new QLabel(this); time_label->setStyleSheet("font-weight:bold"); toolbar->addWidget(time_label); - name_label = new QLabel(this); + name_label = new ElidedLabel(this); + name_label->setContentsMargins(5, 0, 5, 0); name_label->setStyleSheet("font-weight:bold;"); name_label->setAlignment(Qt::AlignCenter); name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index a62e23f226..0983f49924 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -5,6 +5,7 @@ #include #include +#include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/binaryview.h" #include "tools/cabana/chartswidget.h" #include "tools/cabana/historylog.h" @@ -40,7 +41,8 @@ private: void updateState(const QHash * msgs = nullptr); QString msg_id; - QLabel *name_label, *time_label, *warning_icon, *warning_label; + QLabel *time_label, *warning_icon, *warning_label; + ElidedLabel *name_label; QWidget *warning_widget; QTabBar *tabbar; QTabWidget *tab_widget; From 5831a83c907f9f90aac2c53839cd37554b5b235a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 10 Feb 2023 16:14:53 -0800 Subject: [PATCH 0912/1179] GM: add hysteresis to cluster speed (#27301) * add cluster hysteresis * Update ref_commit --- selfdrive/car/gm/carstate.py | 3 +++ selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 3ddec13ced..90705d871e 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -17,6 +17,9 @@ class CarState(CarStateBase): super().__init__(CP) can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"] + self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2. + self.cluster_min_speed = CV.KPH_TO_MS / 2. + self.loopback_lka_steering_cmd_updated = False self.loopback_lka_steering_cmd_ts_nanos = 0 self.pt_lka_steering_cmd_counter = 0 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dc7f985eb3..0081a20e21 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -9c5d75e9255a5a19d28f4317c382f00f4bc0ac61 +fbf92051507b7a7585907b58baadec6b8cc475af From c05aa0e87159e07e66dba946db08735ae83bc442 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 10 Feb 2023 16:32:21 -0800 Subject: [PATCH 0913/1179] Chrysler: log temporary LKAS faults (#27303) * Log temp lkas faults for non-ram * bump to master * add to signals * whoops * ... come onnnnn --- opendbc | 2 +- selfdrive/car/chrysler/carstate.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index d103b156b3..6eab6cf6ad 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit d103b156b36f2bc9d0d6ad9ba1af02a42ecc2b46 +Subproject commit 6eab6cf6ad5ac69539037f4508582fbfaf239eab diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index 0f0d30782a..fdc5aa338a 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -81,8 +81,9 @@ class CarState(CarStateBase): if self.CP.carFingerprint in RAM_CARS: self.auto_high_beam = cp_cam.vl["DAS_6"]['AUTO_HIGH_BEAM_ON'] # Auto High Beam isn't Located in this message on chrysler or jeep currently located in 729 message - ret.steerFaultTemporary = cp.vl["EPS_3"]["DASM_FAULT"] == 1 + ret.steerFaultTemporary = cp.vl["EPS_3"]["DASM_FAULT"] == 1 else: + ret.steerFaultTemporary = cp.vl["EPS_2"]["LKAS_TEMPORARY_FAULT"] == 1 ret.steerFaultPermanent = cp.vl["EPS_2"]["LKAS_STATE"] == 4 # blindspot sensors @@ -135,6 +136,7 @@ class CarState(CarStateBase): ("COUNTER", "EPS_2",), ("COLUMN_TORQUE", "EPS_2"), ("EPS_TORQUE_MOTOR", "EPS_2"), + ("LKAS_TEMPORARY_FAULT", "EPS_2"), ("LKAS_STATE", "EPS_2"), ("COUNTER", "CRUISE_BUTTONS"), ] From 93330302c8abae41175db272f451fd0c5cd2366b Mon Sep 17 00:00:00 2001 From: Yassine Yousfi Date: Fri, 10 Feb 2023 16:52:52 -0800 Subject: [PATCH 0914/1179] add new model to release notes --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 29fa14aad4..ded06346c6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5,6 +5,8 @@ Version 0.9.1 (2023-2-20) * UI updates * Driver monitoring icon shows driver's head pose * German translation thanks to Vrabetz and CzokNorris! +* New driving model + * 30% improved height estimation resulting in better driving performance for tall cars * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support From b1f84f94001e6c8de8bcedb72652831de01dcee4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 10 Feb 2023 22:28:47 -0800 Subject: [PATCH 0915/1179] Chrysler: setup panda safety flag for old tuning's steer limits --- panda | 2 +- selfdrive/car/chrysler/interface.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/panda b/panda index 7d27eb10fb..b29ae782f7 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 7d27eb10fb32095e73f60c59a123cae08cc53719 +Subproject commit b29ae782f78be87e7ac1414773c6015b14eea728 diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 657b018c00..4b22c478a7 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -23,6 +23,9 @@ class CarInterface(CarInterfaceBase): elif candidate in RAM_DT: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_DT + if candidate in CHRYSLER_OLD_TUNING_BLACKLIST: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_LOWER_RATE + ret.minSteerSpeed = 3.8 # m/s CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) if candidate not in RAM_CARS: From 69e52f02fd21844ff068c495b7fcb01ebc53bea5 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 10 Feb 2023 22:43:19 -0800 Subject: [PATCH 0916/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index b29ae782f7..d15250cb14 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit b29ae782f78be87e7ac1414773c6015b14eea728 +Subproject commit d15250cb1454292c6f1217c79642b9ffd93e7595 From 4f2134468f2b2b94daa24d9ba80cc70da0ad8224 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 10 Feb 2023 23:46:48 -0800 Subject: [PATCH 0917/1179] events: reword ESP off alert (#27304) * Rename event * rename to Control * rename to disabled --- selfdrive/controls/lib/events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 3036828662..6d5ed45076 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -729,8 +729,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { }, EventName.espDisabled: { - ET.SOFT_DISABLE: soft_disable_alert("ESP Off"), - ET.NO_ENTRY: NoEntryAlert("ESP Off"), + ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Disabled"), + ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Disabled"), }, EventName.lowBattery: { From ed52916d55cd802be60b9db03f3ce7fe131fcef2 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 10 Feb 2023 23:47:01 -0800 Subject: [PATCH 0918/1179] update chrysler test segment with new flag --- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/process_replay/test_processes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0081a20e21..10665ae18c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -fbf92051507b7a7585907b58baadec6b8cc475af +69e52f02fd21844ff068c495b7fcb01ebc53bea5 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 569090f606..3ff3d36ebc 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -48,7 +48,7 @@ segments = [ ("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"), ("HONDA", "regenC7D5645EB17|2022-09-27--15-47-29--0"), ("HONDA2", "regenCC2ECCE5742|2022-09-27--16-18-01--0"), - ("CHRYSLER", "regenC253C4DAC90|2022-09-27--15-51-03--0"), + ("CHRYSLER", "regenC253C4DAC90|2023-02-10--15-51-03--0"), ("RAM", "regen20490083AE7|2022-09-27--15-53-15--0"), ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"), From 7b654337d6b47e14e0df76ffa43aeac8869e8245 Mon Sep 17 00:00:00 2001 From: Kyumin Han Date: Sat, 11 Feb 2023 01:04:17 -0700 Subject: [PATCH 0919/1179] HKG: remove Kia Stinger 2018 from legacy safety mode (#27302) * Remove Kia stinger from legacy safety system array Enable OP long * update docs --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 74e64b969f..e6b6bbee7d 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -119,7 +119,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| |Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| |Kia|Stinger 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 2241b871a1..bde38b47cc 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1669,7 +1669,8 @@ HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_N EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KONA_EV_2022, CAR.KIA_EV6, CAR.IONIQ_5, CAR.GENESIS_GV60_EV_1ST_GEN} # these cars require a special panda safety mode due to missing counters and checksums in the messages -LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.VELOSTER, CAR.KIA_STINGER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022} +LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.IONIQ, CAR.KONA_EV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.VELOSTER, + CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022} # If 0x500 is present on bus 1 it probably has a Mando radar outputting radar points. # If no points are outputted by default it might be possible to turn it on using selfdrive/debug/hyundai_enable_radar_points.py From 6474e16a720e88181f03652dcfe91306ddbdc06e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 11 Feb 2023 00:12:33 -0800 Subject: [PATCH 0920/1179] GM: add permanent ACC fault signal (#27306) * bump opendbc * check signal * bump opendbc --- opendbc | 2 +- selfdrive/car/gm/carstate.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/opendbc b/opendbc index 6eab6cf6ad..510bfc0695 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 6eab6cf6ad5ac69539037f4508582fbfaf239eab +Subproject commit 510bfc06954e31257f8d8de17adf92f9a68a1b71 diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 90705d871e..3c7d35f2dc 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -100,7 +100,8 @@ class CarState(CarStateBase): ret.parkingBrake = pt_cp.vl["VehicleIgnitionAlt"]["ParkBrake"] == 1 ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0 ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1 - ret.accFaulted = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED + ret.accFaulted = (pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED or + pt_cp.vl["EBCMFrictionBrakeStatus"]["FrictionBrakeUnavailable"] == 1) ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL @@ -155,6 +156,7 @@ class CarState(CarStateBase): ("RLWheelSpd", "EBCMWheelSpdRear"), ("RRWheelSpd", "EBCMWheelSpdRear"), ("MovingBackward", "EBCMWheelSpdRear"), + ("FrictionBrakeUnavailable", "EBCMFrictionBrakeStatus"), ("PRNDL2", "ECMPRDNL2"), ("ManualMode", "ECMPRDNL2"), ("LKADriverAppldTrq", "PSCMStatus"), @@ -180,6 +182,7 @@ class CarState(CarStateBase): ("VehicleIgnitionAlt", 10), ("EBCMWheelSpdFront", 20), ("EBCMWheelSpdRear", 20), + ("EBCMFrictionBrakeStatus", 20), ("AcceleratorPedal2", 33), ("ASCMSteeringButton", 33), ("ECMEngineStatus", 100), From 4998b600ecebf712b127b1e132d249a1b51a90bc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 11 Feb 2023 17:57:10 -0800 Subject: [PATCH 0921/1179] more release notes --- RELEASES.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ded06346c6..f3d4cfb64f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,12 +1,12 @@ -Version 0.9.1 (2023-2-20) +Version 0.9.1 (2023-2-23) ======================== -* Adjust alert volume using ambient noise level -* Removed driver monitoring timer resetting on interaction if face detected and distracted -* UI updates - * Driver monitoring icon shows driver's head pose - * German translation thanks to Vrabetz and CzokNorris! * New driving model * 30% improved height estimation resulting in better driving performance for tall cars +* Driver monitoring: removed timer resetting on user interaction if distracted +* UI updates + * Adjust alert volume using ambient noise level + * Driver monitoring icon shows driver's head pose + * German translation thanks to Vrabetz and CzokNorris! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support From 341eb2e0fd46b79eeb4096b28443f304c3e71528 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 11 Feb 2023 21:12:07 -0800 Subject: [PATCH 0922/1179] boardd: retry on bad SPI RX data len (#27314) Co-authored-by: Comma Device --- selfdrive/boardd/spi.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/boardd/spi.cc b/selfdrive/boardd/spi.cc index c9d4b2ea0e..9a10e30f95 100644 --- a/selfdrive/boardd/spi.cc +++ b/selfdrive/boardd/spi.cc @@ -316,7 +316,10 @@ int PandaSpiHandle::spi_transfer(uint8_t endpoint, uint8_t *tx_data, uint16_t tx goto transfer_fail; } rx_data_len = *(uint16_t *)(rx_buf+1); - assert(rx_data_len < SPI_BUF_SIZE); + if (rx_data_len >= SPI_BUF_SIZE) { + LOGE("SPI: RX data len larger than buf size %d", rx_data_len); + goto transfer_fail; + } // Read data transfer.len = rx_data_len + 1; From f71aad955ca906a69da6d24dee63d1482077de8e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 13 Feb 2023 10:49:33 +0800 Subject: [PATCH 0923/1179] cabana: cancel signal highlighting on leaveEvent (#27315) cacnel signal hilighting on leaveEvent --- tools/cabana/signaledit.cc | 5 +++++ tools/cabana/signaledit.h | 1 + 2 files changed, 6 insertions(+) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 7988037c34..0499b1be8a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -449,3 +449,8 @@ void SignalView::signalHovered(const Signal *sig) { } } } + +void SignalView::leaveEvent(QEvent *event) { + emit highlight(nullptr); + QWidget::leaveEvent(event); +} diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 6a904e7328..c0b649209a 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -89,6 +89,7 @@ signals: private: void rowsChanged(); + void leaveEvent(QEvent *event); QString msg_id; QTreeView *tree; From e219da29b28807a324af1e9c54a3791d8e295230 Mon Sep 17 00:00:00 2001 From: Miniz199922 <124948595+Miniz199922@users.noreply.github.com> Date: Sun, 12 Feb 2023 21:55:31 -0500 Subject: [PATCH 0924/1179] Chrysler: add missing 2020 Jeep SRT address (#27312) * 2020 Jeep srt fingerprint Please update to include my 2020 Jeep srt * Update selfdrive/car/chrysler/values.py * Revert "Update selfdrive/car/chrysler/values.py" This reverts commit 83fc38acbf7e7b257713a0a85096d7d34a6e0c90. * Update selfdrive/car/chrysler/values.py * rm new fp --------- Co-authored-by: Shane Smiskol --- selfdrive/car/chrysler/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 49f8a080cb..c6b8bcadb0 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -142,7 +142,7 @@ FINGERPRINTS = { }], CAR.JEEP_CHEROKEE_2019: [{ # Jeep Grand Cherokee 2019, including most 2020 models - 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 }], } From 38cf0b8382d6f41e4e9ccd2610bdabe34ff33a87 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 13 Feb 2023 12:11:32 +0800 Subject: [PATCH 0925/1179] cabana: fixed the buggy has_more_data, reduce unncessary calls to fetchMore (#27319) --- tools/cabana/historylog.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 3a3397af42..e4ad99758b 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -81,11 +81,12 @@ void HistoryLogModel::updateState() { if (!msg_id.isEmpty()) { uint64_t current_time = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9 + 1; auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); - if ((has_more_data = !new_msgs.empty())) { + if (!new_msgs.empty()) { beginInsertRows({}, 0, new_msgs.size() - 1); messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); endInsertRows(); } + has_more_data = new_msgs.size() >= batch_size; last_fetch_time = current_time; } } @@ -93,11 +94,12 @@ void HistoryLogModel::updateState() { void HistoryLogModel::fetchMore(const QModelIndex &parent) { if (!messages.empty()) { auto new_msgs = fetchData(messages.back().mono_time); - if ((has_more_data = !new_msgs.empty())) { + if (!new_msgs.empty()) { beginInsertRows({}, messages.size(), messages.size() + new_msgs.size() - 1); messages.insert(messages.end(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); endInsertRows(); } + has_more_data = new_msgs.size() >= batch_size; } } From fff6e8baf6791382fc350950ee02e2ab0db78e44 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 13 Feb 2023 12:11:55 +0800 Subject: [PATCH 0926/1179] cabana: fix crash in BinaryView::refresh (#27318) --- tools/cabana/binaryview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index a46c25bdfa..52b31b3559 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -143,8 +143,8 @@ void BinaryView::refresh() { anchor_index = QModelIndex(); resize_sig = nullptr; hovered_sig = nullptr; - highlightPosition(QCursor::pos()); model->refresh(); + highlightPosition(QCursor::pos()); } QSet BinaryView::getOverlappingSignals() const { From e952ad2c66ccaf68027509f5da6b310ddb9c35db Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 14 Feb 2023 02:44:44 +0800 Subject: [PATCH 0927/1179] cabana: draw borders around signals (#27307) * cabana: draw borders around signals * add padding * merge #27294 * add comment * typo * fix alpha * cleanup * spacing =2 --------- Co-authored-by: Willem Melching --- tools/cabana/binaryview.cc | 86 +++++++++++++++++++++++++++++++------- tools/cabana/binaryview.h | 2 + 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 52b31b3559..6f62a04871 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -1,5 +1,7 @@ #include "tools/cabana/binaryview.h" +#include + #include #include #include @@ -7,8 +9,6 @@ #include #include -#include - #include "tools/cabana/commands.h" #include "tools/cabana/streams/abstractstream.h" @@ -83,7 +83,7 @@ void BinaryView::mousePressEvent(QMouseEvent *event) { 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->selection_color = item->bg_color; + delegate->selection_color = getColor(s); break; } } @@ -266,6 +266,17 @@ BinaryItemDelegate::BinaryItemDelegate(QObject *parent) : QStyledItemDelegate(pa hex_font.setBold(true); } +bool BinaryItemDelegate::isSameColor(const QModelIndex &index, int dx, int dy) const { + QModelIndex index2 = index.sibling(index.row() + dy, index.column() + dx); + if (!index2.isValid()) { + return false; + } + auto color1 = ((const BinaryViewModel::Item *)index.internalPointer())->bg_color; + auto color2 = ((const BinaryViewModel::Item *)index2.internalPointer())->bg_color; + // Ignore alpha + return (color1.red() == color2.red()) && (color2.green() == color2.green()) && (color1.blue() == color2.blue()); +} + void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (const BinaryViewModel::Item *)index.internalPointer(); BinaryView *bin_view = (BinaryView *)parent(); @@ -277,24 +288,71 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } else if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, selection_color); painter->setPen(option.palette.color(QPalette::BrightText)); - } else if (!item->sigs.isEmpty() && (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig))) { - bool sig_hovered = item->sigs.contains(bin_view->hovered_sig); - int min_alpha = item->sigs.contains(bin_view->hovered_sig) ? 255 : 50; + } else if (!bin_view->selectionModel()->hasSelection() || !item->sigs.contains(bin_view->resize_sig)) { // not resizing QColor bg = item->bg_color; - if (bg.alpha() < min_alpha) { - bg.setAlpha(min_alpha); + if (bin_view->hovered_sig && item->sigs.contains(bin_view->hovered_sig)) { + bg.setAlpha(255); + painter->fillRect(option.rect, bg.darker(125)); // 4/5x brightness + painter->setPen(option.palette.color(QPalette::BrightText)); + } else { + if (item->sigs.size() > 0) { + drawBorder(painter, option, index); + bg.setAlpha(std::max(50, bg.alpha())); + } + painter->fillRect(option.rect, bg); + painter->setPen(Qt::black); } - painter->fillRect(option.rect, sig_hovered ? bg.darker(125) : bg); // 4/5x brightness - painter->setPen(sig_hovered ? option.palette.color(QPalette::BrightText) : Qt::black); - } else { - painter->fillRect(option.rect, item->bg_color); } - 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->drawText(option.rect.adjusted(8, 0, -8, -3), Qt::AlignRight | Qt::AlignBottom, item->is_msb ? "M" : "L"); } painter->restore(); } + +// Draw border on edge of signal +void BinaryItemDelegate::drawBorder(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + auto item = (const BinaryViewModel::Item *)index.internalPointer(); + QColor border_color = item->bg_color; + border_color.setAlphaF(1.0); + + bool draw_left = !isSameColor(index, -1, 0); + bool draw_top = !isSameColor(index, 0, -1); + bool draw_right = !isSameColor(index, 1, 0); + bool draw_bottom = !isSameColor(index, 0, 1); + + const int spacing = 2; + QRect rc = option.rect.adjusted(draw_left * 3, draw_top * spacing, draw_right * -3, draw_bottom * -spacing); + QRegion subtract; + if (!draw_top) { + if (!draw_left && !isSameColor(index, -1, -1)) { + subtract += QRect{rc.left(), rc.top(), 3, spacing}; + } else if (!draw_right && !isSameColor(index, 1, -1)) { + subtract += QRect{rc.right() - 2, rc.top(), 3, spacing}; + } + } + if (!draw_bottom) { + if (!draw_left && !isSameColor(index, -1, 1)) { + subtract += QRect{rc.left(), rc.bottom() - (spacing - 1), 3, spacing}; + } else if (!draw_right && !isSameColor(index, 1, 1)) { + subtract += QRect{rc.right() - 2, rc.bottom() - (spacing - 1), 3, spacing}; + } + } + + painter->setPen(QPen(border_color, 1)); + if (draw_left) painter->drawLine(rc.topLeft(), rc.bottomLeft()); + if (draw_right) painter->drawLine(rc.topRight(), rc.bottomRight()); + if (draw_bottom) painter->drawLine(rc.bottomLeft(), rc.bottomRight()); + if (draw_top) painter->drawLine(rc.topLeft(), rc.topRight()); + + painter->setClipRegion(QRegion(rc).subtracted(subtract)); + if (!subtract.isEmpty()) { + // fill gaps inside corners. + painter->setPen(QPen(border_color, 2)); + for (auto &r : subtract) { + painter->drawRect(r); + } + } +} diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index d006672793..18d87bdd57 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -13,6 +13,8 @@ public: BinaryItemDelegate(QObject *parent); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setSelectionColor(const QColor &color) { selection_color = color; } + bool isSameColor(const QModelIndex &index, int dx, int dy) const; + void drawBorder(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QFont small_font, hex_font; QColor selection_color; From 507badb11717e23681ddaf7a3f54ebe348978aef Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 14 Feb 2023 06:40:47 +0800 Subject: [PATCH 0928/1179] cabana: set legend marker shape by the series type (#27296) set legend marker shape by the series type --- tools/cabana/chartswidget.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5063ec9dea..aceef40556 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -780,8 +780,10 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor colo QXYSeries *series = nullptr; if (type == QAbstractSeries::SeriesTypeLine) { series = new QLineSeries(this); + chart()->legend()->setMarkerShape(QLegend::MarkerShapeRectangle); } else { series = new QScatterSeries(this); + chart()->legend()->setMarkerShape(QLegend::MarkerShapeCircle); } series->setColor(color); // TODO: Due to a bug in CameraWidget the camera frames From e3de6b88342f050edc0eb89d65b55de0fe2f1a8c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 13 Feb 2023 16:15:59 -0800 Subject: [PATCH 0929/1179] Chrysler: revert torque tuning (#27327) * Chrysler: revert torque tuning * update refs * update refs + route --- panda | 2 +- selfdrive/car/chrysler/interface.py | 23 ++++++++----------- selfdrive/car/chrysler/values.py | 11 ++------- selfdrive/test/process_replay/ref_commit | 2 +- .../test/process_replay/test_processes.py | 2 +- 5 files changed, 14 insertions(+), 26 deletions(-) diff --git a/panda b/panda index d15250cb14..14051f9ce3 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d15250cb1454292c6f1217c79642b9ffd93e7595 +Subproject commit 14051f9ce3c9cbaf7044c81c9902dd0f1cea3980 diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 4b22c478a7..961684f398 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -2,7 +2,7 @@ from cereal import car from panda import Panda from selfdrive.car import STD_CARGO_KG, get_safety_config -from selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, CHRYSLER_OLD_TUNING_BLACKLIST, ChryslerFlags +from selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags from selfdrive.car.interfaces import CarInterfaceBase @@ -23,9 +23,6 @@ class CarInterface(CarInterfaceBase): elif candidate in RAM_DT: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_DT - if candidate in CHRYSLER_OLD_TUNING_BLACKLIST: - ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_LOWER_RATE - ret.minSteerSpeed = 3.8 # m/s CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) if candidate not in RAM_CARS: @@ -41,11 +38,10 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 3.089 ret.steerRatio = 16.2 # Pacifica Hybrid 2017 - if candidate in CHRYSLER_OLD_TUNING_BLACKLIST: - ret.lateralTuning.init('pid') - ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] - ret.lateralTuning.pid.kf = 0.00006 + ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] + ret.lateralTuning.pid.kf = 0.00006 # Jeep elif candidate in (CAR.JEEP_CHEROKEE, CAR.JEEP_CHEROKEE_2019): @@ -54,11 +50,10 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.7 ret.steerActuatorDelay = 0.2 - if candidate in CHRYSLER_OLD_TUNING_BLACKLIST: - ret.lateralTuning.init('pid') - ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] - ret.lateralTuning.pid.kf = 0.00006 + ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[9., 20.], [9., 20.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.15, 0.30], [0.03, 0.05]] + ret.lateralTuning.pid.kf = 0.00006 # Ram elif candidate == CAR.RAM_1500: diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index c6b8bcadb0..16ebb4fa11 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -46,12 +46,8 @@ class CarControllerParams: self.STEER_DELTA_DOWN = 6 self.STEER_MAX = 261 # EPS allows more, up to 350? else: - if CP.carFingerprint in CHRYSLER_OLD_TUNING_BLACKLIST: - self.STEER_DELTA_UP = 3 - self.STEER_DELTA_DOWN = 3 - else: - self.STEER_DELTA_UP = 6 - self.STEER_DELTA_DOWN = 6 + self.STEER_DELTA_UP = 3 + self.STEER_DELTA_DOWN = 3 self.STEER_MAX = 261 # higher than this faults the EPS STEER_THRESHOLD = 120 @@ -60,9 +56,6 @@ RAM_DT = {CAR.RAM_1500, } RAM_HD = {CAR.RAM_HD, } RAM_CARS = RAM_DT | RAM_HD -# the increased steer rate hasn't been verified on these cars. -# remove from this list once it's been tested and confirmed to not fault -CHRYSLER_OLD_TUNING_BLACKLIST = {CAR.PACIFICA_2017_HYBRID, CAR.PACIFICA_2018_HYBRID, CAR.PACIFICA_2020, CAR.JEEP_CHEROKEE} @dataclass class ChryslerCarInfo(CarInfo): diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 10665ae18c..98c78d3be3 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -69e52f02fd21844ff068c495b7fcb01ebc53bea5 \ No newline at end of file +5244c5fea84822bdbcd899a280090e47fb0581b7 \ No newline at end of file diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 3ff3d36ebc..569090f606 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -48,7 +48,7 @@ segments = [ ("TOYOTA3", "regen89026F6BD8D|2022-09-27--15-45-37--0"), ("HONDA", "regenC7D5645EB17|2022-09-27--15-47-29--0"), ("HONDA2", "regenCC2ECCE5742|2022-09-27--16-18-01--0"), - ("CHRYSLER", "regenC253C4DAC90|2023-02-10--15-51-03--0"), + ("CHRYSLER", "regenC253C4DAC90|2022-09-27--15-51-03--0"), ("RAM", "regen20490083AE7|2022-09-27--15-53-15--0"), ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"), From fe6dc7842ec6ffe7a79c98d3dfe701bd101032c6 Mon Sep 17 00:00:00 2001 From: Nelson Chen Date: Mon, 13 Feb 2023 17:06:43 -0800 Subject: [PATCH 0930/1179] Make the latest month in releases.md consistent with 0-padding (#27330) --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index f3d4cfb64f..ceae8d10cb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -Version 0.9.1 (2023-2-23) +Version 0.9.1 (2023-02-23) ======================== * New driving model * 30% improved height estimation resulting in better driving performance for tall cars From d5d19978ad9de0066be943019bd5b7fd89af3487 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 14 Feb 2023 10:25:59 +0800 Subject: [PATCH 0931/1179] cabana: add name validation when editing message (#27316) * check duplicate name * cant use ' untitled' as msg name * const QString UNTITLED --- tools/cabana/dbcmanager.h | 6 ++++-- tools/cabana/detailwidget.cc | 35 ++++++++++++++++++++++++++--------- tools/cabana/detailwidget.h | 5 +++++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 41471a6169..7571d1c44e 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -54,6 +54,8 @@ private: std::map msgs; }; +const QString UNTITLED = "untitled"; + // TODO: Add helper function in dbc.h double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig); bool operator==(const Signal &l, const Signal &r); @@ -63,7 +65,7 @@ int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size); std::pair getSignalRange(const Signal *s); DBCManager *dbc(); -inline QString msgName(const QString &id, const char *def = "untitled") { +inline QString msgName(const QString &id) { auto msg = dbc()->msg(id); - return msg ? msg->name : def; + return msg ? msg->name : UNTITLED; } diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 25d9b3b9ca..27c8cbccc9 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -1,6 +1,5 @@ #include "tools/cabana/detailwidget.h" -#include #include #include #include @@ -190,11 +189,13 @@ void DetailWidget::removeMsg() { // EditMessageDialog -EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) : QDialog(parent) { - setWindowTitle(tr("Edit message")); +EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) + : original_name(title), QDialog(parent) { + setWindowTitle(tr("Edit message: %1").arg(msg_id)); QFormLayout *form_layout = new QFormLayout(this); - form_layout->addRow("ID", new QLabel(msg_id)); + form_layout->addRow("", error_label = new QLabel); + error_label->setVisible(false); name_edit = new QLineEdit(title, this); name_edit->setValidator(new NameValidator(name_edit)); form_layout->addRow(tr("Name"), name_edit); @@ -205,12 +206,28 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title size_spin->setValue(size); form_layout->addRow(tr("Size"), size_spin); - auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - form_layout->addRow(buttonBox); - setFixedWidth(parent->width() * 0.9); + btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + btn_box->button(QDialogButtonBox::Ok)->setEnabled(false); + form_layout->addRow(btn_box); - connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + setFixedWidth(parent->width() * 0.9); + connect(name_edit, &QLineEdit::textEdited, this, &EditMessageDialog::validateName); + connect(btn_box, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +void EditMessageDialog::validateName(const QString &text) { + bool valid = false; + error_label->setVisible(false); + if (!text.isEmpty() && text != original_name && text.compare(UNTITLED, Qt::CaseInsensitive) != 0) { + valid = std::none_of(dbc()->messages().begin(), dbc()->messages().end(), + [&text](auto &m) { return m.second.name == text; }); + if (!valid) { + error_label->setText(tr("Name already exists")); + error_label->setVisible(true); + } + } + btn_box->button(QDialogButtonBox::Ok)->setEnabled(valid); } // WelcomeWidget diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 0983f49924..c5d5fe9a4d 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -14,8 +15,12 @@ class EditMessageDialog : public QDialog { public: EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent); + void validateName(const QString &text); + QString original_name; + QDialogButtonBox *btn_box; QLineEdit *name_edit; + QLabel *error_label; QSpinBox *size_spin; }; From 65a9843ff9bbdf224d539655ea2658101df4da19 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 13 Feb 2023 21:12:13 -0800 Subject: [PATCH 0932/1179] Hyundai: detect LFA HDA message (#27323) * detect lfa message * comment * ? * fix * Update ref_commit --- selfdrive/car/hyundai/carcontroller.py | 6 +----- selfdrive/car/hyundai/interface.py | 4 ++++ selfdrive/car/hyundai/values.py | 3 +-- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 7c31a48ba5..516666eff1 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -178,11 +178,7 @@ class CarController: hud_control.leadVisible, set_speed_in_units, stopping, CC.cruiseControl.override)) # 20 Hz LFA MFA message - if self.frame % 5 == 0 and self.car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.IONIQ, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, - CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV, CAR.KONA_EV_2022, - CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022, - CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022, - CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020): + if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value: can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled)) # 5 Hz ACC options diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index b746680930..ae0f26274c 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -43,6 +43,10 @@ class CarInterface(CarInterfaceBase): ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value if candidate not in CANFD_RADAR_SCC_CAR: ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value + else: + # Send LFA message on cars with HDA + if 0x485 in fingerprint[2]: + ret.flags |= HyundaiFlags.SEND_LFA.value ret.steerActuatorDelay = 0.1 # Default delay ret.steerLimitTimer = 0.4 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index bde38b47cc..261f98f38e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -58,10 +58,9 @@ class HyundaiFlags(IntFlag): CANFD_CAMERA_SCC = 8 ALT_LIMITS = 16 - ENABLE_BLINKERS = 32 - CANFD_ALT_GEARS_2 = 64 + SEND_LFA = 128 class CAR: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 98c78d3be3..a4811375e4 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5244c5fea84822bdbcd899a280090e47fb0581b7 \ No newline at end of file +3629f9d22d0bd70cc9ac19cf2045a6cd47b21fdb From b536b9c4c07742a035723c3a0e1aeb646db6555a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 13 Feb 2023 21:39:06 -0800 Subject: [PATCH 0933/1179] process replay: don't upload if diff doesn't exist (#27333) * fail the replay, successfully print * should still run * debug * outside? * don't fail * don't fail * don't fail * test * test * test * try this now * clean up, works! --- .github/workflows/selfdrive_tests.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index 834b2141d0..efddde720d 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -250,6 +250,7 @@ jobs: ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ coverage xml" - name: Print diff + id: print-diff if: always() run: cat selfdrive/test/process_replay/diff.txt - uses: actions/upload-artifact@v2 @@ -259,7 +260,7 @@ jobs: name: process_replay_diff.txt path: selfdrive/test/process_replay/diff.txt - name: Upload reference logs - if: ${{ failure() && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} + if: ${{ failure() && steps.print-diff.outcome == 'success' && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }} run: | ${{ 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" From a6bf26f5eb5a3cb4059783ce538901b7562a96db Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 14 Feb 2023 16:46:13 +0800 Subject: [PATCH 0934/1179] cabana: fix two bugs in chart (#27336) fix two bugs --- tools/cabana/chartswidget.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index aceef40556..ec54d7f06a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -364,6 +364,8 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { } void ChartView::addSeries(const QString &msg_id, const Signal *sig) { + if (hasSeries(msg_id, sig)) return; + QXYSeries *series = createSeries(series_type, getColor(sig)); chart()->addSeries(series); series->attachAxis(axis_x); @@ -438,9 +440,7 @@ void ChartView::manageSeries() { emit remove(); } else { for (auto s : items) { - if (!hasSeries(s->msg_id, s->sig)) { - addSeries(s->msg_id, s->sig); - } + addSeries(s->msg_id, s->sig); } for (auto it = sigs.begin(); it != sigs.end(); /**/) { bool exists = std::any_of(items.cbegin(), items.cend(), [&](auto &s) { @@ -852,7 +852,9 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) // buttons QVBoxLayout *btn_layout = new QVBoxLayout(); QPushButton *add_btn = new QPushButton(utils::icon("chevron-right"), "", this); + add_btn->setEnabled(false); QPushButton *remove_btn = new QPushButton(utils::icon("chevron-left"), "", this); + remove_btn->setEnabled(false); btn_layout->addStretch(0); btn_layout->addWidget(add_btn); btn_layout->addWidget(remove_btn); From 286e42948e7cd6da66bc6a6c48aedc7ff88fd9eb Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 14 Feb 2023 19:46:29 +0100 Subject: [PATCH 0935/1179] cabana: add keyboard shortcuts to binary view (#27338) * cabana: add keyboard shortcuts to binary view * typo * whitespace * keep signal highlighted --- tools/cabana/binaryview.cc | 59 ++++++++++++++++++++++++++++++++++++ tools/cabana/binaryview.h | 4 +++ tools/cabana/detailwidget.cc | 3 ++ 3 files changed, 66 insertions(+) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 6f62a04871..16df867d56 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -7,9 +7,11 @@ #include #include #include +#include #include #include "tools/cabana/commands.h" +#include "tools/cabana/signaledit.h" #include "tools/cabana/streams/abstractstream.h" // BinaryView @@ -38,6 +40,63 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &BinaryView::refresh); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &BinaryView::refresh); + + addShortcuts(); +} + +void BinaryView::addShortcuts() { + // Delete (x, backspace, delete) + QShortcut *shortcut_delete_x = new QShortcut(QKeySequence(Qt::Key_X), this); + QShortcut *shortcut_delete_backspace = new QShortcut(QKeySequence(Qt::Key_Backspace), this); + QShortcut *shortcut_delete_delete = new QShortcut(QKeySequence(Qt::Key_Delete), this); + QObject::connect(shortcut_delete_delete, &QShortcut::activated, shortcut_delete_x, &QShortcut::activated); + QObject::connect(shortcut_delete_backspace, &QShortcut::activated, shortcut_delete_x, &QShortcut::activated); + QObject::connect(shortcut_delete_x, &QShortcut::activated, [=]{ + if (hovered_sig != nullptr) { + emit removeSignal(hovered_sig); + hovered_sig = nullptr; + } + }); + + // Change endianness (e) + QShortcut *shortcut_endian = new QShortcut(QKeySequence(Qt::Key_E), this); + QObject::connect(shortcut_endian, &QShortcut::activated, [=]{ + if (hovered_sig != nullptr) { + const Signal *hovered_sig_prev = hovered_sig; + Signal s = *hovered_sig; + s.is_little_endian = !s.is_little_endian; + emit editSignal(hovered_sig, s); + + hovered_sig = nullptr; + highlight(hovered_sig_prev); + } + }); + + // Change signedness (s) + QShortcut *shortcut_sign = new QShortcut(QKeySequence(Qt::Key_S), this); + QObject::connect(shortcut_sign, &QShortcut::activated, [=]{ + if (hovered_sig != nullptr) { + const Signal *hovered_sig_prev = hovered_sig; + Signal s = *hovered_sig; + s.is_signed = !s.is_signed; + emit editSignal(hovered_sig, s); + + hovered_sig = nullptr; + highlight(hovered_sig_prev); + } + }); + + // Open chart (c, p, g) + QShortcut *shortcut_plot = new QShortcut(QKeySequence(Qt::Key_P), this); + QShortcut *shortcut_plot_g = new QShortcut(QKeySequence(Qt::Key_G), this); + QShortcut *shortcut_plot_c = new QShortcut(QKeySequence(Qt::Key_C), this); + QObject::connect(shortcut_plot_g, &QShortcut::activated, shortcut_plot, &QShortcut::activated); + QObject::connect(shortcut_plot_c, &QShortcut::activated, shortcut_plot, &QShortcut::activated); + QObject::connect(shortcut_plot, &QShortcut::activated, [=]{ + if (hovered_sig != nullptr) { + emit showChart(model->msg_id, hovered_sig, true, false); + } + }); } QSize BinaryView::minimumSizeHint() const { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 18d87bdd57..7cf9a8081c 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -68,8 +68,12 @@ signals: void signalHovered(const Signal *sig); void addSignal(int start_bit, int size, bool little_endian); void resizeSignal(const Signal *sig, int from, int size); + void removeSignal(const Signal *sig); + void editSignal(const Signal *origin_s, Signal &s); + void showChart(const QString &name, const Signal *sig, bool show, bool merge); private: + void addShortcuts(); void refresh(); std::tuple getSelection(QModelIndex index); void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) override; diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 27c8cbccc9..2036912344 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -74,6 +74,9 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(binary_view, &BinaryView::addSignal, signal_view->model, &SignalModel::addSignal); QObject::connect(binary_view, &BinaryView::signalHovered, signal_view, &SignalView::signalHovered); QObject::connect(binary_view, &BinaryView::signalClicked, signal_view, &SignalView::expandSignal); + QObject::connect(binary_view, &BinaryView::editSignal, signal_view->model, &SignalModel::saveSignal); + QObject::connect(binary_view, &BinaryView::removeSignal, signal_view->model, &SignalModel::removeSignal); + QObject::connect(binary_view, &BinaryView::showChart, charts, &ChartsWidget::showChart); QObject::connect(signal_view, &SignalView::showChart, charts, &ChartsWidget::showChart); QObject::connect(signal_view, &SignalView::highlight, binary_view, &BinaryView::highlight); QObject::connect(tab_widget, &QTabWidget::currentChanged, [this]() { updateState(); }); From b3f327d273c42b4852d00ded35984b833a966a2b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 14 Feb 2023 12:51:24 -0800 Subject: [PATCH 0936/1179] HKG: log AEB/FCW for Optima G4 FL (#27337) FL uses FCA --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 261f98f38e..4ff944cebd 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1653,7 +1653,7 @@ FEATURES = { "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022, CAR.KIA_K5_HEV_2020}, # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020}, + "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_OPTIMA_G4_FL}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN} From e7786738c45aa325d2c4a3649e9b485171e18306 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 14 Feb 2023 13:14:32 -0800 Subject: [PATCH 0937/1179] Hyundai: temporarily remove Tucson FW that requires different tuning (#27340) --- selfdrive/car/hyundai/values.py | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4ff944cebd..a6842ddb1d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1562,7 +1562,6 @@ FW_VERSIONS = { CAR.TUCSON_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T', - b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW010 14X', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ', From 1cdf80003dcaea79375cf398ec65849424f2f44b Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 14 Feb 2023 13:22:49 -0800 Subject: [PATCH 0938/1179] GM: update steering limits (#27331) * reduce steer down limit, driver allowance * update refs * update refs --- panda | 2 +- selfdrive/car/gm/values.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panda b/panda index 14051f9ce3..0d2ee00921 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 14051f9ce3c9cbaf7044c81c9902dd0f1cea3980 +Subproject commit 0d2ee009218009173f26c73a16aefa12dd169de8 diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 7628d8420b..1c956192eb 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -14,8 +14,8 @@ class CarControllerParams: STEER_STEP = 3 # Active control frames per command (~33hz) INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) STEER_DELTA_UP = 10 # Delta rates require review due to observed EPS weakness - STEER_DELTA_DOWN = 25 - STEER_DRIVER_ALLOWANCE = 50 + STEER_DELTA_DOWN = 15 + STEER_DRIVER_ALLOWANCE = 65 STEER_DRIVER_MULTIPLIER = 4 STEER_DRIVER_FACTOR = 100 NEAR_STOP_BRAKE_PHASE = 0.5 # m/s diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a4811375e4..85c7d8e80b 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3629f9d22d0bd70cc9ac19cf2045a6cd47b21fdb +f4efbb65a7eb9a8f4e23492372e707674f80114e \ No newline at end of file From 62b233369bed7a156a019adc5f856f913a50ce61 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 14 Feb 2023 13:27:24 -0800 Subject: [PATCH 0939/1179] HKG: log AEB/FCW for Kia Niro Hybrid 2021 (#27341) Kia Niro Hybrid uses FCA too --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index a6842ddb1d..9067299473 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1652,7 +1652,7 @@ FEATURES = { "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022, CAR.KIA_K5_HEV_2020}, # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_OPTIMA_G4_FL}, + "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_OPTIMA_G4_FL}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN} From 5af5f02ba82a0094c7f721ad8dd6138f503455d8 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 14 Feb 2023 13:29:23 -0800 Subject: [PATCH 0940/1179] better min enable speed alert (#27317) --- selfdrive/controls/lib/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 6d5ed45076..a85e48649f 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -230,7 +230,7 @@ def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM return StartupAlert("WARNING: This branch is not tested", branch, alert_status=AlertStatus.userPrompt) def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: - return NoEntryAlert(f"Speed Below {get_display_speed(CP.minEnableSpeed, metric)}") + return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage") def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: From 6f1d5edab832487c1b11d5e36ec077fdc3def560 Mon Sep 17 00:00:00 2001 From: Mitchell Goff Date: Tue, 14 Feb 2023 14:32:08 -0800 Subject: [PATCH 0941/1179] Add osmnx to xx packages (#27342) --- .pre-commit-config.yaml | 2 +- poetry.lock | 269 +++++++++++++++++++++++++++++++++++++--- pyproject.toml | 3 +- 3 files changed, 254 insertions(+), 20 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index edbca52fed..1779947ff9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: rev: v2.2.1 hooks: - id: codespell - exclude: '^(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/ui/translations/.*.ts)' + exclude: '^(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)' args: # if you've got a short variable name that's getting flagged, add it here - -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup diff --git a/poetry.lock b/poetry.lock index 8edfbb868c..91e1b5c826 100644 --- a/poetry.lock +++ b/poetry.lock @@ -564,6 +564,34 @@ python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "click-plugins" +version = "1.1.1" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[[package]] +name = "cligj" +version = "0.7.2" +description = "Click params for commmand line interfaces to GeoJSON" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4" + +[package.dependencies] +click = ">=4.0" + +[package.extras] +test = ["pytest-cov"] + [[package]] name = "cloudpickle" version = "2.2.0" @@ -959,6 +987,29 @@ python-versions = ">=3.7" docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"] +[[package]] +name = "fiona" +version = "1.9.1" +description = "Fiona reads and writes spatial data files" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=19.2.0" +certifi = "*" +click = ">=8.0,<9.0" +click-plugins = ">=1.0" +cligj = ">=0.5" +munch = ">=2.3.2" +setuptools = "*" + +[package.extras] +all = ["Fiona[calc,s3,test]"] +calc = ["shapely"] +s3 = ["boto3 (>=1.3.1)"] +test = ["Fiona[s3]", "pytest (>=7)", "pytest-cov", "pytz"] + [[package]] name = "flake8" version = "4.0.1" @@ -1092,6 +1143,21 @@ python-versions = ">=3.7" packaging = "*" SQLAlchemy = ">=1.4" +[[package]] +name = "geopandas" +version = "0.12.2" +description = "Geographic pandas extensions" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +fiona = ">=1.8" +packaging = "*" +pandas = ">=1.0.0" +pyproj = ">=2.6.1.post1" +shapely = ">=1.7" + [[package]] name = "gevent" version = "22.10.1" @@ -2325,27 +2391,18 @@ python-versions = ">=3.5" [[package]] name = "networkx" -version = "2.3" +version = "2.8.8" description = "Python package for creating and manipulating graphs and networks" category = "dev" optional = false -python-versions = ">=3.5" - -[package.dependencies] -decorator = ">=4.3.0" +python-versions = ">=3.8" [package.extras] -all = ["gdal", "lxml", "matplotlib", "nose", "numpy", "pandas", "pydot", "pygraphviz", "pyyaml", "scipy"] -gdal = ["gdal"] -lxml = ["lxml"] -matplotlib = ["matplotlib"] -nose = ["nose"] -numpy = ["numpy"] -pandas = ["pandas"] -pydot = ["pydot"] -pygraphviz = ["pygraphviz"] -pyyaml = ["pyyaml"] -scipy = ["scipy"] +default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=0.982)", "pre-commit (>=2.20)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (>=5.2)", "sphinx-gallery (>=0.11)", "texext (>=0.6.6)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"] +test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nodeenv" @@ -2542,6 +2599,31 @@ python-versions = ">=3.6" [package.dependencies] requests = "*" +[[package]] +name = "osmnx" +version = "1.2.2" +description = "Retrieve, model, analyze, and visualize OpenStreetMap street networks and other spatial data" +category = "dev" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +geopandas = ">=0.11" +matplotlib = ">=3.5" +networkx = ">=2.8" +numpy = ">=1.22" +pandas = ">=1.4" +pyproj = ">=3.3" +requests = ">=2.28" +Rtree = ">=1.0" +Shapely = ">=1.8,<2.0" + +[package.extras] +entropy = ["scipy"] +nearest-neighbor = ["scikit-learn", "scipy"] +raster = ["gdal", "rasterio"] +web-map = ["folium"] + [[package]] name = "packaging" version = "21.3" @@ -3486,6 +3568,14 @@ python-versions = "*" numpy = ">=1.11.0" scipy = ">=0.17.1" +[[package]] +name = "rtree" +version = "1.0.1" +description = "R-Tree spatial index for Python GIS" +category = "dev" +optional = false +python-versions = ">=3.7" + [[package]] name = "s2sphere" version = "0.2.5" @@ -3688,6 +3778,19 @@ typing-extensions = "*" test = ["pytest (>=6.2)", "virtualenv (>20)"] toml = ["setuptools (>=42)"] +[[package]] +name = "shapely" +version = "1.8.5.post1" +description = "Geometric objects, predicates, and operations" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +all = ["numpy", "pytest", "pytest-cov"] +test = ["pytest", "pytest-cov"] +vectorized = ["numpy"] + [[package]] name = "shellingham" version = "1.5.0" @@ -4464,7 +4567,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "3c2597d2199a29ef79dd4d5fbc5e2350d86c82a3fe6716d13b93ebc268053eb9" +content-hash = "9e9495c896e6fd0855803aeaf46513c6c22424b86be820759a8baf27d44e73ee" [metadata.files] adal = [ @@ -4917,6 +5020,14 @@ click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] +click-plugins = [ + {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, + {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, +] +cligj = [ + {file = "cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df"}, + {file = "cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27"}, +] cloudpickle = [ {file = "cloudpickle-2.2.0-py3-none-any.whl", hash = "sha256:7428798d5926d8fcbfd092d18d01a2a03daf8237d8fcdc8095d256b8490796f0"}, {file = "cloudpickle-2.2.0.tar.gz", hash = "sha256:3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f"}, @@ -5339,6 +5450,28 @@ filelock = [ {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, ] +fiona = [ + {file = "Fiona-1.9.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:902b67b2d012c5797b5d7d3cb3b46dcf9a342cf90a7f7e53fb12c83738d19926"}, + {file = "Fiona-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2f4535ae2c8446e6b328745a44567478d5a077ed63c888b8c212dddb1e11925"}, + {file = "Fiona-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3d7f3286fb59b93cefefb89014b6fa8413126e180e15c576db859ba936cf334"}, + {file = "Fiona-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:692fe64c0f3a39742d6f7a8e420a8387f6aec3b6818b727d2dfc98a0c40e992d"}, + {file = "Fiona-1.9.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:a017a39650df0cc541c57cf7de450bb4cee6fd9760eb716323b594c1074634a2"}, + {file = "Fiona-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3b52d49bc379fdcfd1250b38e7e00ab24ee14eb765376c793bbe251ffd09d6a"}, + {file = "Fiona-1.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbb0ae851cd4417104c469335a01f938251a8639317f93d422c5c808150bd27"}, + {file = "Fiona-1.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:4a6d8fcbbdafa8af8ac1904628b0267382ed9f9921933d061d7bfc5d3f3daf99"}, + {file = "Fiona-1.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:74f056a84dc52a0b21a2cf024601a69105596f06f28d40b45049948be17b4df2"}, + {file = "Fiona-1.9.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5b9f3f6c782bb4ae2c924eefd373cabdeaaa99f86477b9c7c71eb20c052ee7c5"}, + {file = "Fiona-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5d6183189a7e05e2498d38a1df3ab07e1353fa48e977cbc3a31203927bd06bca"}, + {file = "Fiona-1.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5f2c14beec98a330aee1fd81fa0447a6aa1d5e0a75d000c0052dbe1f23dd6cfd"}, + {file = "Fiona-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:585a47ec21f2d198abc112158eaf12a6587a272beb7f001162d8c3b262676666"}, + {file = "Fiona-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4368b4054f21518a19dea54ce9ac445c40418c6331c0c99d1531c3ddff05da"}, + {file = "Fiona-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:839ed0db23198bb754f0d655d4eeaf5f9c141bef734557e77e95e4dc83e42e7f"}, + {file = "Fiona-1.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:decca3956032ae2d2c19d2f7fa8a4553c43a6e66eb5abe9a05f6ddadcb1bfe5c"}, + {file = "Fiona-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb827fa0030d03d8080723137c74b865ec18dbade87c02ed60215491a315c6be"}, + {file = "Fiona-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7e0f36484757baa8cd1c0602941e029ff992282776f9afae4c5b90f501ff005"}, + {file = "Fiona-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:f98933b552adf0506799097934a6950de412288e7a50466144d04874d6f63fbc"}, + {file = "Fiona-1.9.1.tar.gz", hash = "sha256:3a3725e94840a387fef48726d60db6a6791563f366939d22378a4661f8941be7"}, +] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, @@ -5463,6 +5596,10 @@ geoalchemy2 = [ {file = "GeoAlchemy2-0.12.5-py2.py3-none-any.whl", hash = "sha256:3a59eb651df95b3dfee8e1d82f4d18c80b75f712860a0a3080defc6b0435070d"}, {file = "GeoAlchemy2-0.12.5.tar.gz", hash = "sha256:31c2502dce317b57b335e4eb87562d501fa39e46c728be514d9b86091e08dd67"}, ] +geopandas = [ + {file = "geopandas-0.12.2-py3-none-any.whl", hash = "sha256:0a470e4bf6f5367e6fd83ab6b40405e0b805c8174665bbcb7c4077ed90202912"}, + {file = "geopandas-0.12.2.tar.gz", hash = "sha256:0acdacddefa176525e4da6d9aeeece225da26055c4becdc6e97cf40fa97c27f4"}, +] gevent = [ {file = "gevent-22.10.1-cp27-cp27m-win32.whl", hash = "sha256:702a51b8f21bad1976b0893f90ade466e8c27039b846b611ad2beb8c6e6ac701"}, {file = "gevent-22.10.1-cp27-cp27m-win_amd64.whl", hash = "sha256:af7baec79a5f8ad1cc132d3b14edd12661c628d8094e501b089b1fe2d3df7f6e"}, @@ -6393,7 +6530,8 @@ nest-asyncio = [ {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, ] networkx = [ - {file = "networkx-2.3.zip", hash = "sha256:8311ddef63cf5c5c5e7c1d0212dd141d9a1fe3f474915281b73597ed5f1d4e3d"}, + {file = "networkx-2.8.8-py3-none-any.whl", hash = "sha256:e435dfa75b1d7195c7b8378c3859f0445cd88c6b0375c181ed66823a9ceb7524"}, + {file = "networkx-2.8.8.tar.gz", hash = "sha256:230d388117af870fce5647a3c52401fcf753e94720e6ea6b4197a5355648885e"}, ] nodeenv = [ {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, @@ -6521,6 +6659,10 @@ osmium = [ {file = "osmium-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e45b7c54ac756e9cb40e2ba68691df635804eb6aa2023088af66936a9c8e3782"}, {file = "osmium-3.4.1.tar.gz", hash = "sha256:575dad72ab169cf585b9aeefb4f5f99ac250bf7da1986992afcbf169dc70c381"}, ] +osmnx = [ + {file = "osmnx-1.2.2-py2.py3-none-any.whl", hash = "sha256:94f2a3929e857d8c0da39ae552c6da3b1a3f4bcfea6de108696bda5ee3a7689d"}, + {file = "osmnx-1.2.2.tar.gz", hash = "sha256:30924452ca02758ece3301f9fcfb1b80edf31e2be7abe7fa7e0fefddb5050408"}, +] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, @@ -7362,6 +7504,53 @@ requests-toolbelt = [ reverse-geocoder = [ {file = "reverse_geocoder-1.5.1.tar.gz", hash = "sha256:2a2e781b5f69376d922b78fe8978f1350c84fce0ddb07e02c834ecf98b57c75c"}, ] +rtree = [ + {file = "Rtree-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9855b8f11cdad99c56eb361b7b632a4fbd3d8cbe3f2081426b445f0cfb7fdca9"}, + {file = "Rtree-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:18ce7e4d04b85c48f2d364835620b3b20e38e199639746e7b12f07a2303e18ff"}, + {file = "Rtree-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784efa6b7be9e99b33613ae8495931032689441eabb6120c9b3eb91188c33794"}, + {file = "Rtree-1.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:157207191aebdacbbdbb369e698cfbfebce53bc97114e96c8af5bed3126475f1"}, + {file = "Rtree-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5fb3671a8d440c24b1dd29ec621d4345ced7185e26f02abe98e85a6629fcb50"}, + {file = "Rtree-1.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:11d16f51cf9205cd6995af36e24efe8f184270f667fb49bb69b09fc46b97e7d4"}, + {file = "Rtree-1.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6db6a0a93e41594ffc14b053f386dd414ab5a82535bbd9aedafa6ac8dc0650d8"}, + {file = "Rtree-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6e29e5eb3083ad12ac5c1ce6e37465ea3428d894d3466cc9c9e2ee4bf768e53"}, + {file = "Rtree-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:656b148589c0b5bab4a7db4d033634329f42a5feaac10ca40aceeca109d83c1f"}, + {file = "Rtree-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b2c15f9373ba314c83a8df5cb6d99b4e3af23c376c6b1317add995432dd0970"}, + {file = "Rtree-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93c5e0bf31e76b4f92a6eec3d2891e938408774c75a8ed6ac3d2c8db04a2be33"}, + {file = "Rtree-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6792de0e3c2fd3ad7e069445027603bec7a47000432f49c80246886311f4f152"}, + {file = "Rtree-1.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:004e131b570dc360a49e7f3b60e7bc6517943a54df056587964d1cb903889e7e"}, + {file = "Rtree-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:becd711fe97c2e09b1b7969e83080a3c8012bce2d30f6db879aade255fcba5c1"}, + {file = "Rtree-1.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:015df09e1bc55ddf7c88799bf1515d058cd0ee78eacf4cd443a32876d3b3a863"}, + {file = "Rtree-1.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c2973b76f61669a85e160b4ad09879c4089fc0e3f20fd99adf161ca298fe8374"}, + {file = "Rtree-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e4335e131a58952635560a003458011d97f9ea6f3c010dc24906050b42ee2c03"}, + {file = "Rtree-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:e7ca5d743f6a1dc62653dfac8ee7ce2e1ba91be7cf97916a7f60b7cbe48fb48d"}, + {file = "Rtree-1.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2ee7165e9872a026ccb868c021711eba39cedf7d1820763c9de52d5324691a92"}, + {file = "Rtree-1.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8de99f28af0f1783eefb80918959903b4b18112f6a12b48f296ecb162804e69d"}, + {file = "Rtree-1.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a94e2f4bf74bd202ea8b67ea3d7c71e763ad41f79be1d6b72aa2c8d5a8e92c4"}, + {file = "Rtree-1.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5120da3a1b96f3a7a17dd6af0afdd4e6f3cc9baa87e9ee0a272882f01f980bb"}, + {file = "Rtree-1.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7e3d5f0e7b28250afbb290ab88b49aa0f121c9714d0da2080581783690347507"}, + {file = "Rtree-1.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:296203e933b6ec0dd07f6a7456c4f1492def95b6993f20cc61c92b0fee0aecc5"}, + {file = "Rtree-1.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:77908cd7acdd519a731979ebf5baff8afd102109c2f52864c1e6ee75d3ea2d87"}, + {file = "Rtree-1.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1a213e5d385278ca7668bc5b27083f8d6e39996a9bd59b6528f3a30009dae4ed"}, + {file = "Rtree-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfa8cffec5cb9fed494c4bb335ebdb69b3c26178b0b685f67f79296c6b3d800c"}, + {file = "Rtree-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b31fd22d214160859d038da7cb2aaa27acb71efc24a7bcc75c84b5e502721549"}, + {file = "Rtree-1.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d68a81ad419d5c2ea5fecc677e6c178666c057e2c7b24100a6c48392196f1e9"}, + {file = "Rtree-1.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62f38020af47b765adc6b0bc7c4e810c6c3d1eab44ba339b592ff25a4c0dc0a7"}, + {file = "Rtree-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50b658a6707f215a0056d52e9f83a97148c0af62dea07cf29b3789a2c429e78a"}, + {file = "Rtree-1.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3573cbb0de872f54d0a0c29596a84e8ac3939c47ca3bece4a82e92775730a0d0"}, + {file = "Rtree-1.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5abe5a19d943a88bea14901970e4c53e4579fc2662404cdea6163bf4c04d49a"}, + {file = "Rtree-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e894112cef4de6c518bdea0b43eada65f12888c3645cc437c3a677aa023039f"}, + {file = "Rtree-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:582854252b8fd5c8472478af060635434931fb55edd269bac128cbf2eef43620"}, + {file = "Rtree-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b54057e8a8ad92c1d8e9eaa5cf32aad70dde454abbf9b638e9d6024520a52c02"}, + {file = "Rtree-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:698de8ce6c62e159d93b35bacf64bcf3619077b5367bc88cd2cff5e0bc36169b"}, + {file = "Rtree-1.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:273ee61783de3a1664e5f868feebf5eea4629447137751bfa4087b0f82093082"}, + {file = "Rtree-1.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16900ee02cf5c198a42b03635268a80f606aa102f3f7618b89f75023d406da1c"}, + {file = "Rtree-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ce4a6fdb63254a4c1efebe7a4f7a59b1c333c703bde4ae715d9ad88c833e10b"}, + {file = "Rtree-1.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5b20f69e040a05503b22297af223f336fe7047909b57e4b207b98292f33a229f"}, + {file = "Rtree-1.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:57128293dd625cb1f07726f32208097953e8854d70ab1fc55d6858733618b9ed"}, + {file = "Rtree-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e898d7409ab645c25e06d4e058f99271182601d70b2887aba3351bf08e09a0c6"}, + {file = "Rtree-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:ad9912faeddb1ddcec5e26b33089166d58a107af6862d8b7f1bb2b7c0002ab39"}, + {file = "Rtree-1.0.1.tar.gz", hash = "sha256:222121699c303a64065d849bf7038b1ecabc37b65c7fa340bedb38ef0e805429"}, +] s2sphere = [ {file = "s2sphere-0.2.5-py2.py3-none-any.whl", hash = "sha256:d2340c9cf458ddc9a89afd1d8048a4195ce6fa6b0095ab900d4be5271e537401"}, {file = "s2sphere-0.2.5.tar.gz", hash = "sha256:c2478c1ff7c601a59a7151a57b605435897514578fa6bdb8730721c182adbbaf"}, @@ -7539,6 +7728,50 @@ setuptools-scm = [ {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"}, {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"}, ] +shapely = [ + {file = "Shapely-1.8.5.post1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d048f93e42ba578b82758c15d8ae037d08e69d91d9872bca5a1895b118f4e2b0"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99ab0ddc05e44acabdbe657c599fdb9b2d82e86c5493bdae216c0c4018a82dee"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:99a2f0da0109e81e0c101a2b4cd8412f73f5f299e7b5b2deaf64cd2a100ac118"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6fe855e7d45685926b6ba00aaeb5eba5862611f7465775dacd527e081a8ced6d"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec14ceca36f67cb48b34d02d7f65a9acae15cd72b48e303531893ba4a960f3ea"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a2b2a65fa7f97115c1cd989fe9d6f39281ca2a8a014f1d4904c1a6e34d7f25"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-win32.whl", hash = "sha256:21776184516a16bf82a0c3d6d6a312b3cd15a4cabafc61ee01cf2714a82e8396"}, + {file = "Shapely-1.8.5.post1-cp310-cp310-win_amd64.whl", hash = "sha256:a354199219c8d836f280b88f2c5102c81bb044ccea45bd361dc38a79f3873714"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:783bad5f48e2708a0e2f695a34ed382e4162c795cb2f0368b39528ac1d6db7ed"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a23ef3882d6aa203dd3623a3d55d698f59bfbd9f8a3bfed52c2da05a7f0f8640"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab38f7b5196ace05725e407cb8cab9ff66edb8e6f7bb36a398e8f73f52a7aaa2"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d086591f744be483b34628b391d741e46f2645fe37594319e0a673cc2c26bcf"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4728666fff8cccc65a07448cae72c75a8773fea061c3f4f139c44adc429b18c3"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-win32.whl", hash = "sha256:84010db15eb364a52b74ea8804ef92a6a930dfc1981d17a369444b6ddec66efd"}, + {file = "Shapely-1.8.5.post1-cp311-cp311-win_amd64.whl", hash = "sha256:48dcfffb9e225c0481120f4bdf622131c8c95f342b00b158cdbe220edbbe20b6"}, + {file = "Shapely-1.8.5.post1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2fd15397638df291c427a53d641d3e6fd60458128029c8c4f487190473a69a91"}, + {file = "Shapely-1.8.5.post1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a74631e511153366c6dbe3229fa93f877e3c87ea8369cd00f1d38c76b0ed9ace"}, + {file = "Shapely-1.8.5.post1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:66bdac74fbd1d3458fa787191a90fa0ae610f09e2a5ec398c36f968cc0ed743f"}, + {file = "Shapely-1.8.5.post1-cp36-cp36m-win32.whl", hash = "sha256:6d388c0c1bd878ed1af4583695690aa52234b02ed35f93a1c8486ff52a555838"}, + {file = "Shapely-1.8.5.post1-cp36-cp36m-win_amd64.whl", hash = "sha256:be9423d5a3577ac2e92c7e758bd8a2b205f5e51a012177a590bc46fc51eb4834"}, + {file = "Shapely-1.8.5.post1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5d7f85c2d35d39ff53c9216bc76b7641c52326f7e09aaad1789a3611a0f812f2"}, + {file = "Shapely-1.8.5.post1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:adcf8a11b98af9375e32bff91de184f33a68dc48b9cb9becad4f132fa25cfa3c"}, + {file = "Shapely-1.8.5.post1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:753ed0e21ab108bd4282405b9b659f2e985e8502b1a72b978eaa51d3496dee19"}, + {file = "Shapely-1.8.5.post1-cp37-cp37m-win32.whl", hash = "sha256:65b21243d8f6bcd421210daf1fabb9de84de2c04353c5b026173b88d17c1a581"}, + {file = "Shapely-1.8.5.post1-cp37-cp37m-win_amd64.whl", hash = "sha256:370b574c78dc5af3a198a6da5d9b3d7c04654bd2ef7e80e80a3a0992dfb2d9cd"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:532a55ee2a6c52d23d6f7d1567c8f0473635f3b270262c44e1b0c88096827e22"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3480657460e939f45a7d359ef0e172a081f249312557fe9aa78c4fd3a362d993"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b65f5d530ba91e49ffc7c589255e878d2506a8b96ffce69d3b7c4500a9a9eaf8"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:147066da0be41b147a61f8eb805dea3b13709dbc873a431ccd7306e24d712bc0"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c2822111ddc5bcfb116e6c663e403579d0fe3f147d2a97426011a191c43a7458"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b47bb6f9369e8bf3e6dbd33e6a25a47ee02b2874792a529fe04a49bf8bc0df6"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-win32.whl", hash = "sha256:2e0a8c2e55f1be1312b51c92b06462ea89e6bb703fab4b114e7a846d941cfc40"}, + {file = "Shapely-1.8.5.post1-cp38-cp38-win_amd64.whl", hash = "sha256:0d885cb0cf670c1c834df3f371de8726efdf711f18e2a75da5cfa82843a7ab65"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0b4ee3132ee90f07d63db3aea316c4c065ed7a26231458dda0874414a09d6ba3"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:02dd5d7dc6e46515d88874134dc8fcdc65826bca93c3eecee59d1910c42c1b17"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c6a9a4a31cd6e86d0fbe8473ceed83d4fe760b19d949fb557ef668defafea0f6"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:38f0fbbcb8ca20c16451c966c1f527cc43968e121c8a048af19ed3e339a921cd"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:78fb9d929b8ee15cfd424b6c10879ce1907f24e05fb83310fc47d2cd27088e40"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89164e7a9776a19e29f01369a98529321994e2e4d852b92b7e01d4d9804c55bf"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-win32.whl", hash = "sha256:8e59817b0fe63d34baedaabba8c393c0090f061917d18fc0bcc2f621937a8f73"}, + {file = "Shapely-1.8.5.post1-cp39-cp39-win_amd64.whl", hash = "sha256:e9c30b311de2513555ab02464ebb76115d242842b29c412f5a9aa0cac57be9f6"}, + {file = "Shapely-1.8.5.post1.tar.gz", hash = "sha256:ef3be705c3eac282a28058e6c6e5503419b250f482320df2172abcbea642c831"}, +] shellingham = [ {file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"}, {file = "shellingham-1.5.0.tar.gz", hash = "sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad"}, diff --git a/pyproject.toml b/pyproject.toml index ed3a821e29..6b4b0bb5fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,7 +145,7 @@ jupyterlab = "^3.4.4" jupyterlab-vim = "^0.15.1" Markdown = "^3.4.1" msgpack-python = "^0.5.6" -networkx = "~2.3" +networkx = "~2.8" nvidia-ml-py3 = "^7.352.0" onnx2torch = "^1.5.4" onnxoptimizer = "^0.3.1" @@ -172,6 +172,7 @@ triton = "^1.1.1" Werkzeug = "^2.1.2" zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } omegaconf = "^2.3.0" +osmnx = "==1.2.2" [build-system] From e49748d571d06a65a4361dde1f2f63c7294da13a Mon Sep 17 00:00:00 2001 From: Vivek Aithal Date: Tue, 14 Feb 2023 16:20:28 -0800 Subject: [PATCH 0942/1179] Chevrolet Bolt: Non-linear torque tune (#27344) * add non linear tune * update refs * rerun tests --- selfdrive/car/gm/interface.py | 44 ++++++++++++++++++++- selfdrive/car/interfaces.py | 4 +- selfdrive/controls/lib/latcontrol_torque.py | 4 +- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 8bfc067b48..9a165cf067 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -1,12 +1,15 @@ #!/usr/bin/env python3 +import numpy as np from cereal import car from math import fabs from panda import Panda +from common.numpy_fast import interp from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR -from selfdrive.car.interfaces import CarInterfaceBase +from selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD +from selfdrive.controls.lib.drive_helpers import apply_center_deadzone ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -43,6 +46,43 @@ class CarInterface(CarInterfaceBase): else: return CarInterfaceBase.get_steer_feedforward_default + @staticmethod + def torque_from_lateral_accel_bolt(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, vego, friction_compensation): + friction_interp = interp( + apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), + [-FRICTION_THRESHOLD, FRICTION_THRESHOLD], + [-torque_params.friction, torque_params.friction] + ) + friction = friction_interp if friction_compensation else 0.0 + steer_torque = lateral_accel_value / torque_params.latAccelFactor + + # TODO: + # 1. Learn the correction factors from data + # 2. Generalize the logic to other GM torque control platforms + steer_break_pts = np.array([-1.0, -0.9, -0.75, -0.5, 0.0, 0.5, 0.75, 0.9, 1.0]) + steer_lataccel_factors = np.array([1.5, 1.15, 1.02, 1.0, 1.0, 1.0, 1.02, 1.15, 1.5]) + steer_correction_factor = np.interp( + steer_torque, + steer_break_pts, + steer_lataccel_factors + ) + + vego_break_pts = np.array([0.0, 10.0, 15.0, 20.0, 100.0]) + vego_lataccel_factors = np.array([1.5, 1.5, 1.25, 1.0, 1.0]) + vego_correction_factor = np.interp( + vego, + vego_break_pts, + vego_lataccel_factors, + ) + + return float((steer_torque + friction) / (steer_correction_factor * vego_correction_factor)) + + def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: + if self.CP.carFingerprint == CAR.BOLT_EUV: + return self.torque_from_lateral_accel_bolt + else: + return self.torque_from_lateral_accel_linear + @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "gm" @@ -176,7 +216,7 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.8 ret.centerToFront = 2.15 # measured tire_stiffness_factor = 1.0 - ret.steerActuatorDelay = 0.2 + ret.steerActuatorDelay = 0.12 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.SILVERADO: diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 249818369c..f1e2081d05 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,7 +18,7 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel ButtonType = car.CarState.ButtonEvent.Type GearShifter = car.CarState.GearShifter EventName = car.CarEvent.EventName -TorqueFromLateralAccelCallbackType = Callable[[float, car.CarParams.LateralTorqueTuning, float, float, bool], float] +TorqueFromLateralAccelCallbackType = Callable[[float, car.CarParams.LateralTorqueTuning, float, float, float, bool], float] MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS ACCEL_MAX = 2.0 @@ -131,7 +131,7 @@ class CarInterfaceBase(ABC): return self.get_steer_feedforward_default @staticmethod - def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, friction_compensation): + def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, vego, friction_compensation): # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) friction_interp = interp( apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 2f56094379..9129693e5a 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -64,10 +64,10 @@ class LatControlTorque(LatControl): error = setpoint - measurement gravity_adjusted_lateral_accel = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY pid_log.error = self.torque_from_lateral_accel(error, self.torque_params, error, - lateral_accel_deadzone, friction_compensation=False) + lateral_accel_deadzone, CS.vEgo, friction_compensation=False) ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params, desired_lateral_accel - actual_lateral_accel, - lateral_accel_deadzone, friction_compensation=True) + lateral_accel_deadzone, CS.vEgo, friction_compensation=True) freeze_integrator = steer_limited or CS.steeringPressed or CS.vEgo < 5 output_torque = self.pid.update(pid_log.error, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 85c7d8e80b..ed1875dcbe 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f4efbb65a7eb9a8f4e23492372e707674f80114e \ No newline at end of file +3e53ce81f1ce26409fdc4479e650ef5626130876 \ No newline at end of file From f29e19cf4238199eec142f9c7eab5936874e04de Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 14 Feb 2023 16:59:20 -0800 Subject: [PATCH 0943/1179] FPv2: log responses from data collection queries (#27345) * log responses from logging/debugging queries * don't add logging FW to FW dict for fingerprinting * flip? * fine before * log if extra in debug ecus * clean up * test extra ecus too * Revert "test extra ecus too" This reverts commit 8f7867844db95f48631348551551148bf504e37b. * bump to master --- cereal | 2 +- selfdrive/car/fw_query_definitions.py | 2 ++ selfdrive/car/fw_versions.py | 17 +++++++++++------ selfdrive/car/honda/values.py | 2 ++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cereal b/cereal index fa3e77b7c8..162a26ca2d 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit fa3e77b7c8eee8752f19427b34adcb1ae5c70ec5 +Subproject commit 162a26ca2d7e5bc9a42bb5ea11e98194f722027b diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index a1695733fa..2ee0e9b4c6 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -57,6 +57,8 @@ class Request: whitelist_ecus: List[int] = field(default_factory=list) rx_offset: int = 0x8 bus: int = 1 + # FW responses from these queries will not be used for fingerprinting + logging: bool = False @dataclass diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 0db260abbd..8bf4b74e0f 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -29,10 +29,9 @@ def chunks(l, n=128): def build_fw_dict(fw_versions, filter_brand=None): fw_versions_dict = defaultdict(set) for fw in fw_versions: - if filter_brand is None or fw.brand == filter_brand: - addr = fw.address + if (filter_brand is None or fw.brand == filter_brand) and not fw.logging: sub_addr = fw.subAddress if fw.subAddress != 0 else None - fw_versions_dict[(addr, sub_addr)].add(fw.fwVersion) + fw_versions_dict[(fw.address, sub_addr)].add(fw.fwVersion) return dict(fw_versions_dict) @@ -232,15 +231,19 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # ECUs using a subaddress need be queried one by one, the rest can be done in parallel addrs = [] parallel_addrs = [] + logging_addrs = [] ecu_types = {} for brand, brand_versions in versions.items(): - for c in brand_versions.values(): - for ecu_type, addr, sub_addr in c.keys(): + for candidate, ecu in brand_versions.items(): + for ecu_type, addr, sub_addr in ecu.keys(): a = (brand, addr, sub_addr) if a not in ecu_types: ecu_types[a] = ecu_type + if a not in logging_addrs and candidate == "debug": + logging_addrs.append(a) + if sub_addr is None: if a not in parallel_addrs: parallel_addrs.append(a) @@ -269,13 +272,15 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, for (tx_addr, sub_addr), version in query.get_data(timeout).items(): f = car.CarParams.CarFw.new_message() - f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown) + ecu_key = (brand, tx_addr, sub_addr) + f.ecu = ecu_types.get(ecu_key, Ecu.unknown) f.fwVersion = version f.address = tx_addr f.responseAddress = uds.get_rx_addr_for_tx_addr(tx_addr, r.rx_offset) f.request = r.request f.brand = brand f.bus = r.bus + f.logging = r.logging or ecu_key in logging_addrs if sub_addr is not None: f.subAddress = sub_addr diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 3d1c006aaa..a4ddd84ead 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -171,12 +171,14 @@ FW_QUERY_CONFIG = FwQueryConfig( [HONDA_VERSION_REQUEST], [HONDA_VERSION_RESPONSE], bus=1, + logging=True ), # Query Nidec PT bus from camera for data collection Request( [StdQueries.UDS_VERSION_REQUEST], [StdQueries.UDS_VERSION_RESPONSE], bus=0, + logging=True ), ], extra_ecus=[ From c4b84783a003479bc105e2f7a93d5e71c2e1c38f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 14 Feb 2023 17:55:41 -0800 Subject: [PATCH 0944/1179] Honda Bosch: gather available ECUs from camera (#27180) * add flag * actually use in fw_versions.py * simpler * not here * Comment * better name * add param and block * keys keys * block * with a value with a value * add query for bosch PT bus * different name * fix * . * fix test fix test * add cloulogs * mark as logging --- common/params.cc | 1 + selfdrive/boardd/boardd.cc | 2 ++ selfdrive/car/car_helpers.py | 1 - selfdrive/car/fw_query_definitions.py | 2 ++ selfdrive/car/fw_versions.py | 22 ++++++++++++++++++++-- selfdrive/car/honda/values.py | 14 +++++++++++--- selfdrive/controls/tests/test_startup.py | 1 + 7 files changed, 37 insertions(+), 6 deletions(-) diff --git a/common/params.cc b/common/params.cc index db5e5e700d..5e3361a70f 100644 --- a/common/params.cc +++ b/common/params.cc @@ -155,6 +155,7 @@ std::unordered_map keys = { {"NavSettingTime24h", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT}, {"NavdRender", PERSISTENT}, + {"ObdMultiplexingDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"OpenpilotEnabledToggle", PERSISTENT}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"PandaSignatures", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 0473d3488c..5d885c2c79 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -137,6 +137,8 @@ bool safety_setter_thread(std::vector pandas) { panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); } + p.putBool("ObdMultiplexingDisabled", true); + std::string params; LOGW("waiting for params to set safety model"); while (true) { diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 4ccce979d3..ae19fd6248 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -116,7 +116,6 @@ def fingerprint(logcan, sendcan, num_pandas): params = Params() params.put("CarVin", vin) - params.put_bool("FirmwareObdQueryDone", True) finger = gen_empty_fingerprint() candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index 2ee0e9b4c6..dd3b19f6de 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -59,6 +59,8 @@ class Request: bus: int = 1 # FW responses from these queries will not be used for fingerprinting logging: bool = False + # These requests are done once OBD multiplexing is disabled, after all others + non_obd: bool = False @dataclass diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 8bf4b74e0f..23b0fcc6d1 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -5,6 +5,7 @@ from tqdm import tqdm import panda.python.uds as uds from cereal import car +from common.params import Params from selfdrive.car.ecu_addrs import get_ecu_addrs from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.fingerprints import FW_VERSIONS @@ -89,7 +90,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None): return set() -def match_fw_to_car_exact(fw_versions_dict): +def match_fw_to_car_exact(fw_versions_dict) -> Set[str]: """Do an exact FW match. Returns all cars that match the given FW versions for a list of "essential" ECUs. If an ECU is not considered essential the FW version can be missing to get a fingerprint, but if it's present it @@ -202,6 +203,7 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand all_car_fw = [] brand_matches = get_brand_ecu_matches(ecu_rx_addrs) + matched_brand: Optional[str] = None 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, num_pandas=num_pandas, debug=debug, progress=progress) @@ -209,12 +211,25 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand # Try to match using FW returned from this brand only matches = match_fw_to_car_exact(build_fw_dict(car_fw)) if len(matches) == 1: + matched_brand = brand break + # Do non-OBD queries for matched brand, or all if no match is found + params = Params() + params.put_bool("FirmwareObdQueryDone", True) + + cloudlog.warning("Waiting for OBD multiplexing to be disabled") + params.get_bool("ObdMultiplexingDisabled", block=True) + cloudlog.warning("OBD multiplexing disabled") + + for brand in FW_QUERY_CONFIGS.keys(): + if brand == matched_brand or matched_brand is None: + all_car_fw.extend(get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, obd_multiplexed=False, debug=debug, progress=progress)) + return all_car_fw -def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, debug=False, progress=False): +def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, obd_multiplexed=True, debug=False, progress=False): versions = VERSIONS.copy() # Each brand can define extra ECUs to query for data collection @@ -262,6 +277,9 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue + # Or if request is not designated for current multiplexing mode + elif r.non_obd == obd_multiplexed: + continue try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index a4ddd84ead..c085c3fe80 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -171,14 +171,22 @@ FW_QUERY_CONFIG = FwQueryConfig( [HONDA_VERSION_REQUEST], [HONDA_VERSION_RESPONSE], bus=1, - logging=True + logging=True, ), - # Query Nidec PT bus from camera for data collection + # Nidec PT bus Request( [StdQueries.UDS_VERSION_REQUEST], [StdQueries.UDS_VERSION_RESPONSE], bus=0, - logging=True + logging=True, + ), + # Bosch PT bus + Request( + [StdQueries.UDS_VERSION_REQUEST], + [StdQueries.UDS_VERSION_RESPONSE], + bus=1, + logging=True, + non_obd=True, ), ], extra_ecus=[ diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index ba2d2f5c02..92fc2468bb 100755 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -72,6 +72,7 @@ class TestStartup(unittest.TestCase): params.clear_all() params.put_bool("Passive", False) params.put_bool("OpenpilotEnabledToggle", True) + params.put_bool("ObdMultiplexingDisabled", True) # Build capnn version of FW array if fw_versions is not None: From 8c099dd4e5adf040f7f454714cf729725bee7f91 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 14 Feb 2023 22:06:23 -0800 Subject: [PATCH 0945/1179] GM: cleanup torque feedforward function (#27347) no numpy --- selfdrive/car/gm/interface.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 9a165cf067..104cb8fbd8 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import numpy as np from cereal import car from math import fabs from panda import Panda @@ -59,23 +58,23 @@ class CarInterface(CarInterfaceBase): # TODO: # 1. Learn the correction factors from data # 2. Generalize the logic to other GM torque control platforms - steer_break_pts = np.array([-1.0, -0.9, -0.75, -0.5, 0.0, 0.5, 0.75, 0.9, 1.0]) - steer_lataccel_factors = np.array([1.5, 1.15, 1.02, 1.0, 1.0, 1.0, 1.02, 1.15, 1.5]) - steer_correction_factor = np.interp( + steer_break_pts = [-1.0, -0.9, -0.75, -0.5, 0.0, 0.5, 0.75, 0.9, 1.0] + steer_lataccel_factors = [1.5, 1.15, 1.02, 1.0, 1.0, 1.0, 1.02, 1.15, 1.5] + steer_correction_factor = interp( steer_torque, steer_break_pts, steer_lataccel_factors ) - vego_break_pts = np.array([0.0, 10.0, 15.0, 20.0, 100.0]) - vego_lataccel_factors = np.array([1.5, 1.5, 1.25, 1.0, 1.0]) - vego_correction_factor = np.interp( + vego_break_pts = [0.0, 10.0, 15.0, 20.0, 100.0] + vego_lataccel_factors = [1.5, 1.5, 1.25, 1.0, 1.0] + vego_correction_factor = interp( vego, vego_break_pts, vego_lataccel_factors, ) - return float((steer_torque + friction) / (steer_correction_factor * vego_correction_factor)) + return (steer_torque + friction) / (steer_correction_factor * vego_correction_factor) def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: if self.CP.carFingerprint == CAR.BOLT_EUV: From d4c5b8d6f4ba7606f6823ce523c66a7e270b924b Mon Sep 17 00:00:00 2001 From: Rob Chouinard Date: Wed, 15 Feb 2023 01:24:13 -0500 Subject: [PATCH 0946/1179] Allow Honda Nidec vehicles with comma pedal to drive at max speed. (#26902) Without this Honda Nidec vehicles with the comma pedal will drive around 2 mph under the max speed. --- selfdrive/car/honda/interface.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 66c0ce4275..d3cf9fa891 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -21,6 +21,8 @@ class CarInterface(CarInterfaceBase): def get_pid_accel_limits(CP, current_speed, cruise_speed): if CP.carFingerprint in HONDA_BOSCH: return CarControllerParams.BOSCH_ACCEL_MIN, CarControllerParams.BOSCH_ACCEL_MAX + elif CP.enableGasInterceptor: + return CarControllerParams.NIDEC_ACCEL_MIN, CarControllerParams.NIDEC_ACCEL_MAX else: # NIDECs don't allow acceleration near cruise_speed, # so limit limits of pid to prevent windup From e4d0ee8716c382e90fd725998216a2f7deafc592 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 16 Feb 2023 02:59:57 +0800 Subject: [PATCH 0947/1179] cabana: cleanup code for charts (#27350) --- tools/cabana/chartswidget.cc | 123 ++++++++++++++--------------------- tools/cabana/chartswidget.h | 14 ++-- 2 files changed, 54 insertions(+), 83 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index ec54d7f06a..3f12c55ffc 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -11,9 +11,11 @@ #include #include #include +#include #include #include +const int MAX_COLUMN_COUNT = 4; // ChartsWidget ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { @@ -23,14 +25,17 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QToolBar *toolbar = new QToolBar(tr("Charts"), this); toolbar->setIconSize({16, 16}); - QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), ""); - new_plot_btn->setToolTip(tr("New Plot")); + QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), tr("New Plot")); toolbar->addWidget(title_label = new QLabel()); title_label->setContentsMargins(0, 0, 12, 0); - columns_cb = new QComboBox(this); - columns_cb->addItems({"1", "2", "3", "4"}); - columns_lb_action = toolbar->addWidget(new QLabel(tr("Columns:"))); - columns_cb_action = toolbar->addWidget(columns_cb); + + QMenu *menu = new QMenu(this); + for (int i = 0; i < MAX_COLUMN_COUNT; ++i) { + menu->addAction(tr("%1").arg(i + 1), [=]() { setColumnCount(i + 1); }); + } + columns_action = toolbar->addAction(""); + columns_action->setMenu(menu); + qobject_cast(toolbar->widgetForAction(columns_action))->setPopupMode(QToolButton::InstantPopup); QLabel *stretch_label = new QLabel(this); stretch_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -44,13 +49,10 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { range_slider->setPageStep(60); // 1 min range_slider_action = toolbar->addWidget(range_slider); - reset_zoom_action = toolbar->addWidget(reset_zoom_btn = new QToolButton()); - reset_zoom_btn->setIcon(utils::icon("zoom-out")); - reset_zoom_btn->setToolTip(tr("Reset zoom")); - reset_zoom_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + reset_zoom_action = toolbar->addAction(utils::icon("zoom-out"), tr("Reset Zoom")); + qobject_cast(toolbar->widgetForAction(reset_zoom_action))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - remove_all_btn = toolbar->addAction(utils::icon("x"), ""); - remove_all_btn->setToolTip(tr("Remove all charts")); + remove_all_btn = toolbar->addAction(utils::icon("x"), tr("Remove all charts")); dock_btn = toolbar->addAction(""); main_layout->addWidget(toolbar); @@ -73,10 +75,9 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { // init settings use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > QApplication::style()->standardPalette().color(QPalette::Background).value(); - column_count = std::clamp(settings.chart_column_count, 1, columns_cb->count()); + column_count = std::clamp(settings.chart_column_count, 1, MAX_COLUMN_COUNT); max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); display_range = {0, max_chart_range}; - columns_cb->setCurrentIndex(column_count - 1); range_slider->setValue(max_chart_range); updateToolBar(); @@ -86,8 +87,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange); QObject::connect(new_plot_btn, &QAction::triggered, this, &ChartsWidget::newChart); QObject::connect(remove_all_btn, &QAction::triggered, this, &ChartsWidget::removeAll); - QObject::connect(reset_zoom_btn, &QToolButton::clicked, this, &ChartsWidget::zoomReset); - QObject::connect(columns_cb, SIGNAL(activated(int)), SLOT(setColumnCount(int))); + QObject::connect(reset_zoom_action, &QAction::triggered, this, &ChartsWidget::zoomReset); QObject::connect(&settings, &Settings::changed, this, &ChartsWidget::settingChanged); QObject::connect(dock_btn, &QAction::triggered, [this]() { emit dock(!docking); @@ -162,11 +162,12 @@ void ChartsWidget::setMaxChartRange(int value) { void ChartsWidget::updateToolBar() { title_label->setText(tr("Charts: %1").arg(charts.size())); + columns_action->setText(tr("Column: %1").arg(column_count)); range_lb->setText(QString("Range: %1:%2 ").arg(max_chart_range / 60, 2, 10, QLatin1Char('0')).arg(max_chart_range % 60, 2, 10, QLatin1Char('0'))); range_lb_action->setVisible(!is_zoomed); range_slider_action->setVisible(!is_zoomed); reset_zoom_action->setVisible(is_zoomed); - reset_zoom_btn->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : ""); + reset_zoom_action->setText(is_zoomed ? tr("Zoomin: %1-%2").arg(zoomed_range.first, 0, 'f', 1).arg(zoomed_range.second, 0, 'f', 1) : ""); remove_all_btn->setEnabled(!charts.isEmpty()); dock_btn->setIcon(utils::icon(docking ? "arrow-up-right-square" : "arrow-down-left-square")); dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts")); @@ -211,29 +212,29 @@ void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bo chart->addSeries(id, sig); updateState(); } else if (!show && chart) { - chart->removeSeries(id, sig); + chart->removeIf([&](auto &s) { return s.msg_id == id && s.sig == sig; }); } updateToolBar(); setUpdatesEnabled(true); } void ChartsWidget::setColumnCount(int n) { - n = std::clamp(n + 1, 1, columns_cb->count()); + n = std::clamp(n, 1, MAX_COLUMN_COUNT); if (column_count != n) { column_count = settings.chart_column_count = n; + updateToolBar(); updateLayout(); } } void ChartsWidget::updateLayout() { - int n = columns_cb->count(); + int n = MAX_COLUMN_COUNT; for (; n > 1; --n) { if ((n * CHART_MIN_WIDTH + (n - 1) * charts_layout->spacing()) < charts_layout->geometry().width()) break; } bool show_column_cb = n > 1; - columns_lb_action->setVisible(show_column_cb); - columns_cb_action->setVisible(show_column_cb); + columns_action->setVisible(show_column_cb); n = std::min(column_count, n); if (charts.size() != charts_layout->count() || n != current_column_count) { @@ -305,7 +306,6 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; - QChart *chart = new QChart(); chart->setBackgroundVisible(false); axis_x = new QValueAxis(this); @@ -367,9 +367,6 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { if (hasSeries(msg_id, sig)) return; QXYSeries *series = createSeries(series_type, getColor(sig)); - 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(); @@ -378,30 +375,29 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) { emit seriesAdded(msg_id, 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 = removeItem(it); - } -} - bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); } -QList::iterator ChartView::removeItem(const QList::iterator &it) { - chart()->removeSeries(it->series); - it->series->deleteLater(); - QString msg_id = it->msg_id; - const Signal *sig = it->sig; - auto ret = sigs.erase(it); - emit seriesRemoved(msg_id, sig); - if (!sigs.isEmpty()) { +void ChartView::removeIf(std::function predicate) { + int prev_size = sigs.size(); + for (auto it = sigs.begin(); it != sigs.end(); /**/) { + if (predicate(*it)) { + chart()->removeSeries(it->series); + it->series->deleteLater(); + auto msg_id = it->msg_id; + auto sig = it->sig; + it = sigs.erase(it); + emit seriesRemoved(msg_id, sig); + } else { + ++it; + } + } + if (sigs.empty()) { + emit remove(); + } else if (sigs.size() != prev_size) { updateAxisY(); - } else { - emit remove(); } - return ret; } void ChartView::signalUpdated(const Signal *sig) { @@ -412,23 +408,11 @@ void ChartView::signalUpdated(const Signal *sig) { } } -void ChartView::signalRemoved(const Signal *sig) { - for (auto it = sigs.begin(); it != sigs.end(); /**/) { - it = (it->sig == sig) ? removeItem(it) : ++it; - } -} - void ChartView::msgUpdated(uint32_t address) { if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; })) updateTitle(); } -void ChartView::msgRemoved(uint32_t address) { - for (auto it = sigs.begin(); it != sigs.end(); /**/) { - it = (it->address == address) ? removeItem(it) : ++it; - } -} - void ChartView::manageSeries() { SeriesSelector dlg(tr("Mange Chart"), this); for (auto &s : sigs) { @@ -436,19 +420,12 @@ void ChartView::manageSeries() { } if (dlg.exec() == QDialog::Accepted) { auto items = dlg.seletedItems(); - if (items.isEmpty()) { - emit remove(); - } else { - for (auto s : items) { - addSeries(s->msg_id, s->sig); - } - for (auto it = sigs.begin(); it != sigs.end(); /**/) { - bool exists = std::any_of(items.cbegin(), items.cend(), [&](auto &s) { - return s->msg_id == it->msg_id && s->sig == it->sig; - }); - it = exists ? ++it : removeItem(it); - } + for (auto s : items) { + addSeries(s->msg_id, s->sig); } + removeIf([&](auto &s) { + return std::none_of(items.cbegin(), items.cend(), [&](auto &it) { return s.msg_id == it->msg_id && s.sig == it->sig; }); + }); } } @@ -503,7 +480,7 @@ void ChartView::updateSeriesPoints() { int pixels_per_point = width() / num_points; if (series_type == QAbstractSeries::SeriesTypeScatter) { - ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 1, 8)); + ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8)); } else { s.series->setPointsVisible(pixels_per_point > 20); } @@ -698,7 +675,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { text_list.push_front(QString::number(chart()->mapToValue(pt).x(), 'f', 3)); QPointF tooltip_pt(pt.x() + 12, plot_area.top() - 20); QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), pt.isNull() ? "" : text_list.join("
"), this, plot_area.toRect()); - scene()->update(); + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } else { QToolTip::hideText(); } @@ -795,6 +772,9 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor colo pen.setWidth(2.0 * qApp->devicePixelRatio()); series->setPen(pen); #endif + chart()->addSeries(series); + series->attachAxis(axis_x); + series->attachAxis(axis_y); return series; } @@ -809,9 +789,6 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { } for (auto &s : sigs) { auto series = createSeries(series_type, getColor(s.sig)); - chart()->addSeries(series); - series->attachAxis(axis_x); - series->attachAxis(axis_y); series->replace(s.vals); s.series = series; } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 25949dd654..58ae7e3b4c 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -8,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -28,7 +26,6 @@ class ChartView : public QChartView { public: ChartView(QWidget *parent = nullptr); 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, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); @@ -54,15 +51,14 @@ signals: void axisYLabelWidthChanged(int w); private slots: - void msgRemoved(uint32_t address); void msgUpdated(uint32_t address); void signalUpdated(const Signal *sig); - void signalRemoved(const Signal *sig); void manageSeries(); void handleMarkerClicked(); + void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.address == address; }); } + void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: - QList::iterator removeItem(const QList::iterator &it); void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; @@ -78,6 +74,7 @@ private: qreal niceNumber(qreal x, bool ceiling); QXYSeries *createSeries(QAbstractSeries::SeriesType type, QColor color); void updateSeriesPoints(); + void removeIf(std::function predicate); int y_label_width = 0; int align_to = 0; @@ -139,7 +136,6 @@ private: bool docking = true; QAction *dock_btn; QAction *reset_zoom_action; - QToolButton *reset_zoom_btn; QAction *remove_all_btn; QGridLayout *charts_layout; QList charts; @@ -148,9 +144,7 @@ private: std::pair display_range; std::pair zoomed_range; bool use_dark_theme = false; - QAction *columns_lb_action; - QAction *columns_cb_action; - QComboBox *columns_cb; + QAction *columns_action; int column_count = 1; int current_column_count = 0; }; From 00513f10011ad6ad693fbbc9b4b5dc7df36f9a79 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 15 Feb 2023 11:28:47 -0800 Subject: [PATCH 0948/1179] locationd: adjust GPS alive check for QCOM GPS (#27339) * locationd: adjust GPS alive check for QCOM GPS * update refs * update refs --- selfdrive/locationd/locationd.cc | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc index 8941b50248..307626506a 100755 --- a/selfdrive/locationd/locationd.cc +++ b/selfdrive/locationd/locationd.cc @@ -619,7 +619,7 @@ kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_build } bool Localizer::is_gps_ok() { - return (this->kf->get_filter_time() - this->last_gps_msg) < 1.0; + return (this->kf->get_filter_time() - this->last_gps_msg) < 2.0; } bool Localizer::critical_services_valid(std::map critical_services) { diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index ed1875dcbe..85eada072e 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3e53ce81f1ce26409fdc4479e650ef5626130876 \ No newline at end of file +c7bb411b37ab7ff573402b6e4fa24f796cbb2ee8 \ No newline at end of file From 5078c918056c189a3ec84bc63231fbae75c57eda Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 15 Feb 2023 21:39:03 +0100 Subject: [PATCH 0949/1179] cabana: refactor message id from QString to struct (#27352) * cabana: refactor message id from QString to struct * fix tabbar * fix findsimilarbits * optimize hash function * cleanup sorting * use in updateLastMsgsTo --- tools/cabana/binaryview.cc | 12 +++--- tools/cabana/binaryview.h | 8 ++-- tools/cabana/chartswidget.cc | 27 +++++++------- tools/cabana/chartswidget.h | 28 +++++++------- tools/cabana/commands.cc | 18 ++++----- tools/cabana/commands.h | 20 +++++----- tools/cabana/dbcmanager.cc | 34 ++++++++--------- tools/cabana/dbcmanager.h | 44 ++++++++++++++++++---- tools/cabana/detailwidget.cc | 51 +++++++++++++++----------- tools/cabana/detailwidget.h | 9 +++-- tools/cabana/historylog.cc | 17 ++++----- tools/cabana/historylog.h | 8 ++-- tools/cabana/messageswidget.cc | 22 +++++------ tools/cabana/messageswidget.h | 14 ++++--- tools/cabana/signaledit.cc | 10 ++--- tools/cabana/signaledit.h | 12 +++--- tools/cabana/streams/abstractstream.cc | 19 +++++----- tools/cabana/streams/abstractstream.h | 17 +++++---- tools/cabana/tools/findsimilarbits.cc | 8 ++-- tools/cabana/tools/findsimilarbits.h | 4 +- 20 files changed, 209 insertions(+), 173 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 16df867d56..9085bf310a 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -94,7 +94,7 @@ void BinaryView::addShortcuts() { QObject::connect(shortcut_plot_c, &QShortcut::activated, shortcut_plot, &QShortcut::activated); QObject::connect(shortcut_plot, &QShortcut::activated, [=]{ if (hovered_sig != nullptr) { - emit showChart(model->msg_id, hovered_sig, true, false); + emit showChart(*model->msg_id, hovered_sig, true, false); } }); } @@ -189,14 +189,14 @@ void BinaryView::leaveEvent(QEvent *event) { QTableView::leaveEvent(event); } -void BinaryView::setMessage(const QString &message_id) { +void BinaryView::setMessage(const MessageId &message_id) { model->msg_id = message_id; verticalScrollBar()->setValue(0); refresh(); } void BinaryView::refresh() { - if (model->msg_id.isEmpty()) return; + if (!model->msg_id) return; clearSelection(); anchor_index = QModelIndex(); @@ -231,7 +231,7 @@ std::tuple BinaryView::getSelection(QModelIndex index) { void BinaryViewModel::refresh() { beginResetModel(); items.clear(); - if ((dbc_msg = dbc()->msg(msg_id))) { + if ((dbc_msg = dbc()->msg(*msg_id))) { row_count = dbc_msg->size; items.resize(row_count * column_count); for (auto sig : dbc_msg->getSignals()) { @@ -250,7 +250,7 @@ void BinaryViewModel::refresh() { } } } else { - row_count = can->lastMessage(msg_id).dat.size(); + row_count = can->lastMessage(*msg_id).dat.size(); items.resize(row_count * column_count); } endResetModel(); @@ -259,7 +259,7 @@ void BinaryViewModel::refresh() { void BinaryViewModel::updateState() { auto prev_items = items; - const auto &last_msg = can->lastMessage(msg_id); + const auto &last_msg = can->lastMessage(*msg_id); const auto &binary = last_msg.dat; // data size may changed. diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 7cf9a8081c..6743b6cfac 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -46,7 +48,7 @@ public: }; std::vector items; - QString msg_id; + std::optional msg_id; const DBCMsg *dbc_msg = nullptr; int row_count = 0; const int column_count = 9; @@ -57,7 +59,7 @@ class BinaryView : public QTableView { public: BinaryView(QWidget *parent = nullptr); - void setMessage(const QString &message_id); + void setMessage(const MessageId &message_id); void highlight(const Signal *sig); QSet getOverlappingSignals() const; inline void updateState() { model->updateState(); } @@ -70,7 +72,7 @@ signals: void resizeSignal(const Signal *sig, int from, int size); void removeSignal(const Signal *sig); void editSignal(const Signal *origin_s, Signal &s); - void showChart(const QString &name, const Signal *sig, bool show, bool merge); + void showChart(const MessageId &id, const Signal *sig, bool show, bool merge); private: void addShortcuts(); diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 3f12c55ffc..9a085ec732 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -181,7 +181,7 @@ void ChartsWidget::settingChanged() { } } -ChartView *ChartsWidget::findChart(const QString &id, const Signal *sig) { +ChartView *ChartsWidget::findChart(const MessageId &id, const Signal *sig) { for (auto c : charts) if (c->hasSeries(id, sig)) return c; return nullptr; @@ -204,7 +204,7 @@ ChartView *ChartsWidget::createChart() { return chart; } -void ChartsWidget::showChart(const QString &id, const Signal *sig, bool show, bool merge) { +void ChartsWidget::showChart(const MessageId &id, const Signal *sig, bool show, bool merge) { setUpdatesEnabled(false); ChartView *chart = findChart(id, sig); if (show && !chart) { @@ -363,19 +363,18 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); } -void ChartView::addSeries(const QString &msg_id, const Signal *sig) { +void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) { if (hasSeries(msg_id, sig)) return; QXYSeries *series = createSeries(series_type, getColor(sig)); - auto [source, address] = DBCManager::parseId(msg_id); - sigs.push_back({.msg_id = msg_id, .address = address, .source = source, .sig = sig, .series = series}); + sigs.push_back({.msg_id = msg_id, .sig = sig, .series = series}); updateTitle(); updateSeries(sig); updateSeriesPoints(); emit seriesAdded(msg_id, sig); } -bool ChartView::hasSeries(const QString &msg_id, const Signal *sig) const { +bool ChartView::hasSeries(const MessageId &msg_id, const Signal *sig) const { return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); } @@ -409,7 +408,7 @@ void ChartView::signalUpdated(const Signal *sig) { } void ChartView::msgUpdated(uint32_t address) { - if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.address == address; })) + if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.msg_id.address == address; })) updateTitle(); } @@ -455,7 +454,7 @@ void ChartView::updateTitle() { } for (auto &s : sigs) { auto decoration = s.series->isVisible() ? "none" : "line-through"; - s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id)); + s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id.toString())); } } @@ -517,7 +516,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even for (auto it = chunk.first; it != chunk.second; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - if (s.address == c.getAddress() && s.source == c.getSrc()) { + if (s.msg_id.address == c.getAddress() && s.msg_id.source == c.getSrc()) { 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 @@ -847,7 +846,7 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) { if (auto m = dbc()->msg(it.key())) { - msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key()), it.key()); + msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key().toString()), QVariant::fromValue(it.key())); } } msgs_combo->model()->sort(0); @@ -872,7 +871,7 @@ void SeriesSelector::add(QListWidgetItem *item) { void SeriesSelector::remove(QListWidgetItem *item) { auto it = (ListItem *)item; - if (it->msg_id == msgs_combo->currentData().toString()) { + if (it->msg_id == msgs_combo->currentData().value()) { addItemToList(available_list, it->msg_id, it->sig); } delete item; @@ -881,7 +880,7 @@ void SeriesSelector::remove(QListWidgetItem *item) { void SeriesSelector::updateAvailableList(int index) { if (index == -1) return; available_list->clear(); - QString msg_id = msgs_combo->itemData(index).toString(); + MessageId msg_id = msgs_combo->itemData(index).value(); auto selected_items = seletedItems(); for (auto &[name, s] : dbc()->msg(msg_id)->sigs) { bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); @@ -891,9 +890,9 @@ void SeriesSelector::updateAvailableList(int index) { } } -void SeriesSelector::addItemToList(QListWidget *parent, const QString id, const Signal *sig, bool show_msg_name) { +void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name) { QString text = QString(" %1").arg(getColor(sig).name(), sig->name.c_str()); - if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id); + if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id.toString()); QLabel *label = new QLabel(text); label->setContentsMargins(5, 0, 5, 0); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 58ae7e3b4c..7569155d39 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -25,17 +25,15 @@ class ChartView : public QChartView { public: ChartView(QWidget *parent = nullptr); - void addSeries(const QString &msg_id, const Signal *sig); - bool hasSeries(const QString &msg_id, const Signal *sig) const; + void addSeries(const MessageId &msg_id, const Signal *sig); + bool hasSeries(const MessageId &msg_id, const Signal *sig) const; void updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); void setSeriesType(QAbstractSeries::SeriesType type); void updatePlotArea(int left); struct SigItem { - QString msg_id; - uint8_t source = 0; - uint32_t address = 0; + MessageId msg_id; const Signal *sig = nullptr; QXYSeries *series = nullptr; QVector vals; @@ -43,8 +41,8 @@ public: }; signals: - void seriesRemoved(const QString &id, const Signal *sig); - void seriesAdded(const QString &id, const Signal *sig); + void seriesRemoved(const MessageId &id, const Signal *sig); + void seriesAdded(const MessageId &id, const Signal *sig); void zoomIn(double min, double max); void zoomReset(); void remove(); @@ -55,7 +53,7 @@ private slots: void signalUpdated(const Signal *sig); void manageSeries(); void handleMarkerClicked(); - void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.address == address; }); } + void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.msg_id.address == address; }); } void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: @@ -99,8 +97,8 @@ class ChartsWidget : public QWidget { public: ChartsWidget(QWidget *parent = nullptr); - void showChart(const QString &id, const Signal *sig, bool show, bool merge); - inline bool hasSignal(const QString &id, const Signal *sig) { return findChart(id, sig) != nullptr; } + void showChart(const MessageId &id, const Signal *sig, bool show, bool merge); + inline bool hasSignal(const MessageId &id, const Signal *sig) { return findChart(id, sig) != nullptr; } public slots: void setColumnCount(int n); @@ -126,7 +124,7 @@ private: void updateLayout(); void settingChanged(); bool eventFilter(QObject *obj, QEvent *event) override; - ChartView *findChart(const QString &id, const Signal *sig); + ChartView *findChart(const MessageId &id, const Signal *sig); QLabel *title_label; QLabel *range_lb; @@ -152,18 +150,18 @@ private: class SeriesSelector : public QDialog { public: struct ListItem : public QListWidgetItem { - ListItem(const QString &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {} - QString msg_id; + ListItem(const MessageId &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {} + MessageId msg_id; const Signal *sig; }; SeriesSelector(QString title, QWidget *parent); QList seletedItems(); - inline void addSelected(const QString &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); } + inline void addSelected(const MessageId &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); } private: void updateAvailableList(int index); - void addItemToList(QListWidget *parent, const QString id, const Signal *sig, bool show_msg_name = false); + void addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name = false); void add(QListWidgetItem *item); void remove(QListWidgetItem *item); diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index e4bf999062..b03f46b5d2 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -4,13 +4,13 @@ // EditMsgCommand -EditMsgCommand::EditMsgCommand(const QString &id, const QString &title, int size, QUndoCommand *parent) +EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &title, int size, QUndoCommand *parent) : id(id), new_title(title), new_size(size), QUndoCommand(parent) { if (auto msg = dbc()->msg(id)) { old_title = msg->name; old_size = msg->size; } - setText(QObject::tr("Edit message %1:%2").arg(DBCManager::parseId(id).second).arg(title)); + setText(QObject::tr("Edit message %1:%2").arg(id.address).arg(title)); } void EditMsgCommand::undo() { @@ -26,10 +26,10 @@ void EditMsgCommand::redo() { // RemoveMsgCommand -RemoveMsgCommand::RemoveMsgCommand(const QString &id, QUndoCommand *parent) : id(id), QUndoCommand(parent) { +RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : id(id), QUndoCommand(parent) { if (auto msg = dbc()->msg(id)) { message = *msg; - setText(QObject::tr("Remove message %1:%2").arg(DBCManager::parseId(id).second).arg(message.name)); + setText(QObject::tr("Remove message %1:%2").arg(id.address).arg(message.name)); } } @@ -48,9 +48,9 @@ void RemoveMsgCommand::redo() { // AddSigCommand -AddSigCommand::AddSigCommand(const QString &id, const Signal &sig, QUndoCommand *parent) +AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent) : id(id), signal(sig), QUndoCommand(parent) { - setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(DBCManager::parseId(id).second)); + setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(id.address)); } void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name.c_str()); } @@ -58,9 +58,9 @@ void AddSigCommand::redo() { dbc()->addSignal(id, signal); } // RemoveSigCommand -RemoveSigCommand::RemoveSigCommand(const QString &id, const Signal *sig, QUndoCommand *parent) +RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent) : id(id), signal(*sig), QUndoCommand(parent) { - setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(DBCManager::parseId(id).second)); + setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(id.address)); } void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } @@ -68,7 +68,7 @@ void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name.c_str()); } // EditSignalCommand -EditSignalCommand::EditSignalCommand(const QString &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) +EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { setText(QObject::tr("Edit signal %1").arg(old_signal.name.c_str())); } diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index c07a00b760..46e9f0a030 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -7,57 +7,57 @@ class EditMsgCommand : public QUndoCommand { public: - EditMsgCommand(const QString &id, const QString &title, int size, QUndoCommand *parent = nullptr); + EditMsgCommand(const MessageId &id, const QString &title, int size, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - const QString id; + const MessageId id; QString old_title, new_title; int old_size = 0, new_size = 0; }; class RemoveMsgCommand : public QUndoCommand { public: - RemoveMsgCommand(const QString &id, QUndoCommand *parent = nullptr); + RemoveMsgCommand(const MessageId &id, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - const QString id; + const MessageId id; DBCMsg message; }; class AddSigCommand : public QUndoCommand { public: - AddSigCommand(const QString &id, const Signal &sig, QUndoCommand *parent = nullptr); + AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - const QString id; + const MessageId id; Signal signal = {}; }; class RemoveSigCommand : public QUndoCommand { public: - RemoveSigCommand(const QString &id, const Signal *sig, QUndoCommand *parent = nullptr); + RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - const QString id; + const MessageId id; Signal signal = {}; }; class EditSignalCommand : public QUndoCommand { public: - EditSignalCommand(const QString &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr); + EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - const QString id; + const MessageId id; Signal old_signal = {}; Signal new_signal = {}; }; diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 3d565e7067..27f16c71e5 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -4,6 +4,10 @@ #include #include +uint qHash(const MessageId &item) { + return qHash(item.source) ^ qHash(item.address); +} + DBCManager::DBCManager(QObject *parent) : QObject(parent) {} DBCManager::~DBCManager() {} @@ -56,29 +60,27 @@ QString DBCManager::generateDBC() { return dbc_string; } -void DBCManager::updateMsg(const QString &id, const QString &name, uint32_t size) { - auto [_, address] = parseId(id); - auto &m = msgs[address]; +void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size) { + auto &m = msgs[id.address]; m.name = name; m.size = size; - emit msgUpdated(address); + emit msgUpdated(id.address); } -void DBCManager::removeMsg(const QString &id) { - uint32_t address = parseId(id).second; - msgs.erase(address); - emit msgRemoved(address); +void DBCManager::removeMsg(const MessageId &id) { + msgs.erase(id.address); + emit msgRemoved(id.address); } -void DBCManager::addSignal(const QString &id, const Signal &sig) { - if (auto m = const_cast(msg(id))) { +void DBCManager::addSignal(const MessageId &id, const Signal &sig) { + if (auto m = const_cast(msg(id.address))) { auto &s = m->sigs[sig.name.c_str()]; s = sig; - emit signalAdded(parseId(id).second, &s); + emit signalAdded(id.address, &s); } } -void DBCManager::updateSignal(const QString &id, const QString &sig_name, const Signal &sig) { +void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig) { if (auto m = const_cast(msg(id))) { // change key name QString new_name = QString::fromStdString(sig.name); @@ -91,7 +93,7 @@ void DBCManager::updateSignal(const QString &id, const QString &sig_name, const } } -void DBCManager::removeSignal(const QString &id, const QString &sig_name) { +void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { if (auto m = const_cast(msg(id))) { auto it = m->sigs.find(sig_name); if (it != m->sigs.end()) { @@ -101,12 +103,6 @@ void DBCManager::removeSignal(const QString &id, const QString &sig_name) { } } -std::pair DBCManager::parseId(const QString &id) { - const auto list = id.split(':'); - if (list.size() != 2) return {0, 0}; - return {list[0].toInt(), list[1].toUInt(nullptr, 16)}; -} - DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 7571d1c44e..b766c837b6 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -5,6 +5,35 @@ #include #include "opendbc/can/common_dbc.h" +struct MessageId { + uint8_t source; + uint32_t address; + + QString toString() const { + return QString("%1:%2").arg(source).arg(address, 1, 16); + } + + bool operator==(const MessageId &other) const { + return source == other.source && address == other.address; + } + + bool operator!=(const MessageId &other) const { + return !(*this == other); + } + + bool operator<(const MessageId &other) const { + return std::pair{source, address} < std::pair{other.source, other.address}; + } + + bool operator>(const MessageId &other) const { + return std::pair{source, address} > std::pair{other.source, other.address}; + } +}; + +Q_DECLARE_METATYPE(MessageId); + +uint qHash(const MessageId &item); + struct DBCMsg { QString name; uint32_t size; @@ -24,17 +53,16 @@ public: void open(const QString &dbc_file_name); bool open(const QString &name, const QString &content, QString *error = nullptr); QString generateDBC(); - 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); + void addSignal(const MessageId &id, const Signal &sig); + void updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig); + void removeSignal(const MessageId &id, const QString &sig_name); - static std::pair parseId(const QString &id); inline static std::vector allDBCNames() { return get_dbc_names(); } inline QString name() const { return dbc ? dbc->name.c_str() : ""; } - void updateMsg(const QString &id, const QString &name, uint32_t size); - void removeMsg(const QString &id); + void updateMsg(const MessageId &id, const QString &name, uint32_t size); + void removeMsg(const MessageId &id); inline const std::map &messages() const { return msgs; } - inline const DBCMsg *msg(const QString &id) const { return msg(parseId(id).second); } + inline const DBCMsg *msg(const MessageId &id) const { return msg(id.address); } inline const DBCMsg *msg(uint32_t address) const { auto it = msgs.find(address); return it != msgs.end() ? &it->second : nullptr; @@ -65,7 +93,7 @@ int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size); std::pair getSignalRange(const Signal *s); DBCManager *dbc(); -inline QString msgName(const QString &id) { +inline QString msgName(const MessageId &id) { auto msg = dbc()->msg(id); return msg ? msg->name : UNTITLED; } diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 2036912344..55ba0b9feb 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -85,11 +85,15 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &DetailWidget::refresh); QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { - if (index != -1 && tabbar->tabText(index) != msg_id) { - setMessage(tabbar->tabText(index)); + if (index != -1) { + setMessage(tabbar_ids[index]); } }); - QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); + QObject::connect(tabbar, &QTabBar::tabCloseRequested, [this](int index) { + tabbar_ids.removeAt(index); + tabbar->removeTab(index); + assert(tabbar_ids.size() == tabbar->count()); + }); QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState); } @@ -108,29 +112,32 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { } void DetailWidget::removeAll() { - msg_id = ""; + msg_id = std::nullopt; tabbar->blockSignals(true); while (tabbar->count() > 0) { tabbar->removeTab(0); } + tabbar_ids.clear(); tabbar->blockSignals(false); stacked_layout->setCurrentIndex(0); } -void DetailWidget::setMessage(const QString &message_id) { +void DetailWidget::setMessage(const MessageId &message_id) { msg_id = message_id; - int index = tabbar->count() - 1; - for (/**/; index >= 0 && tabbar->tabText(index) != msg_id; --index) { /**/ } + int index = tabbar_ids.indexOf(*msg_id); + if (index == -1) { - index = tabbar->addTab(message_id); + tabbar_ids.append(*msg_id); + index = tabbar->addTab(message_id.toString()); tabbar->setTabToolTip(index, msgName(message_id)); } + assert(tabbar->count() == tabbar_ids.size()); setUpdatesEnabled(false); - signal_view->setMessage(msg_id); - binary_view->setMessage(msg_id); - history_log->setMessage(msg_id); + signal_view->setMessage(*msg_id); + binary_view->setMessage(*msg_id); + history_log->setMessage(*msg_id); stacked_layout->setCurrentIndex(1); tabbar->setCurrentIndex(index); @@ -141,12 +148,12 @@ void DetailWidget::setMessage(const QString &message_id) { } void DetailWidget::refresh() { - if (msg_id.isEmpty()) return; + if (!msg_id) return; QStringList warnings; - const DBCMsg *msg = dbc()->msg(msg_id); + const DBCMsg *msg = dbc()->msg(*msg_id); if (msg) { - if (msg->size != can->lastMessage(msg_id).dat.size()) { + if (msg->size != can->lastMessage(*msg_id).dat.size()) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } for (auto s : binary_view->getOverlappingSignals()) { @@ -156,7 +163,7 @@ void DetailWidget::refresh() { warnings.push_back(tr("Drag-Select in binary view to create new signal.")); } remove_msg_act->setEnabled(msg != nullptr); - name_label->setText(msgName(msg_id)); + name_label->setText(msgName(*msg_id)); if (!warnings.isEmpty()) { warning_label->setText(warnings.join('\n')); @@ -165,9 +172,9 @@ void DetailWidget::refresh() { warning_widget->setVisible(!warnings.isEmpty()); } -void DetailWidget::updateState(const QHash *msgs) { +void DetailWidget::updateState(const QHash *msgs) { time_label->setText(QString::number(can->currentSec(), 'f', 3)); - if (msg_id.isEmpty() || (msgs && !msgs->contains(msg_id))) + if (!msg_id || (msgs && !msgs->contains(*msg_id))) return; if (tab_widget->currentIndex() == 0) @@ -177,24 +184,24 @@ void DetailWidget::updateState(const QHash *msgs) { } void DetailWidget::editMsg() { - QString id = msg_id; + MessageId id = *msg_id; auto msg = dbc()->msg(id); int size = msg ? msg->size : can->lastMessage(id).dat.size(); EditMessageDialog dlg(id, msgName(id), size, this); if (dlg.exec()) { - UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); + UndoStack::push(new EditMsgCommand(*msg_id, dlg.name_edit->text(), dlg.size_spin->value())); } } void DetailWidget::removeMsg() { - UndoStack::push(new RemoveMsgCommand(msg_id)); + UndoStack::push(new RemoveMsgCommand(*msg_id)); } // EditMessageDialog -EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent) +EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent) : original_name(title), QDialog(parent) { - setWindowTitle(tr("Edit message: %1").arg(msg_id)); + setWindowTitle(tr("Edit message: %1").arg(msg_id.toString())); QFormLayout *form_layout = new QFormLayout(this); form_layout->addRow("", error_label = new QLabel); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index c5d5fe9a4d..949a8c9b8d 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -14,7 +14,7 @@ class EditMessageDialog : public QDialog { public: - EditMessageDialog(const QString &msg_id, const QString &title, int size, QWidget *parent); + EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent); void validateName(const QString &text); QString original_name; @@ -34,7 +34,7 @@ class DetailWidget : public QWidget { public: DetailWidget(ChartsWidget *charts, QWidget *parent); - void setMessage(const QString &message_id); + void setMessage(const MessageId &message_id); void refresh(); void removeAll(); QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } @@ -43,13 +43,14 @@ private: void showTabBarContextMenu(const QPoint &pt); void editMsg(); void removeMsg(); - void updateState(const QHash * msgs = nullptr); + void updateState(const QHash * msgs = nullptr); - QString msg_id; + std::optional msg_id; QLabel *time_label, *warning_icon, *warning_label; ElidedLabel *name_label; QWidget *warning_widget; QTabBar *tabbar; + QList tabbar_ids; QTabWidget *tab_widget; QAction *remove_msg_act; LogsWidget *history_log; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index e4ad99758b..f7f02b06d8 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -22,14 +22,14 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { return {}; } -void HistoryLogModel::setMessage(const QString &message_id) { +void HistoryLogModel::setMessage(const MessageId &message_id) { msg_id = message_id; } void HistoryLogModel::refresh() { beginResetModel(); sigs.clear(); - if (auto dbc_msg = dbc()->msg(msg_id)) { + if (auto dbc_msg = dbc()->msg(*msg_id)) { sigs = dbc_msg->getSignals(); } last_fetch_time = 0; @@ -78,8 +78,8 @@ void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function } void HistoryLogModel::updateState() { - if (!msg_id.isEmpty()) { - uint64_t current_time = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9 + 1; + if (msg_id) { + uint64_t current_time = (can->lastMessage(*msg_id).ts + can->routeStartTime()) * 1e9 + 1; auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); if (!new_msgs.empty()) { beginInsertRows({}, 0, new_msgs.size() - 1); @@ -106,12 +106,11 @@ void HistoryLogModel::fetchMore(const QModelIndex &parent) { template std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; - const auto [src, address] = DBCManager::parseId(msg_id); QVector values(sigs.size()); for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - if (address == c.getAddress() && src == c.getSrc()) { + if (msg_id->address == c.getAddress() && msg_id->source == c.getSrc()) { const auto dat = c.getDat(); for (int i = 0; i < sigs.size(); ++i) { values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i])); @@ -136,7 +135,7 @@ template std::deque HistoryLogModel::fetchData<>(std:: std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { auto events = can->events(); - const auto freq = can->lastMessage(msg_id).freq; + const auto freq = can->lastMessage(*msg_id).freq; const bool update_colors = !display_signals_mode || sigs.empty(); if (dynamic_mode) { @@ -241,13 +240,13 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &AbstractStream::eventsMerged, model, &HistoryLogModel::segmentsMerged); } -void LogsWidget::setMessage(const QString &message_id) { +void LogsWidget::setMessage(const MessageId &message_id) { model->setMessage(message_id); refresh(); } void LogsWidget::refresh() { - if (model->msg_id.isEmpty()) return; + if (!model->msg_id) return; model->setFilter(0, "", nullptr); model->refresh(); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 2458fc1c31..00a8f73836 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -1,6 +1,8 @@ #pragma once #include +#include + #include #include #include @@ -22,7 +24,7 @@ class HistoryLogModel : public QAbstractTableModel { public: HistoryLogModel(QObject *parent) : QAbstractTableModel(parent) {} - void setMessage(const QString &message_id); + void setMessage(const MessageId &message_id); void updateState(); void setFilter(int sig_idx, const QString &value, std::function cmp); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; @@ -52,7 +54,7 @@ public: std::deque fetchData(InputIt first, InputIt last, uint64_t min_time); std::deque fetchData(uint64_t from_time, uint64_t min_time = 0); - QString msg_id; + std::optional msg_id; ChangeTracker hex_colors; bool has_more_data = true; const int batch_size = 50; @@ -71,7 +73,7 @@ class LogsWidget : public QWidget { public: LogsWidget(QWidget *parent); - void setMessage(const QString &message_id); + void setMessage(const MessageId &message_id); void updateState() {if (dynamic_mode->isChecked()) model->updateState(); } void showEvent(QShowEvent *event) override { if (dynamic_mode->isChecked()) model->refresh(); } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 8279d08a5c..4f6bb92375 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -46,12 +46,12 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); - QObject::connect(model, &MessageListModel::modelReset, [this]() { selectMessage(current_msg_id); }); + QObject::connect(model, &MessageListModel::modelReset, [this]() { selectMessage(*current_msg_id); }); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid() && current.row() < model->msgs.size()) { - if (model->msgs[current.row()] != current_msg_id) { + if (model->msgs[current.row()] != *current_msg_id) { current_msg_id = model->msgs[current.row()]; - emit msgSelectionChanged(current_msg_id); + emit msgSelectionChanged(*current_msg_id); } } }); @@ -67,7 +67,7 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { updateSuppressedButtons(); } -void MessagesWidget::selectMessage(const QString &msg_id) { +void MessagesWidget::selectMessage(const MessageId &msg_id) { if (int row = model->msgs.indexOf(msg_id); row != -1) { table_widget->selectionModel()->setCurrentIndex(model->index(row, 0), QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); } @@ -86,7 +86,7 @@ void MessagesWidget::updateSuppressedButtons() { void MessagesWidget::reset() { model->reset(); filter->clear(); - current_msg_id = ""; + current_msg_id = std::nullopt; updateSuppressedButtons(); } @@ -106,7 +106,7 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return msgName(id); - case 1: return id; + case 1: return id.toString(); // TODO: put source and address in separate columns case 2: return can_data.freq; case 3: return can_data.count; case 4: return toHex(can_data.dat); @@ -128,9 +128,9 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } void MessageListModel::setFilterString(const QString &string) { - auto contains = [](const QString &id, const QString &txt) { + auto contains = [](const MessageId &id, const QString &txt) { auto cs = Qt::CaseInsensitive; - if (id.contains(txt, cs) || msgName(id).contains(txt, cs)) return true; + if (id.toString().contains(txt, cs) || msgName(id).contains(txt, cs)) return true; // Search by signal name if (const auto msg = dbc()->msg(id)) { for (auto &signal : msg->getSignals()) { @@ -160,9 +160,7 @@ void MessageListModel::sortMessages() { }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - auto ll = DBCManager::parseId(l); - auto rr = DBCManager::parseId(r); - return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; + return sort_order == Qt::AscendingOrder ? l < r : l > r; }); } else if (sort_column == 2) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { @@ -180,7 +178,7 @@ void MessageListModel::sortMessages() { endResetModel(); } -void MessageListModel::msgsReceived(const QHash *new_msgs) { +void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { msgs = can->can_msgs.keys(); diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 81ee36cd6f..562069c3ae 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -20,13 +22,13 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; void setFilterString(const QString &string); - void msgsReceived(const QHash *new_msgs = nullptr); + void msgsReceived(const QHash *new_msgs = nullptr); void sortMessages(); void suppress(); void clearSuppress(); void reset(); - QStringList msgs; - QSet> suppressed_bytes; + QList msgs; + QSet> suppressed_bytes; private: QString filter_str; @@ -39,18 +41,18 @@ class MessagesWidget : public QWidget { public: MessagesWidget(QWidget *parent); - void selectMessage(const QString &message_id); + void selectMessage(const MessageId &message_id); QByteArray saveHeaderState() const { return table_widget->horizontalHeader()->saveState(); } bool restoreHeaderState(const QByteArray &state) const { return table_widget->horizontalHeader()->restoreState(state); } void updateSuppressedButtons(); void reset(); signals: - void msgSelectionChanged(const QString &message_id); + void msgSelectionChanged(const MessageId &message_id); protected: QTableView *table_widget; - QString current_msg_id; + std::optional current_msg_id; QLineEdit *filter; MessageListModel *model; QPushButton *suppress_add; diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 0499b1be8a..98dd39204f 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -31,7 +31,7 @@ void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Sign } } -void SignalModel::setMessage(const QString &id) { +void SignalModel::setMessage(const MessageId &id) { msg_id = id; filter_str = ""; refresh(); @@ -56,7 +56,7 @@ void SignalModel::refresh() { endResetModel(); } -void SignalModel::updateState(const QHash *msgs) { +void SignalModel::updateState(const QHash *msgs) { if (!msgs || (msgs->contains(msg_id))) { auto &dat = can->lastMessage(msg_id).dat; int row = 0; @@ -230,13 +230,13 @@ void SignalModel::removeSignal(const Signal *sig) { } void SignalModel::handleMsgChanged(uint32_t address) { - if (address == DBCManager::parseId(msg_id).second) { + if (address == msg_id.address) { refresh(); } } void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) { - if (address == DBCManager::parseId(msg_id).second) { + if (address == msg_id.address) { int i = 0; for (; i < root->children.size(); ++i) { if (sig->start_bit < root->children[i]->sig->start_bit) break; @@ -367,7 +367,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { expandSignal(sig); }); } -void SignalView::setMessage(const QString &id) { +void SignalView::setMessage(const MessageId &id) { msg_id = id; filter_edit->clear(); model->setMessage(id); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index c0b649209a..7e5015f707 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -37,7 +37,7 @@ public: QModelIndex parent(const QModelIndex &index) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - void setMessage(const QString &id); + void setMessage(const MessageId &id); void setFilter(const QString &txt); void addSignal(int start_bit, int size, bool little_endian); bool saveSignal(const Signal *origin_s, Signal &s); @@ -54,9 +54,9 @@ private: void handleSignalRemoved(const Signal *sig); void handleMsgChanged(uint32_t address); void refresh(); - void updateState(const QHash *msgs); + void updateState(const QHash *msgs); - QString msg_id; + MessageId msg_id; QString filter_str; std::unique_ptr root; friend class SignalView; @@ -76,7 +76,7 @@ class SignalView : public QWidget { public: SignalView(ChartsWidget *charts, QWidget *parent); - void setMessage(const QString &id); + void setMessage(const MessageId &id); void signalHovered(const Signal *sig); void updateChartState(); void expandSignal(const Signal *sig); @@ -85,13 +85,13 @@ public: signals: void highlight(const Signal *sig); - void showChart(const QString &name, const Signal *sig, bool show, bool merge); + void showChart(const MessageId &id, const Signal *sig, bool show, bool merge); private: void rowsChanged(); void leaveEvent(QEvent *event); - QString msg_id; + MessageId msg_id; QTreeView *tree; QLineEdit *filter_edit; ChartsWidget *charts; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 13b154a7ea..5f12e0c42f 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -4,12 +4,12 @@ AbstractStream *can = nullptr; AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_live_streaming(is_live_streaming), QObject(parent) { can = this; - new_msgs = std::make_unique>(); + new_msgs = std::make_unique>(); QObject::connect(this, &AbstractStream::received, this, &AbstractStream::process, Qt::QueuedConnection); QObject::connect(this, &AbstractStream::seekedTo, this, &AbstractStream::updateLastMsgsTo); } -void AbstractStream::process(QHash *messages) { +void AbstractStream::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { can_msgs[it.key()] = it.value(); } @@ -25,7 +25,7 @@ bool AbstractStream::updateEvent(const Event *event) { if (event->which == cereal::Event::Which::CAN) { double current_sec = event->mono_time / 1e9 - routeStartTime(); for (const auto &c : event->event.getCan()) { - QString id = QString("%1:%2").arg(c.getSrc()).arg(c.getAddress(), 1, 16); + MessageId id = {.source = c.getSrc(), .address = c.getAddress()}; CanData &data = (*new_msgs)[id]; data.ts = current_sec; data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); @@ -44,21 +44,21 @@ bool AbstractStream::updateEvent(const Event *event) { prev_update_ts = ts; // use pointer to avoid data copy in queued connection. emit received(new_msgs.release()); - new_msgs.reset(new QHash); + new_msgs.reset(new QHash); new_msgs->reserve(100); } } return true; } -const CanData &AbstractStream::lastMessage(const QString &id) { +const CanData &AbstractStream::lastMessage(const MessageId &id) { static CanData empty_data; auto it = can_msgs.find(id); return it != can_msgs.end() ? it.value() : empty_data; } void AbstractStream::updateLastMsgsTo(double sec) { - QHash, CanData> last_msgs; // Much faster than QHash + QHash last_msgs; last_msgs.reserve(can_msgs.size()); double route_start_time = routeStartTime(); uint64_t last_ts = (sec + route_start_time) * 1e9; @@ -66,7 +66,7 @@ void AbstractStream::updateLastMsgsTo(double sec) { for (auto it = last; it != events()->rend(); ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - auto &m = last_msgs[{c.getSrc(), c.getAddress()}]; + auto &m = last_msgs[{.source = c.getSrc(), .address = c.getAddress()}]; if (++m.count == 1) { m.ts = ((*it)->mono_time / 1e9) - route_start_time; m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); @@ -87,9 +87,8 @@ void AbstractStream::updateLastMsgsTo(double sec) { counters.clear(); can_msgs.clear(); for (auto it = last_msgs.cbegin(); it != last_msgs.cend(); ++it) { - QString msg_id = QString("%1:%2").arg(it.key().first).arg(it.key().second, 1, 16); - can_msgs[msg_id] = it.value(); - counters[msg_id] = it.value().count; + can_msgs[it.key()] = it.value(); + counters[it.key()] = it.value().count; } emit updated(); emit msgsReceived(&can_msgs); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 8c10d959cb..e582682971 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -5,6 +5,7 @@ #include #include +#include "tools/cabana/dbcmanager.h" #include "tools/cabana/settings.h" #include "tools/cabana/util.h" #include "tools/replay/replay.h" @@ -33,7 +34,7 @@ public: virtual double routeStartTime() const { return 0; } virtual double currentSec() const = 0; virtual QDateTime currentDateTime() const { return {}; } - virtual const CanData &lastMessage(const QString &id); + virtual const CanData &lastMessage(const MessageId &id); virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } virtual const Route *route() const { return nullptr; } virtual const std::vector *events() const = 0; @@ -49,22 +50,22 @@ signals: void streamStarted(); void eventsMerged(); void updated(); - void msgsReceived(const QHash *); - void received(QHash *); + void msgsReceived(const QHash *); + void received(QHash *); public: - QHash can_msgs; + QHash can_msgs; protected: - void process(QHash *); + void process(QHash *); bool updateEvent(const Event *event); void updateLastMsgsTo(double sec); bool is_live_streaming = false; std::atomic processing = false; - QHash counters; - std::unique_ptr> new_msgs; - QHash change_trackers; + QHash counters; + std::unique_ptr> new_msgs; + QHash change_trackers; }; // A global pointer referring to the unique AbstractStream object diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 63d01b152d..ffb0e54b0e 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -20,10 +20,10 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi bus_combo = new QComboBox(this); QSet bus_set; for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { - bus_set << DBCManager::parseId(it.key()).first; + bus_set << it.key().source; } for (uint8_t bus : bus_set) { - bus_combo->addItem(QString::number(bus)); + bus_combo->addItem(QString::number(bus), bus); } bus_combo->model()->sort(0); bus_combo->setCurrentIndex(0); @@ -69,9 +69,11 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi setMinimumSize({700, 500}); QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); + QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) { if (index.isValid()) { - emit openMessage(bus_combo->currentText() + ":" + table->item(index.row(), 0)->text()); + MessageId msg_id = {.source = (uint8_t)bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; + emit openMessage(msg_id); } }); } diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 30d78f0dea..53d7806a8f 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -6,6 +6,8 @@ #include #include +#include "tools/cabana/dbcmanager.h" + class FindSimilarBitsDlg : public QDialog { Q_OBJECT @@ -13,7 +15,7 @@ public: FindSimilarBitsDlg(QWidget *parent); signals: - void openMessage(const QString &msg_id); + void openMessage(const MessageId &msg_id); private: struct mismatched_struct { From 5dde8f2c8436df9a11bfb11cf86dcfbf3f1ee874 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 15 Feb 2023 15:52:10 -0800 Subject: [PATCH 0950/1179] Write boardd param to continue startup (#27354) disable at the bottom --- selfdrive/car/car_helpers.py | 3 ++- selfdrive/car/fw_versions.py | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index ae19fd6248..370772c902 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -8,7 +8,7 @@ from system.version import is_comma_remote, is_tested_branch from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from selfdrive.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN -from selfdrive.car.fw_versions import get_fw_versions_ordered, match_fw_to_car, get_present_ecus +from selfdrive.car.fw_versions import disable_obd_multiplexing, get_fw_versions_ordered, match_fw_to_car, get_present_ecus from system.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.car import gen_empty_fingerprint @@ -116,6 +116,7 @@ def fingerprint(logcan, sendcan, num_pandas): params = Params() params.put("CarVin", vin) + disable_obd_multiplexing(params) finger = gen_empty_fingerprint() candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 23b0fcc6d1..8092ac0b76 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -198,6 +198,15 @@ def get_brand_ecu_matches(ecu_rx_addrs): return brand_matches +def disable_obd_multiplexing(params): + if not params.get_bool("ObdMultiplexingDisabled"): + params.put_bool("FirmwareObdQueryDone", True) + + cloudlog.warning("Waiting for OBD multiplexing to be disabled") + params.get_bool("ObdMultiplexingDisabled", block=True) + cloudlog.warning("OBD multiplexing disabled") + + 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""" @@ -214,14 +223,9 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand matched_brand = brand break + disable_obd_multiplexing(Params()) + # Do non-OBD queries for matched brand, or all if no match is found - params = Params() - params.put_bool("FirmwareObdQueryDone", True) - - cloudlog.warning("Waiting for OBD multiplexing to be disabled") - params.get_bool("ObdMultiplexingDisabled", block=True) - cloudlog.warning("OBD multiplexing disabled") - for brand in FW_QUERY_CONFIGS.keys(): if brand == matched_brand or matched_brand is None: all_car_fw.extend(get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, obd_multiplexed=False, debug=debug, progress=progress)) From 2bc2dbfb700e71588c998cf1dfaef10ac9d852ce Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 15 Feb 2023 15:55:08 -0800 Subject: [PATCH 0951/1179] process replay: fix hang --- selfdrive/test/process_replay/process_replay.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index b531cb3430..28fc9c452c 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -407,6 +407,7 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): params.put_bool("WideCameraOnly", False) params.put_bool("DisableLogging", False) params.put_bool("UbloxAvailable", True) + params.put_bool("ObdMultiplexingDisabled", True) os.environ["NO_RADAR_SLEEP"] = "1" os.environ["REPLAY"] = "1" From 48b059d3670e8082eae785c850508f88b1181188 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 15 Feb 2023 15:59:23 -0800 Subject: [PATCH 0952/1179] CAN fingerprint script improvements (#27355) * match online logic * 0 and 2 are different buses. on gm, same address has different lengths * match fingerprint_from_route --- selfdrive/debug/fingerprint_from_route.py | 2 +- selfdrive/debug/get_fingerprint.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/debug/fingerprint_from_route.py b/selfdrive/debug/fingerprint_from_route.py index 326e68f8e7..b3598b105c 100755 --- a/selfdrive/debug/fingerprint_from_route.py +++ b/selfdrive/debug/fingerprint_from_route.py @@ -17,7 +17,7 @@ def get_fingerprint(lr): for c in msg.can: # read also msgs sent by EON on CAN bus 0x80 and filter out the # addr with more than 11 bits - if c.src % 0x80 == 0 and c.address < 0x800: + if c.src % 0x80 == 0 and c.address < 0x800 and c.address not in (0x7df, 0x7e0, 0x7e8): msgs[c.address] = len(c.dat) # show CAN fingerprint diff --git a/selfdrive/debug/get_fingerprint.py b/selfdrive/debug/get_fingerprint.py index e678db4f17..f7f7a1604f 100755 --- a/selfdrive/debug/get_fingerprint.py +++ b/selfdrive/debug/get_fingerprint.py @@ -22,7 +22,7 @@ while True: for c in lc.can: # read also msgs sent by EON on CAN bus 0x80 and filter out the # addr with more than 11 bits - if c.src in [0, 2] and c.address < 0x800: + if c.src % 0x80 == 0 and c.address < 0x800 and c.address not in (0x7df, 0x7e0, 0x7e8): msgs[c.address] = len(c.dat) fingerprint = ', '.join("%d: %d" % v for v in sorted(msgs.items())) From 89934b35d04291384b7a287a41ce49905f321167 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 15 Feb 2023 16:27:00 -0800 Subject: [PATCH 0953/1179] Car interfaces: assert reasonable centerToFront range (#27356) * assert reasonable centerToFront values * comment * fix Bolt centerToFront * Update ref_commit --- selfdrive/car/gm/interface.py | 2 +- selfdrive/car/tests/test_car_interfaces.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 104cb8fbd8..71e1ad4018 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -213,7 +213,7 @@ class CarInterface(CarInterfaceBase): ret.mass = 1669. + STD_CARGO_KG ret.wheelbase = 2.63779 ret.steerRatio = 16.8 - ret.centerToFront = 2.15 # measured + ret.centerToFront = ret.wheelbase * 0.4 tire_stiffness_factor = 1.0 ret.steerActuatorDelay = 0.12 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 78ecbe425e..ac8213e4c1 100755 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -32,7 +32,8 @@ class TestCarInterfaces(unittest.TestCase): self.assertGreater(car_params.mass, 1) self.assertGreater(car_params.wheelbase, 0) - self.assertGreater(car_params.centerToFront, 0) + # centerToFront is center of gravity to front wheels, assert a reasonable range + self.assertTrue(car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7) self.assertGreater(car_params.maxLateralAccel, 0) # Longitudinal sanity checks diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 85eada072e..b151a6a5ae 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c7bb411b37ab7ff573402b6e4fa24f796cbb2ee8 \ No newline at end of file +fbb99ee7dc0336062e6785814af82e359dcdd9bf From b76795d7f083c956004fefd07dbb406eeeb20584 Mon Sep 17 00:00:00 2001 From: Ricky Gilleland Date: Wed, 15 Feb 2023 20:07:24 -0500 Subject: [PATCH 0954/1179] GM: Escalade 2017 support (#27276) * Initial 2017 Escalade values * update docs/CARS.md * revert back to v1 fingerprint & add test route * revert bad merge * update fingerprint * update * update * Update selfdrive/car/gm/values.py * Update selfdrive/car/gm/values.py * no engine * Try global tune * pcm * Driver Assist Package has ACC, and includes LKAS from previous package * update docs * add to releases --------- Co-authored-by: Shane Smiskol --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/gm/interface.py | 8 ++++++++ selfdrive/car/gm/values.py | 6 ++++++ selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/override.yaml | 1 + 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index ceae8d10cb..78d2e3b74b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -7,6 +7,7 @@ Version 0.9.1 (2023-02-23) * Adjust alert volume using ambient noise level * Driver monitoring icon shows driver's head pose * German translation thanks to Vrabetz and CzokNorris! +* Cadillac Escalade 2017 support thanks to rickygilleland! * Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler! * Genesis GV60 2023 support thanks to sunnyhaibin! * Hyundai Tucson 2022-23 support diff --git a/docs/CARS.md b/docs/CARS.md index e6b6bbee7d..8860299360 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 236 Supported Cars +# 237 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -17,6 +17,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 71e1ad4018..c28274011e 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -198,6 +198,14 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 15.3 ret.centerToFront = ret.wheelbase * 0.5 + elif candidate == CAR.ESCALADE: + ret.minEnableSpeed = -1. # engage speed is decided by pcm + ret.mass = 5653. * CV.LB_TO_KG + STD_CARGO_KG # (5552+5815)/2 + ret.wheelbase = 2.95 # 116 inches in meters + ret.steerRatio = 17.3 + ret.centerToFront = ret.wheelbase * 0.5 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.ESCALADE_ESV: ret.minEnableSpeed = -1. # engage speed is decided by pcm ret.mass = 2739. + STD_CARGO_KG diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 1c956192eb..207af6bb05 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -67,6 +67,7 @@ class CAR: MALIBU = "CHEVROLET MALIBU PREMIER 2017" ACADIA = "GMC ACADIA DENALI 2018" BUICK_REGAL = "BUICK REGAL ESSENCE 2018" + ESCALADE = "CADILLAC ESCALADE 2017" ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016" BOLT_EUV = "CHEVROLET BOLT EUV 2022" SILVERADO = "CHEVROLET SILVERADO 1500 2020" @@ -99,6 +100,7 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), + CAR.ESCALADE: GMCarInfo("Cadillac Escalade 2017", "Driver Assist Package"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), CAR.BOLT_EUV: [ GMCarInfo("Chevrolet Bolt EUV 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", "https://youtu.be/xvwzGMUA210"), @@ -174,6 +176,10 @@ FINGERPRINTS = { { 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 313: 8, 320: 3, 322: 7, 328: 1, 338: 6, 340: 6, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 393: 8, 398: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1919: 7, 1920: 7, 1930: 7, 2016: 8, 2024: 8 }], + CAR.ESCALADE: [ + { + 170: 8, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 4, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 460: 5, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 719: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1917: 7, 1918: 7, 1919: 7, 1920: 7, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 + }], CAR.ESCALADE_ESV: [ { 309: 1, 848: 8, 849: 8, 850: 8, 851: 8, 852: 8, 853: 8, 854: 3, 1056: 6, 1057: 8, 1058: 8, 1059: 8, 1060: 8, 1061: 8, 1062: 8, 1063: 8, 1064: 8, 1065: 8, 1066: 8, 1067: 8, 1068: 8, 1120: 8, 1121: 8, 1122: 8, 1123: 8, 1124: 8, 1125: 8, 1126: 8, 1127: 8, 1128: 8, 1129: 8, 1130: 8, 1131: 8, 1132: 8, 1133: 8, 1134: 8, 1135: 8, 1136: 8, 1137: 8, 1138: 8, 1139: 8, 1140: 8, 1141: 8, 1142: 8, 1143: 8, 1146: 8, 1147: 8, 1148: 8, 1149: 8, 1150: 8, 1151: 8, 1216: 8, 1217: 8, 1218: 8, 1219: 8, 1220: 8, 1221: 8, 1222: 8, 1223: 8, 1224: 8, 1225: 8, 1226: 8, 1232: 8, 1233: 8, 1234: 8, 1235: 8, 1236: 8, 1237: 8, 1238: 8, 1239: 8, 1240: 8, 1241: 8, 1242: 8, 1787: 8, 1788: 8 diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index a4d2f55581..02e37492d3 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -50,6 +50,7 @@ routes = [ CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA), CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL), + CarTestRoute("ef8f2185104d862e|2023-02-09--18-37-13", GM.ESCALADE), CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV), CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT), CarTestRoute("f08912a233c1584f|2022-08-11--18-02-41", GM.BOLT_EUV, segment=1), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 52c9e8d547..cc1681bce1 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -26,6 +26,7 @@ COMMA BODY: [.nan, 1000, .nan] RAM 1500 5TH GEN: [2.0, 2.0, 0.0] RAM HD 5TH GEN: [1.4, 1.4, 0.0] SUBARU OUTBACK 6TH GEN: [2.3, 2.3, 0.11] +CADILLAC ESCALADE 2017: [1.899999976158142, 1.842270016670227, 0.1120000034570694] CHEVROLET BOLT EUV 2022: [2.0, 2.0, 0.05] CHEVROLET SILVERADO 1500 2020: [1.9, 1.9, 0.112] CHEVROLET EQUINOX 2019: [2.0, 2.0, 0.05] From 90ce7605c159133eaad5ffe6259da513db28e8ff Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Wed, 15 Feb 2023 20:33:04 -0500 Subject: [PATCH 0955/1179] Hyundai: 2015-16 Genesis resume from standstill fix (#25579) * Hyundai: 2015-16 Genesis resume from standstill fix * Add comment * Fix typo * Merge both methods * Add back the comment * 20Hz not needed according to tester * no new global state variable * PCM's perspective: random counter -> random counter * only send 5 --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/carcontroller.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 516666eff1..1e6f78af20 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -169,7 +169,8 @@ class CarController: if (self.frame - self.last_button_frame) * DT_CTRL > 0.1: # send 25 messages at a time to increases the likelihood of resume being accepted can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25) - self.last_button_frame = self.frame + if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15: + self.last_button_frame = self.frame if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl: # TODO: unclear if this is needed From 4638d4b1a2e1dd7ad500750e6f8d97b0e66e9e97 Mon Sep 17 00:00:00 2001 From: wowcat1234 <124840678+wowcat1234@users.noreply.github.com> Date: Wed, 15 Feb 2023 21:17:46 -0600 Subject: [PATCH 0956/1179] Add fingerprint for Hyundai Ioniq 22 limited HEV (#27334) * Update values.py * update for ioniq HEV 22 --------- Co-authored-by: Shane Smiskol --- 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 9067299473..086bd1f26b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -483,6 +483,7 @@ FW_VERSIONS = { CAR.IONIQ_HEV_2022: { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ', + b'\xf1\x00AEhe SCC FHCUP 1.00 1.00 99110-G2600 ', ], (Ecu.eps, 0x7d4, None): [ b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101', @@ -495,6 +496,7 @@ FW_VERSIONS = { ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x00\x00\x00\x00', + b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00HAE0G16NL2\x96\xda\xd4\xee', ], }, CAR.SONATA: { From d7ddf25899ba480b11a6b9064875392b7d2f68b5 Mon Sep 17 00:00:00 2001 From: gregschueman <124465406+gregschueman@users.noreply.github.com> Date: Wed, 15 Feb 2023 22:21:36 -0500 Subject: [PATCH 0957/1179] 2021 Hyundai Ioniq PHEV - additional engine fingerprint added (#27221) * Update values.py Addition of Hyundai 2021 Ioniq PHEV modeled on 2019 entry * Update values.py * Update values.py * Update values.py * Update values.py * replace with shorter trans --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 086bd1f26b..4a7f257092 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -437,13 +437,14 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00', + b'\xf1\x816H6G5051\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x816U3J9051\000\000\xf1\0006U3H1_C2\000\0006U3J9051\000\000PAE0G16NL0\x82zT\xd2', b'\xf1\x816U3J8051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00', - b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt', b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00', b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL0\x00\x00\x00\x00', + b'\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt', ], }, CAR.IONIQ_EV_2020: { From 2769b110e0b0ea82f96471d964b05499441b6d73 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 15 Feb 2023 19:42:56 -0800 Subject: [PATCH 0958/1179] Fingerprint for Hyundai Santa Fe 2019 Europe (#26952) * Fingerpint fur Hyundai Santa Fe 2019 Europe * add version for transmission segment 092ef1cc055c6354|2023-01-05--17-49-21 * remove long --------- Co-authored-by: sevdokim --- selfdrive/car/hyundai/values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4a7f257092..15c239506b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -685,12 +685,14 @@ FW_VERSIONS = { }, CAR.SANTA_FE: { (Ecu.fwdRadar, 0x7d0, None): [ + b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1210 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.01 99110-S2000 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.02 99110-S2000 ', b'\xf1\x00TM__ SCC F-CUP 1.00 1.03 99110-S2000 ', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00TM ESC \r 100\x18\x031 58910-S2650', + b'\xf1\x00TM ESC \r 105\x19\x05# 58910-S1500', b'\xf1\x00TM ESC \r 103\x18\x11\x08 58910-S2650', b'\xf1\x00TM ESC \r 104\x19\x07\x08 58910-S2650', b'\xf1\x00TM ESC \x02 100\x18\x030 58910-S2600', @@ -709,11 +711,14 @@ FW_VERSIONS = { b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8409', b'\xf1\x00TM MDPS C 1.00 1.00 56340-S2000 8A12', b'\xf1\x00TM MDPS C 1.00 1.01 56340-S2000 9129', + b'\xf1\x00TM MDPS R 1.00 1.02 57700-S1100 4TMDP102' ], (Ecu.fwdCamera, 0x7c4, None): [ + b'\xf1\x00TM MFC AT EUR LHD 1.00 1.01 99211-S1010 181207', b'\xf1\x00TM MFC AT USA LHD 1.00 1.00 99211-S2000 180409', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00bcsh8p54 U833\x00\x00\x00\x00\x00\x00TTM4V22US3_<]\xf1', b'\xf1\x006W351_C2\x00\x006W3E1051\x00\x00TTM4T20NS5\x00\x00\x00\x00', b'\xf1\x87LBJSGA7082574HG0\x87www\x98\x88\x88\x88\x99\xaa\xb9\x9afw\x86gx\x99\xa7\x89co\xf8\xffvU_\xffR\xaf\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\xa6\xe0\x91', b'\xf1\x87LBKSGA0458404HG0vfvg\x87www\x89\x99\xa8\x99y\xaa\xa7\x9ax\x88\xa7\x88t_\xf9\xff\x86w\x8f\xff\x15x\xf1\x816W3C2051\x00\x00\xf1\x006W351_C2\x00\x006W3C2051\x00\x00TTM2T20NS1\x00\x00\x00\x00', From e6c02027d3d7c6cd850fb13b948bd010b15b5308 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 16 Feb 2023 19:34:18 +0100 Subject: [PATCH 0959/1179] cabana: fix updating tabbar_ids on "Close Other Tabs" (#27362) --- tools/cabana/detailwidget.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 55ba0b9feb..bf4c1e44f8 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -103,10 +103,14 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { QMenu menu(this); menu.addAction(tr("Close Other Tabs")); if (menu.exec(tabbar->mapToGlobal(pt))) { + tabbar_ids.move(index, 0); tabbar->moveTab(index, 0); tabbar->setCurrentIndex(0); - while (tabbar->count() > 1) + while (tabbar->count() > 1) { + tabbar_ids.removeAt(1); tabbar->removeTab(1); + } + assert(tabbar_ids.size() == tabbar->count()); } } } From 8772306467630df66716e47ec34fa36935152bf6 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 16 Feb 2023 19:34:42 +0100 Subject: [PATCH 0960/1179] cabana: fix events() call in AbstractStream::updateLastMsgsTo (#27360) --- tools/cabana/streams/abstractstream.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 5f12e0c42f..8fdfbd5c1b 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -62,8 +62,9 @@ void AbstractStream::updateLastMsgsTo(double sec) { last_msgs.reserve(can_msgs.size()); double route_start_time = routeStartTime(); uint64_t last_ts = (sec + route_start_time) * 1e9; - auto last = std::upper_bound(events()->rbegin(), events()->rend(), last_ts, [](uint64_t ts, auto &e) { return e->mono_time < ts; }); - for (auto it = last; it != events()->rend(); ++it) { + auto evs = events(); + auto last = std::upper_bound(evs->rbegin(), evs->rend(), last_ts, [](uint64_t ts, auto &e) { return e->mono_time < ts; }); + for (auto it = last; it != evs->rend(); ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { auto &m = last_msgs[{.source = c.getSrc(), .address = c.getAddress()}]; From 2510f78126b0a457b5e8b42f1f32e5bf24a2c045 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 17 Feb 2023 06:47:36 +0800 Subject: [PATCH 0961/1179] cabana: add online-help (#27349) * add online helps * typo * remove duplicate 'too' * show idle message:For Help, Press F1 * improve drawHelp * fix color desc --- tools/cabana/binaryview.cc | 15 ++++++++ tools/cabana/chartswidget.cc | 5 +++ tools/cabana/detailwidget.cc | 5 +-- tools/cabana/mainwin.cc | 66 ++++++++++++++++++++++++++++++++-- tools/cabana/mainwin.h | 14 ++++++++ tools/cabana/messageswidget.cc | 9 +++++ tools/cabana/signaledit.cc | 5 +++ tools/cabana/videowidget.cc | 7 ++++ 8 files changed, 122 insertions(+), 4 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 9085bf310a..20edfd06ff 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -42,6 +42,21 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &BinaryView::refresh); addShortcuts(); + setWhatsThis(R"( + Binary View
+ + Shortcuts:
+ Delete Signal: + x , + Backspace , + Delete
+ Change endianness: e
+ Change singedness: s
+ Open chart: + c , + p , + g
+ )"); } void BinaryView::addShortcuts() { diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 9a085ec732..9c5ed097c6 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -94,6 +94,11 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { docking = !docking; updateToolBar(); }); + + setWhatsThis(tr(R"( + Chart view
+ + )")); } void ChartsWidget::eventsMerged() { diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index bf4c1e44f8..95ef975dd1 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -264,11 +264,12 @@ WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { return hlayout; }; - auto lb = new QLabel(tr("<-Select a message to to view details")); + auto lb = new QLabel(tr("<-Select a message to view details")); lb->setAlignment(Qt::AlignHCenter); main_layout->addWidget(lb); main_layout->addLayout(newShortcutRow("Pause", "Space")); - main_layout->addLayout(newShortcutRow("Help", "Alt + H")); + main_layout->addLayout(newShortcutRow("Help", "F1")); + main_layout->addLayout(newShortcutRow("WhatsThis", "Shift+F1")); main_layout->addStretch(0); setStyleSheet("QLabel{color:darkGray;}"); diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index bce6d313c8..07d37df4e4 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -20,7 +22,7 @@ static MainWindow *main_win = nullptr; void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (type == QtDebugMsg) std::cout << msg.toStdString() << std::endl; - if (main_win) emit main_win->showMessage(msg, 0); + if (main_win) emit main_win->showMessage(msg, 2000); } MainWindow::MainWindow() : QMainWindow() { @@ -43,7 +45,7 @@ MainWindow::MainWindow() : QMainWindow() { qRegisterMetaType("ReplyMsgType"); installMessageHandler([this](ReplyMsgType type, const std::string msg) { // use queued connection to recv the log messages from replay. - emit showMessage(QString::fromStdString(msg), 3000); + emit showMessage(QString::fromStdString(msg), 2000); }); installDownloadProgressHandler([this](uint64_t cur, uint64_t total, bool success) { emit updateProgressBar(cur, total, success); @@ -125,6 +127,7 @@ void MainWindow::createActions() { tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); QMenu *help_menu = menuBar()->addMenu(tr("&Help")); + help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents); help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } @@ -173,6 +176,7 @@ void MainWindow::createStatusBar() { progress_bar->setTextVisible(true); progress_bar->setFixedSize({230, 16}); progress_bar->setVisible(false); + statusBar()->addWidget(new QLabel(tr("For Help,Press F1"))); statusBar()->addPermanentWidget(progress_bar); } @@ -422,3 +426,61 @@ void MainWindow::findSimilarBits() { QObject::connect(dlg, &FindSimilarBitsDlg::openMessage, messages_widget, &MessagesWidget::selectMessage); dlg->show(); } + +void MainWindow::onlineHelp() { + if (auto help = findChild()) { + help->close(); + } else { + help = new HelpOverlay(this); + help->setGeometry(rect()); + help->show(); + help->raise(); + } +} + +// HelpOverlay +HelpOverlay::HelpOverlay(MainWindow *parent) : QWidget(parent) { + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_TranslucentBackground, true); + setAttribute(Qt::WA_DeleteOnClose); + parent->installEventFilter(this); +} + +void HelpOverlay::paintEvent(QPaintEvent *event) { + QPainter painter(this); + painter.fillRect(rect(), QColor(0, 0, 0, 50)); + MainWindow *parent = (MainWindow *)parentWidget(); + drawHelpForWidget(painter, parent->findChild()); + drawHelpForWidget(painter, parent->findChild()); + drawHelpForWidget(painter, parent->findChild()); + drawHelpForWidget(painter, parent->findChild()); + drawHelpForWidget(painter, parent->findChild()); +} + +void HelpOverlay::drawHelpForWidget(QPainter &painter, QWidget *w) { + if (w && w->isVisible() && !w->whatsThis().isEmpty()) { + QPoint pt = mapFromGlobal(w->mapToGlobal(w->rect().center())); + if (rect().contains(pt)) { + QTextDocument document; + document.setHtml(w->whatsThis()); + QSize doc_size = document.size().toSize(); + QPoint topleft = {pt.x() - doc_size.width() / 2, pt.y() - doc_size.height() / 2}; + painter.translate(topleft); + painter.fillRect(QRect{{0, 0}, doc_size}, palette().toolTipBase()); + document.drawContents(&painter); + painter.translate(-topleft); + } + } +} + +bool HelpOverlay::eventFilter(QObject *obj, QEvent *event) { + if (obj == parentWidget() && event->type() == QEvent::Resize) { + QResizeEvent *resize_event = (QResizeEvent *)(event); + setGeometry(QRect{QPoint(0, 0), resize_event->size()}); + } + return false; +} + +void HelpOverlay::mouseReleaseEvent(QMouseEvent *event) { + close(); +} diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 5e627df58b..e7a39adab7 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -54,6 +54,7 @@ protected: void setOption(); void findSimilarBits(); void undoStackCleanChanged(bool clean); + void onlineHelp(); VideoWidget *video_widget = nullptr; QDockWidget *video_dock; @@ -69,4 +70,17 @@ protected: enum { MAX_RECENT_FILES = 15 }; QAction *recent_files_acts[MAX_RECENT_FILES] = {}; QMenu *open_recent_menu = nullptr; + friend class OnlineHelp; +}; + +class HelpOverlay : public QWidget { + Q_OBJECT +public: + HelpOverlay(MainWindow *parent); + +protected: + void drawHelpForWidget(QPainter &painter, QWidget *w); + void paintEvent(QPaintEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + bool eventFilter(QObject *obj, QEvent *event) override; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 4f6bb92375..1cf85ed740 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -65,6 +65,15 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { }); updateSuppressedButtons(); + + setWhatsThis(tr(R"( + Message View
+ + Byte color:
+ constant changing
+ increasing
+ decreasing
+ )")); } void MessagesWidget::selectMessage(const MessageId &msg_id) { diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 98dd39204f..e2be5c85d0 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -365,6 +365,11 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { expandSignal(sig); }); + + setWhatsThis(tr(R"( + Signal view
+ + )")); } void SignalView::setMessage(const MessageId &id) { diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index cd3dc0b516..f77f7c306d 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -53,6 +53,13 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState); QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState); updatePlayBtnState(); + + setWhatsThis(tr(R"( + Video
+ + Shortcuts:
+ Pause/Resume: space
+ )")); } QWidget *VideoWidget::createCameraWidget() { From 202eb06a05e43ce77e5be19540fb427b5a060cfc Mon Sep 17 00:00:00 2001 From: grekiki <96022003+GregorKikelj@users.noreply.github.com> Date: Thu, 16 Feb 2023 23:51:25 +0100 Subject: [PATCH 0962/1179] Carla simulator: set driver orientation (#27363) --- tools/sim/bridge.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py index f0694078e2..7bb12badb2 100755 --- a/tools/sim/bridge.py +++ b/tools/sim/bridge.py @@ -211,7 +211,10 @@ def fake_driver_monitoring(exit_event: threading.Event): while not exit_event.is_set(): # dmonitoringmodeld output dat = messaging.new_message('driverStateV2') + dat.driverStateV2.leftDriverData.faceOrientation = [0., 0., 0.] dat.driverStateV2.leftDriverData.faceProb = 1.0 + dat.driverStateV2.rightDriverData.faceOrientation = [0., 0., 0.] + dat.driverStateV2.rightDriverData.faceProb = 1.0 pm.send('driverStateV2', dat) # dmonitoringd output From 5e0b28111902f9d8565a5bae50369185ad1cbe01 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 16 Feb 2023 16:09:11 -0800 Subject: [PATCH 0963/1179] HKG: log AEB/FCW for Kia Ceed (#27364) Ceed uses FCA --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 15c239506b..422431a718 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1660,7 +1660,7 @@ FEATURES = { "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022, CAR.KIA_K5_HEV_2020}, # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_OPTIMA_G4_FL}, + "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.KIA_CEED, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_OPTIMA_G4_FL}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN} From 37adf5d3a681daac2542270a24897ae00d42e4b8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 17 Feb 2023 10:53:12 +0800 Subject: [PATCH 0964/1179] cabana: simplify conversions between QVariant and QVector (#27367) --- tools/cabana/historylog.cc | 2 +- tools/cabana/messageswidget.cc | 16 +++++++--------- tools/cabana/util.cc | 25 ++++++------------------- tools/cabana/util.h | 1 - 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index f7f02b06d8..87968d495c 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -17,7 +17,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { } return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { - return ChangeTracker::toVariantList(m.colors); + return QVariant::fromValue(m.colors); } return {}; } diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 1cf85ed740..81ebc6af20 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -121,17 +121,15 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { case 4: return toHex(can_data.dat); } } else if (role == Qt::UserRole && index.column() == 4) { - QList colors; - colors.reserve(can_data.dat.size()); - for (int i = 0; i < can_data.dat.size(); i++){ - if (suppressed_bytes.contains({id, i})) { - colors.append(QColor(255, 255, 255, 0)); - } else { - colors.append(i < can_data.colors.size() ? can_data.colors[i] : QColor(255, 255, 255, 0)); + QVector colors = can_data.colors; + if (!suppressed_bytes.empty()) { + for (int i = 0; i < colors.size(); i++) { + if (suppressed_bytes.contains({id, i})) { + colors[i] = QColor(255, 255, 255, 0); + } } } - return colors; - + return QVariant::fromValue(colors); } return {}; } diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 454dd29b87..9843a3f00c 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -66,13 +66,6 @@ void ChangeTracker::clear() { colors.clear(); } -QList ChangeTracker::toVariantList(const QVector &colors) { - QList ret; - ret.reserve(colors.size()); - for (auto &c : colors) ret.append(c); - return ret; -} - // MessageBytesDelegate MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { @@ -89,12 +82,8 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & return; } - if ((option.state & QStyle::State_Selected) && (option.state & QStyle::State_Active)) { - painter->setPen(option.palette.color(QPalette::HighlightedText)); - } else { - painter->setPen(option.palette.color(QPalette::Text)); - } - + auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText: QPalette::Text; + painter->setPen(option.palette.color(color_role)); painter->setFont(fixed_font); QRect space = painter->boundingRect(opt.rect, opt.displayAlignment, " "); QRect pos = painter->boundingRect(opt.rect, opt.displayAlignment, "00"); @@ -103,15 +92,13 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & int m = space.width() / 2; const QMargins margins(m, m, m, m); - QList colors = index.data(Qt::UserRole).toList(); - int i = 0; - for (auto &byte : byte_list) { + auto colors = index.data(Qt::UserRole).value>(); + for (int i = 0; i < byte_list.size(); ++i) { if (i < colors.size()) { - painter->fillRect(pos.marginsAdded(margins), colors[i].value()); + painter->fillRect(pos.marginsAdded(margins), colors[i]); } - painter->drawText(pos, opt.displayAlignment, byte); + painter->drawText(pos, opt.displayAlignment, byte_list[i]); pos.moveLeft(pos.right() + space.width()); - i++; } } diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 8ec4cda90c..eb5203fb0b 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -14,7 +14,6 @@ class ChangeTracker { public: void compute(const QByteArray &dat, double ts, uint32_t freq); - static QList toVariantList(const QVector &colors); void clear(); QVector last_change_t; From b2453d55c12e4e6e8e5115ef7c8daf0f60205fdb Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 16 Feb 2023 21:52:32 -0800 Subject: [PATCH 0965/1179] Hyundai: detect FCA feature (#27322) * detect fca * use value * it will be from camera on camera acc cars * Update ref_commit --- selfdrive/car/hyundai/carstate.py | 8 ++++---- selfdrive/car/hyundai/interface.py | 4 ++++ selfdrive/car/hyundai/values.py | 4 +--- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index 0bab188790..22934c05b2 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -135,8 +135,8 @@ class CarState(CarStateBase): ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear)) if not self.CP.openpilotLongitudinalControl: - aeb_src = "FCA11" if self.CP.carFingerprint in FEATURES["use_fca"] else "SCC12" - aeb_sig = "FCA_CmdAct" if self.CP.carFingerprint in FEATURES["use_fca"] else "AEB_CmdAct" + aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12" + aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct" aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0 aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0 ret.stockFcw = aeb_warning and not aeb_braking @@ -317,7 +317,7 @@ class CarState(CarStateBase): ("SCC12", 50), ] - if CP.carFingerprint in FEATURES["use_fca"]: + if CP.flags & HyundaiFlags.USE_FCA.value: signals += [ ("FCA_CmdAct", "FCA11"), ("CF_VSM_Warn", "FCA11"), @@ -408,7 +408,7 @@ class CarState(CarStateBase): ("SCC12", 50), ] - if CP.carFingerprint in FEATURES["use_fca"]: + if CP.flags & HyundaiFlags.USE_FCA.value: signals += [ ("FCA_CmdAct", "FCA11"), ("CF_VSM_Warn", "FCA11"), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index ae0f26274c..d2cc5b4ec0 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -48,6 +48,10 @@ class CarInterface(CarInterfaceBase): if 0x485 in fingerprint[2]: ret.flags |= HyundaiFlags.SEND_LFA.value + # These cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 + if 0x38d in fingerprint[0] or 0x38d in fingerprint[2]: + ret.flags |= HyundaiFlags.USE_FCA.value + ret.steerActuatorDelay = 0.1 # Default delay ret.steerLimitTimer = 0.4 tire_stiffness_factor = 1. diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 422431a718..d0a4e4dd1a 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -61,6 +61,7 @@ class HyundaiFlags(IntFlag): ENABLE_BLINKERS = 32 CANFD_ALT_GEARS_2 = 64 SEND_LFA = 128 + USE_FCA = 256 class CAR: @@ -1658,9 +1659,6 @@ FEATURES = { "use_cluster_gears": {CAR.ELANTRA, CAR.KONA}, "use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON}, "use_elect_gears": {CAR.KIA_NIRO_EV, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.IONIQ, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.KONA_EV_2022, CAR.KIA_K5_HEV_2020}, - - # these cars use the FCA11 message for the AEB and FCW signals, all others use SCC12 - "use_fca": {CAR.SONATA, CAR.SONATA_HYBRID, CAR.ELANTRA, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.KIA_STINGER, CAR.KIA_CEED, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KONA_EV, CAR.KIA_FORTE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.PALISADE, CAR.GENESIS_G70, CAR.GENESIS_G70_2020, CAR.KONA, CAR.SANTA_FE, CAR.KIA_SELTOS, CAR.KONA_HEV, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.TUCSON, CAR.KONA_EV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_OPTIMA_G4_FL}, } CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN} diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index b151a6a5ae..6884eb4660 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -fbb99ee7dc0336062e6785814af82e359dcdd9bf +8883c476d5abc12b4b2949e04c6d7c0cd7c8b9fa From 524f7079a9a51631bef042f28bfc339ecdf6d7d3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Feb 2023 02:35:50 +0800 Subject: [PATCH 0966/1179] cabana: add description for timeline color in help (#27375) --- tools/cabana/videowidget.cc | 41 +++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index f77f7c306d..2b5374d85f 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -13,6 +13,15 @@ #include #include +static const QColor timeline_colors[] = { + [(int)TimelineType::None] = QColor(111, 143, 175), + [(int)TimelineType::Engaged] = QColor(0, 163, 108), + [(int)TimelineType::UserFlag] = Qt::magenta, + [(int)TimelineType::AlertInfo] = Qt::green, + [(int)TimelineType::AlertWarning] = QColor(255, 195, 0), + [(int)TimelineType::AlertCritical] = QColor(199, 0, 57), +}; + inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } @@ -57,9 +66,23 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { setWhatsThis(tr(R"( Video
- Shortcuts:
- Pause/Resume: space
- )")); + Timeline color + + + + + + + +
Disengaged Engaged
User Flag Info
Warning Critical
+ Shortcuts
+ Pause/Resume:  space  + )").arg(timeline_colors[(int)TimelineType::None].name(), + timeline_colors[(int)TimelineType::Engaged].name(), + timeline_colors[(int)TimelineType::UserFlag].name(), + timeline_colors[(int)TimelineType::AlertInfo].name(), + timeline_colors[(int)TimelineType::AlertWarning].name(), + timeline_colors[(int)TimelineType::AlertCritical].name())); } QWidget *VideoWidget::createCameraWidget() { @@ -212,17 +235,9 @@ void Slider::sliderChange(QAbstractSlider::SliderChange change) { } void Slider::paintEvent(QPaintEvent *ev) { - static const QColor colors[] = { - [(int)TimelineType::None] = QColor(111, 143, 175), - [(int)TimelineType::Engaged] = QColor(0, 163, 108), - [(int)TimelineType::UserFlag] = Qt::white, - [(int)TimelineType::AlertInfo] = Qt::green, - [(int)TimelineType::AlertWarning] = QColor(255, 195, 0), - [(int)TimelineType::AlertCritical] = QColor(199, 0, 57)}; - QPainter p(this); QRect r = rect().adjusted(0, 4, 0, -4); - p.fillRect(r, colors[(int)TimelineType::None]); + p.fillRect(r, timeline_colors[(int)TimelineType::None]); double min = minimum() / 1000.0; double max = maximum() / 1000.0; for (auto [begin, end, type] : timeline) { @@ -230,7 +245,7 @@ void Slider::paintEvent(QPaintEvent *ev) { continue; r.setLeft(((std::max(min, (double)begin) - min) / (max - min)) * width()); r.setRight(((std::min(max, (double)end) - min) / (max - min)) * width()); - p.fillRect(r, colors[(int)type]); + p.fillRect(r, timeline_colors[(int)type]); } QStyleOptionSlider opt; From 2c5e55ccdca597857208fc2fbb6bbc58972dbc4b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Feb 2023 02:53:47 +0800 Subject: [PATCH 0967/1179] cabana: attach messageid to tabdata (#27368) --- tools/cabana/detailwidget.cc | 20 +++++++++----------- tools/cabana/detailwidget.h | 1 - 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 95ef975dd1..f290b3b706 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -86,13 +86,11 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(tabbar, &QTabBar::customContextMenuRequested, this, &DetailWidget::showTabBarContextMenu); QObject::connect(tabbar, &QTabBar::currentChanged, [this](int index) { if (index != -1) { - setMessage(tabbar_ids[index]); + setMessage(tabbar->tabData(index).value()); } }); QObject::connect(tabbar, &QTabBar::tabCloseRequested, [this](int index) { - tabbar_ids.removeAt(index); tabbar->removeTab(index); - assert(tabbar_ids.size() == tabbar->count()); }); QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState); } @@ -103,14 +101,11 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { QMenu menu(this); menu.addAction(tr("Close Other Tabs")); if (menu.exec(tabbar->mapToGlobal(pt))) { - tabbar_ids.move(index, 0); tabbar->moveTab(index, 0); tabbar->setCurrentIndex(0); while (tabbar->count() > 1) { - tabbar_ids.removeAt(1); tabbar->removeTab(1); } - assert(tabbar_ids.size() == tabbar->count()); } } } @@ -121,21 +116,25 @@ void DetailWidget::removeAll() { while (tabbar->count() > 0) { tabbar->removeTab(0); } - tabbar_ids.clear(); tabbar->blockSignals(false); stacked_layout->setCurrentIndex(0); } void DetailWidget::setMessage(const MessageId &message_id) { msg_id = message_id; - int index = tabbar_ids.indexOf(*msg_id); + tabbar->blockSignals(true); + int index = tabbar->count() - 1; + for (/**/; index >= 0; --index) { + if (tabbar->tabData(index).value() == message_id) break; + } if (index == -1) { - tabbar_ids.append(*msg_id); index = tabbar->addTab(message_id.toString()); + tabbar->setTabData(index, QVariant::fromValue(message_id)); tabbar->setTabToolTip(index, msgName(message_id)); } - assert(tabbar->count() == tabbar_ids.size()); + tabbar->setCurrentIndex(index); + tabbar->blockSignals(false); setUpdatesEnabled(false); @@ -144,7 +143,6 @@ void DetailWidget::setMessage(const MessageId &message_id) { history_log->setMessage(*msg_id); stacked_layout->setCurrentIndex(1); - tabbar->setCurrentIndex(index); refresh(); splitter->setSizes({1, 2}); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 949a8c9b8d..b3e353d539 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -50,7 +50,6 @@ private: ElidedLabel *name_label; QWidget *warning_widget; QTabBar *tabbar; - QList tabbar_ids; QTabWidget *tab_widget; QAction *remove_msg_act; LogsWidget *history_log; From 89f68bf0cbf53a81b0553d3816fdbe522f941fa1 Mon Sep 17 00:00:00 2001 From: martinl Date: Fri, 17 Feb 2023 21:08:41 +0200 Subject: [PATCH 0968/1179] cleanup: remove nonexisting third_party includes (#27372) --- SConstruct | 4 ---- 1 file changed, 4 deletions(-) diff --git a/SConstruct b/SConstruct index 31aa6ecced..007931b7f5 100644 --- a/SConstruct +++ b/SConstruct @@ -197,10 +197,6 @@ env = Environment( "#third_party/libyuv/include", "#third_party/json11", "#third_party/curl/include", - "#third_party/libgralloc/include", - "#third_party/android_frameworks_native/include", - "#third_party/android_hardware_libhardware/include", - "#third_party/android_system_core/include", "#third_party/linux/include", "#third_party/snpe/include", "#third_party/mapbox-gl-native-qt/include", From b9a01752fc88e12eb3375aca1492d0cedae17946 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 Feb 2023 14:13:22 -0800 Subject: [PATCH 0969/1179] bump version to 0.9.2 --- RELEASES.md | 4 ++++ common/version.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 78d2e3b74b..ff5b686e0c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,7 @@ +Version 0.9.2 (2023-03-XX) +======================== + + Version 0.9.1 (2023-02-23) ======================== * New driving model diff --git a/common/version.h b/common/version.h index 7b5764785a..5637029cf4 100644 --- a/common/version.h +++ b/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.9.1" +#define COMMA_VERSION "0.9.2" From dad948983a7ff26ffc073c536bd1e99b5d826cec Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 Feb 2023 15:04:21 -0800 Subject: [PATCH 0970/1179] chyrsler: add comment about radar parsing --- selfdrive/car/chrysler/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 961684f398..303f563c90 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -12,6 +12,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "chrysler" ret.dashcamOnly = candidate in RAM_HD + # radar parsing needs some work, see https://github.com/commaai/openpilot/issues/26842 ret.radarUnavailable = True # DBC[candidate]['radar'] is None ret.steerActuatorDelay = 0.1 ret.steerLimitTimer = 0.4 From 04fe6c4ec72dfcf89456a484d03f85502c237701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 17 Feb 2023 15:28:26 -0800 Subject: [PATCH 0971/1179] Expand lateral MPC to 10s (#27343) * 10s lat * Full length MPC * redfine N * Leave controls the same for now * Updates * use long plan in lat plan * interp plan * add new interp * simplergit add selfdrive/controls/plannerd.py selfdrive/controls/ * expand to 10s * revert this * fix linter * Update sconscripts * fix test * fix test * fix test * Revert "Update sconscripts" This reverts commit 6e23c69dcebd5ed003e37e01921f6af7c31de0db. * Dont import drive helpers * better compile deps * fix compile * comment * update replay * Update plannerd time --- selfdrive/controls/lib/drive_helpers.py | 2 -- .../controls/lib/lateral_mpc_lib/SConscript | 1 + .../controls/lib/lateral_mpc_lib/lat_mpc.py | 10 ++++----- selfdrive/controls/lib/lateral_planner.py | 21 +++++++++++-------- .../lib/longitudinal_mpc_lib/SConscript | 1 + .../lib/longitudinal_mpc_lib/long_mpc.py | 1 + selfdrive/controls/tests/test_lateral_mpc.py | 3 ++- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/test/test_onroad.py | 2 +- 9 files changed, 24 insertions(+), 19 deletions(-) diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py index a332d06765..05c3897335 100644 --- a/selfdrive/controls/lib/drive_helpers.py +++ b/selfdrive/controls/lib/drive_helpers.py @@ -17,8 +17,6 @@ V_CRUISE_INITIAL_EXPERIMENTAL_MODE = 105 IMPERIAL_INCREMENT = 1.6 # should be CV.MPH_TO_KPH, but this causes rounding errors MIN_SPEED = 1.0 -LAT_MPC_N = 16 -LON_MPC_N = 32 CONTROL_N = 17 CAR_ROTATION_RADIUS = 0.0 diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index 868b5a873c..745ed99d10 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -47,6 +47,7 @@ acados_dir = '#third_party/acados' acados_templates_dir = '#third_party/acados/acados_template/c_templates_tera' source_list = ['lat_mpc.py', + '#/selfdrive/modeld/constants.py', f'{acados_dir}/include/acados_c/ocp_nlp_interface.h', f'{acados_dir}/x86_64/lib/libacados.so', f'{acados_dir}/larch64/lib/libacados.so', diff --git a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py index 536f436fce..ca7b991e69 100755 --- a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py +++ b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py @@ -3,8 +3,8 @@ import os import numpy as np from casadi import SX, vertcat, sin, cos - from common.realtime import sec_since_boot +# WARNING: imports outside of constants will not trigger a rebuild from selfdrive.modeld.constants import T_IDXS if __name__ == '__main__': # generating code @@ -17,12 +17,12 @@ EXPORT_DIR = os.path.join(LAT_MPC_DIR, "c_generated_code") JSON_FILE = os.path.join(LAT_MPC_DIR, "acados_ocp_lat.json") X_DIM = 4 P_DIM = 2 -N = 16 COST_E_DIM = 3 COST_DIM = COST_E_DIM + 2 SPEED_OFFSET = 10.0 MODEL_NAME = 'lat' ACADOS_SOLVER_TYPE = 'SQP_RTI' +N = 32 def gen_lat_model(): model = AcadosModel() @@ -168,14 +168,14 @@ class LateralMpc(): self.solver.constraints_set(0, "lbx", x0_cp) self.solver.constraints_set(0, "ubx", x0_cp) self.yref[:,0] = y_pts - v_ego = p_cp[0] + v_ego = p_cp[0, 0] # rotation_radius = p_cp[1] self.yref[:,1] = heading_pts * (v_ego + SPEED_OFFSET) self.yref[:,2] = yaw_rate_pts * (v_ego + SPEED_OFFSET) for i in range(N): self.solver.cost_set(i, "yref", self.yref[i]) - self.solver.set(i, "p", p_cp) - self.solver.set(N, "p", p_cp) + self.solver.set(i, "p", p_cp[i]) + self.solver.set(N, "p", p_cp[N]) self.solver.cost_set(N, "yref", self.yref[N][:COST_E_DIM]) t = sec_since_boot() diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index 932ad49535..7230b5ad14 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -16,12 +16,12 @@ CAMERA_OFFSET = 0.04 PATH_COST = 1.0 LATERAL_MOTION_COST = 0.11 LATERAL_ACCEL_COST = 0.0 -LATERAL_JERK_COST = 0.05 +LATERAL_JERK_COST = 0.04 # Extreme steering rate is unpleasant, even # when it does not cause bad jerk. # TODO this cost should be lowered when low # speed lateral control is stable on all cars -STEERING_RATE_COST = 800.0 +STEERING_RATE_COST = 700.0 class LateralPlanner: @@ -35,6 +35,7 @@ class LateralPlanner: self.solution_invalid_cnt = 0 self.path_xyz = np.zeros((TRAJECTORY_SIZE, 3)) + self.velocity_xyz = np.zeros((TRAJECTORY_SIZE, 3)) self.plan_yaw = np.zeros((TRAJECTORY_SIZE,)) self.plan_yaw_rate = np.zeros((TRAJECTORY_SIZE,)) self.t_idxs = np.arange(TRAJECTORY_SIZE) @@ -49,7 +50,6 @@ class LateralPlanner: def update(self, sm): # clip speed , lateral planning is not possible at 0 speed - self.v_ego = max(MIN_SPEED, sm['carState'].vEgo) measured_curvature = sm['controlsState'].curvature # Parse model predictions @@ -59,6 +59,10 @@ class LateralPlanner: self.t_idxs = np.array(md.position.t) self.plan_yaw = np.array(md.orientation.z) self.plan_yaw_rate = np.array(md.orientationRate.z) + self.velocity_xyz = np.column_stack([md.velocity.x, md.velocity.y, md.velocity.z]) + car_speed = np.linalg.norm(self.velocity_xyz, axis=1) + self.v_plan = np.clip(car_speed, MIN_SPEED, np.inf) + self.v_ego = self.v_plan[0] # Lane change logic desire_state = md.meta.desireState @@ -68,21 +72,20 @@ class LateralPlanner: lane_change_prob = self.l_lane_change_prob + self.r_lane_change_prob self.DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob) - d_path_xyz = self.path_xyz self.lat_mpc.set_weights(PATH_COST, LATERAL_MOTION_COST, LATERAL_ACCEL_COST, LATERAL_JERK_COST, STEERING_RATE_COST) - y_pts = np.interp(self.v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(d_path_xyz, axis=1), d_path_xyz[:, 1]) - heading_pts = np.interp(self.v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(self.path_xyz, axis=1), self.plan_yaw) - yaw_rate_pts = np.interp(self.v_ego * self.t_idxs[:LAT_MPC_N + 1], np.linalg.norm(self.path_xyz, axis=1), self.plan_yaw_rate) + y_pts = self.path_xyz[:LAT_MPC_N+1, 1] + heading_pts = self.plan_yaw[:LAT_MPC_N+1] + yaw_rate_pts = self.plan_yaw_rate[:LAT_MPC_N+1] self.y_pts = y_pts assert len(y_pts) == LAT_MPC_N + 1 assert len(heading_pts) == LAT_MPC_N + 1 assert len(yaw_rate_pts) == LAT_MPC_N + 1 - lateral_factor = max(0, self.factor1 - (self.factor2 * self.v_ego**2)) - p = np.array([self.v_ego, lateral_factor]) + lateral_factor = np.clip(self.factor1 - (self.factor2 * self.v_plan**2), 0.0, np.inf) + p = np.column_stack([self.v_plan, lateral_factor]) self.lat_mpc.run(self.x0, p, y_pts, diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index e5b2360607..7f5daf157c 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -54,6 +54,7 @@ acados_dir = '#third_party/acados' acados_templates_dir = '#third_party/acados/acados_template/c_templates_tera' source_list = ['long_mpc.py', + '#/selfdrive/modeld/constants.py', f'{acados_dir}/include/acados_c/ocp_nlp_interface.h', f'{acados_dir}/x86_64/lib/libacados.so', f'{acados_dir}/larch64/lib/libacados.so', diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py index c017951232..660002691a 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @@ -5,6 +5,7 @@ import numpy as np from common.realtime import sec_since_boot from common.numpy_fast import clip from system.swaglog import cloudlog +# WARNING: imports outside of constants will not trigger a rebuild from selfdrive.modeld.constants import index_function from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU diff --git a/selfdrive/controls/tests/test_lateral_mpc.py b/selfdrive/controls/tests/test_lateral_mpc.py index df5154b2b4..b569da09b4 100644 --- a/selfdrive/controls/tests/test_lateral_mpc.py +++ b/selfdrive/controls/tests/test_lateral_mpc.py @@ -17,7 +17,8 @@ def run_mpc(lat_mpc=None, v_ref=30., x_init=0., y_init=0., psi_init=0., curvatur curv_rate_pts = np.zeros(LAT_MPC_N + 1) x0 = np.array([x_init, y_init, psi_init, curvature_init]) - p = np.array([v_ref, CAR_ROTATION_RADIUS]) + p = np.column_stack([v_ref * np.ones(LAT_MPC_N + 1), + CAR_ROTATION_RADIUS * np.ones(LAT_MPC_N + 1)]) # converge in no more than 10 iterations for _ in range(10): diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 6884eb4660..4a670b11ff 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -8883c476d5abc12b4b2949e04c6d7c0cd7c8b9fa +086896986a3fcdb1a03d9afd00a9abc928f9ef25 diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 4021e27de3..84511771f7 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -26,7 +26,7 @@ PROCS = { "./encoderd": 17.0, "./camerad": 14.5, "./locationd": 9.1, - "selfdrive.controls.plannerd": 11.7, + "selfdrive.controls.plannerd": 16.5, "./_ui": 19.2, "selfdrive.locationd.paramsd": 9.0, "./_sensord": 12.0, From b6fd39856c2862132f00ca48269f2e851cda62f3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 17 Feb 2023 18:39:27 -0800 Subject: [PATCH 0972/1179] HKG: simplify Ioniq car params (#27371) * move PHEV to other ioniqs * reverse if * order * order --- selfdrive/car/hyundai/interface.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index d2cc5b4ec0..2a909b6e2e 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -103,18 +103,13 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.6 ret.steerRatio = 13.42 # Spec tire_stiffness_factor = 0.385 - elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): + elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019, CAR.IONIQ_HEV_2022, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV): ret.mass = 1490. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx ret.wheelbase = 2.7 ret.steerRatio = 13.73 # Spec tire_stiffness_factor = 0.385 - if candidate not in (CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.IONIQ_HEV_2022): + if candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019): ret.minSteerSpeed = 32 * CV.MPH_TO_MS - elif candidate == CAR.IONIQ_PHEV_2019: - ret.mass = 1550. + STD_CARGO_KG # weight per hyundai site https://www.hyundaiusa.com/us/en/vehicles/2019-ioniq-plug-in-hybrid/compare-specs - ret.wheelbase = 2.7 - ret.steerRatio = 13.73 - ret.minSteerSpeed = 32 * CV.MPH_TO_MS elif candidate == CAR.VELOSTER: ret.mass = 3558. * CV.LB_TO_KG ret.wheelbase = 2.80 From 7330466dffe4b1142c64d99d328654e7109e8073 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Sat, 18 Feb 2023 03:12:15 +0000 Subject: [PATCH 0973/1179] Ford Escape PHEV 2022 Fingerprint (#27382) * Ford Escape PHEV 2022 Fingerprint 6cffc47c251aa36c|2023-02-17--18-17-14 VIN: 1FMCU0EZ0NUB76728 * include MY2022 in car info * Update selfdrive/car/ford/values.py Co-authored-by: Shane Smiskol --------- Co-authored-by: koffee-bean Co-authored-by: Shane Smiskol --- selfdrive/car/ford/values.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 526b74b16c..24415c74be 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -72,7 +72,8 @@ class FordCarInfo(CarInfo): CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { CAR.BRONCO_SPORT_MK1: FordCarInfo("Ford Bronco Sport 2021-22"), CAR.ESCAPE_MK4: [ - FordCarInfo("Ford Escape 2020-21"), + FordCarInfo("Ford Escape 2020-22"), + FordCarInfo("Ford Escape Plug-in Hybrid 2020-22"), FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"), ], CAR.EXPLORER_MK6: [ @@ -128,6 +129,7 @@ FW_VERSIONS = { (Ecu.eps, 0x730, None): [ b'LX6C-14D003-AF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6C-14D003-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'LX6C-14D003-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x760, None): [ b'LX6C-2D053-NS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', @@ -145,10 +147,12 @@ FW_VERSIONS = { b'LX6A-14C204-BJV\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6A-14C204-ESG\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MX6A-14C204-BEF\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'NX6A-14C204-BLE\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.shiftByWire, 0x732, None): [ b'LX6P-14G395-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LX6P-14G395-AD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + b'PZ1P-14G395-AC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], }, CAR.EXPLORER_MK6: { From ce9fd785d55f5bee8e49d035b13548709fbe989c Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Fri, 17 Feb 2023 19:30:06 -0800 Subject: [PATCH 0974/1179] Ford: add CarInfo for Plug-in Hybrids --- selfdrive/car/ford/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 24415c74be..951cd09ba0 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -75,10 +75,12 @@ CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { FordCarInfo("Ford Escape 2020-22"), FordCarInfo("Ford Escape Plug-in Hybrid 2020-22"), FordCarInfo("Ford Kuga 2020-21", "Driver Assistance Pack"), + FordCarInfo("Ford Kuga Plug-in Hybrid 2020-22", "Driver Assistance Pack"), ], CAR.EXPLORER_MK6: [ FordCarInfo("Ford Explorer 2020-22"), FordCarInfo("Lincoln Aviator 2021", "Co-Pilot360 Plus"), + FordCarInfo("Lincoln Aviator Plug-in Hybrid 2021", "Co-Pilot360 Plus"), ], CAR.FOCUS_MK4: FordCarInfo("Ford Focus EU 2019", "Driver Assistance Pack"), CAR.MAVERICK_MK1: FordCarInfo("Ford Maverick 2022", "Co-Pilot360 Assist"), From ac0dbf74bc835faa46beab4bbb948c95597e4e67 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Feb 2023 11:31:54 +0800 Subject: [PATCH 0975/1179] cabana: add support for load&save extra dbc info (#27203) * support extra info * support undo/redo * fix undo/redo * cleanup * fix regexp * refactor dbcmanager * replace text in headerview * fix binary::refresh * cleanup * use QRegularExpression * add desc validation * edit val description in table * cleanup --- tools/cabana/SConscript | 2 + tools/cabana/binaryview.cc | 21 ++- tools/cabana/binaryview.h | 3 +- tools/cabana/chartswidget.cc | 8 +- tools/cabana/chartswidget.h | 2 +- tools/cabana/commands.cc | 16 +- tools/cabana/commands.h | 4 +- tools/cabana/dbcmanager.cc | 220 +++++++++++++++++--------- tools/cabana/dbcmanager.h | 56 ++++--- tools/cabana/detailwidget.cc | 6 +- tools/cabana/historylog.cc | 19 +-- tools/cabana/historylog.h | 3 +- tools/cabana/messageswidget.cc | 6 +- tools/cabana/messageswidget.h | 2 + tools/cabana/signaledit.cc | 122 ++++++++++++-- tools/cabana/signaledit.h | 18 ++- tools/cabana/streams/replaystream.cc | 2 - tools/cabana/streams/replaystream.h | 1 - tools/cabana/tests/test_cabana.cc | 19 ++- tools/cabana/tools/findsimilarbits.cc | 1 + tools/cabana/tools/findsimilarbits.h | 1 + tools/cabana/util.cc | 2 +- tools/cabana/util.h | 6 +- tools/cabana/videowidget.h | 2 + 24 files changed, 376 insertions(+), 166 deletions(-) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index a9922ba9be..166b3d5548 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -17,6 +17,8 @@ qt_libs = ['qt_util'] + base_libs cabana_libs = [widgets, cereal, messaging, visionipc, replay_lib, opendbc,'avutil', 'avcodec', 'avformat', 'bz2', 'curl', 'yuv'] + qt_libs cabana_env = qt_env.Clone() +opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc").abspath) +cabana_env['CXXFLAGS'] += [opendbc_path] prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 20edfd06ff..5ea5ea2d99 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -12,7 +12,6 @@ #include "tools/cabana/commands.h" #include "tools/cabana/signaledit.h" -#include "tools/cabana/streams/abstractstream.h" // BinaryView @@ -170,7 +169,7 @@ void BinaryView::highlightPosition(const QPoint &pos) { auto item = (BinaryViewModel::Item *)index.internalPointer(); const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); highlight(sig); - QToolTip::showText(pos, sig ? sig->name.c_str() : "", this, rect()); + QToolTip::showText(pos, sig ? sig->name : "", this, rect()); } } @@ -246,22 +245,22 @@ std::tuple BinaryView::getSelection(QModelIndex index) { void BinaryViewModel::refresh() { beginResetModel(); items.clear(); - if ((dbc_msg = dbc()->msg(*msg_id))) { + if (auto dbc_msg = dbc()->msg(*msg_id)) { row_count = dbc_msg->size; items.resize(row_count * column_count); - for (auto sig : dbc_msg->getSignals()) { - auto [start, end] = getSignalRange(sig); + for (auto &sig : dbc_msg->sigs) { + 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 " << sig->name.c_str() << "out of bounds.start_bit:" << sig->start_bit << "size:" << sig->size; + qWarning() << "signal " << sig.name << "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; - items[idx].bg_color = getColor(sig); - items[idx].sigs.push_back(sig); + 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(&sig); + items[idx].sigs.push_back(&sig); } } } else { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 6743b6cfac..1d6d5d0b07 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -9,6 +9,8 @@ #include #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class BinaryItemDelegate : public QStyledItemDelegate { public: @@ -49,7 +51,6 @@ public: std::vector items; std::optional msg_id; - const DBCMsg *dbc_msg = nullptr; int row_count = 0; const int column_count = 9; }; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 9c5ed097c6..8515ffcfe7 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -459,7 +459,7 @@ void ChartView::updateTitle() { } for (auto &s : sigs) { auto decoration = s.series->isVisible() ? "none" : "line-through"; - s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name.c_str(), msgName(s.msg_id), s.msg_id.toString())); + s.series->setName(QString("%2 %3 %4").arg(decoration, s.sig->name, msgName(s.msg_id), s.msg_id.toString())); } } @@ -672,7 +672,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { value = QString::number(it->y()); track_pts[i] = chart()->mapToPosition(*it); } - text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name.c_str(), value)); + text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name, value)); } auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); auto pt = (max == track_pts.end()) ? ev->pos() : *max; @@ -887,7 +887,7 @@ void SeriesSelector::updateAvailableList(int index) { available_list->clear(); MessageId msg_id = msgs_combo->itemData(index).value(); auto selected_items = seletedItems(); - for (auto &[name, s] : dbc()->msg(msg_id)->sigs) { + for (auto &s : dbc()->msg(msg_id)->sigs) { bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); if (!is_selected) { addItemToList(available_list, msg_id, &s); @@ -896,7 +896,7 @@ void SeriesSelector::updateAvailableList(int index) { } void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name) { - QString text = QString(" %1").arg(getColor(sig).name(), sig->name.c_str()); + QString text = QString(" %1").arg(getColor(sig).name(), sig->name); if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id.toString()); QLabel *label = new QLabel(text); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 7569155d39..7089b4eaee 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -15,7 +15,7 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" - +using namespace dbcmanager; using namespace QtCharts; const int CHART_MIN_WIDTH = 300; diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index b03f46b5d2..e03d6d1b11 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -36,7 +36,7 @@ RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : void RemoveMsgCommand::undo() { if (!message.name.isEmpty()) { dbc()->updateMsg(id, message.name, message.size); - for (auto &[name, s] : message.sigs) + for (auto &s : message.sigs) dbc()->addSignal(id, s); } } @@ -50,31 +50,31 @@ void RemoveMsgCommand::redo() { AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent) : id(id), signal(sig), QUndoCommand(parent) { - setText(QObject::tr("Add signal %1 to %2").arg(sig.name.c_str()).arg(id.address)); + setText(QObject::tr("Add signal %1 to %2").arg(sig.name).arg(id.address)); } -void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name.c_str()); } +void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name); } void AddSigCommand::redo() { dbc()->addSignal(id, signal); } // RemoveSigCommand RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent) : id(id), signal(*sig), QUndoCommand(parent) { - setText(QObject::tr("Remove signal %1 from %2").arg(signal.name.c_str()).arg(id.address)); + setText(QObject::tr("Remove signal %1 from %2").arg(signal.name).arg(id.address)); } void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } -void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name.c_str()); } +void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name); } // EditSignalCommand EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { - setText(QObject::tr("Edit signal %1").arg(old_signal.name.c_str())); + setText(QObject::tr("Edit signal %1").arg(old_signal.name)); } -void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name.c_str(), old_signal); } -void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name.c_str(), new_signal); } +void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name, old_signal); } +void EditSignalCommand::redo() { dbc()->updateSignal(id, old_signal.name, new_signal); } namespace UndoStack { diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 46e9f0a030..57df664974 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -4,6 +4,8 @@ #include #include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class EditMsgCommand : public QUndoCommand { public: @@ -25,7 +27,7 @@ public: private: const MessageId id; - DBCMsg message; + Msg message; }; class AddSigCommand : public QUndoCommand { diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 27f16c71e5..ae3a65a99b 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -1,63 +1,114 @@ #include "tools/cabana/dbcmanager.h" +#include +#include +#include +#include +#include #include #include -#include -uint qHash(const MessageId &item) { - return qHash(item.source) ^ qHash(item.address); +namespace dbcmanager { + +void sortSignalsByAddress(QList &sigs) { + std::sort(sigs.begin(), sigs.end(), [](auto &a, auto &b) { return a.start_bit < b.start_bit; }); } -DBCManager::DBCManager(QObject *parent) : QObject(parent) {} - -DBCManager::~DBCManager() {} - -void DBCManager::open(const QString &dbc_file_name) { - dbc = const_cast(dbc_lookup(dbc_file_name.toStdString())); - initMsgMap(); -} - -bool DBCManager::open(const QString &name, const QString &content, QString *error) { - try { - std::istringstream stream(content.toStdString()); - dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); - initMsgMap(); - return true; - } catch (std::exception &e) { - if (error) *error = e.what(); +bool DBCManager::open(const QString &dbc_file_name, QString *error) { + QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, dbc_file_name); + QFile file(opendbc_file_path); + if (file.open(QIODevice::ReadOnly)) { + return open(dbc_file_name, file.readAll(), error); } return false; } -void DBCManager::initMsgMap() { - msgs.clear(); - for (auto &msg : dbc->msgs) { - auto &m = msgs[msg.address]; - m.name = msg.name.c_str(); - m.size = msg.size; - for (auto &s : msg.sigs) - m.sigs[QString::fromStdString(s.name)] = s; +void DBCManager::parseExtraInfo(const QString &content) { + static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); + static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); + static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); + static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"(.*)\";)"); + static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (.*);)"); + auto get_sig = [this](uint32_t address, const QString &name) -> Signal * { + auto m = (Msg *)msg(address); + return m ? (Signal *)m->sig(name) : nullptr; + }; + + QTextStream stream((QString *)&content); + uint32_t address = 0; + while (!stream.atEnd()) { + QString line = stream.readLine().trimmed(); + if (line.startsWith("BO_ ")) { + if (auto match = bo_regexp.match(line); match.hasMatch()) { + address = match.captured(1).toUInt(); + } + } else if (line.startsWith("SG_ ")) { + int offset = 0; + auto match = sg_regexp.match(line); + if (!match.hasMatch()) { + match = sgm_regexp.match(line); + offset = 1; + } + if (match.hasMatch()) { + if (auto s = get_sig(address, match.captured(1))) { + s->min = match.captured(8 + offset); + s->max = match.captured(9 + offset); + s->unit = match.captured(10 + offset); + } + } + } else if (line.startsWith("VAL_ ")) { + if (auto match = val_regexp.match(line); match.hasMatch()) { + if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { + QStringList desc_list = match.captured(3).trimmed().split('"'); + for (int i = 0; i < desc_list.size(); i += 2) { + auto val = desc_list[i].trimmed(); + if (!val.isEmpty() && (i + 1) < desc_list.size()) { + auto desc = desc_list[i+1].trimmed(); + s->val_desc.push_back({val, desc}); + } + } + } + } + } else if (line.startsWith("CM_ SG_ ")) { + if (auto match = sg_comment_regexp.match(line); match.hasMatch()) { + if (auto s = get_sig(match.captured(1).toUInt(), match.captured(2))) { + s->comment = match.captured(3).trimmed(); + } + } + } } - emit DBCFileChanged(); } QString DBCManager::generateDBC() { - QString dbc_string; + QString dbc_string, signal_comment, val_desc; for (auto &[address, m] : msgs) { dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); - for (auto &[name, sig] : m.sigs) { - dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [0|0] \"\" XXX\n") - .arg(name) + for (auto &sig : m.sigs) { + dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") + .arg(sig.name) .arg(sig.start_bit) .arg(sig.size) .arg(sig.is_little_endian ? '1' : '0') .arg(sig.is_signed ? '-' : '+') .arg(sig.factor, 0, 'g', std::numeric_limits::digits10) - .arg(sig.offset, 0, 'g', std::numeric_limits::digits10); + .arg(sig.offset, 0, 'g', std::numeric_limits::digits10) + .arg(sig.min) + .arg(sig.max) + .arg(sig.unit); + if (!sig.comment.isEmpty()) { + signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig.name).arg(sig.comment); + } + if (!sig.val_desc.isEmpty()) { + QString text; + for (auto &[val, desc] : sig.val_desc) { + text += QString("%1 \"%2\"").arg(val, desc); + } + val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig.name).arg(text); + } } dbc_string += "\n"; } - return dbc_string; + return dbc_string + signal_comment + val_desc; } void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t size) { @@ -73,31 +124,29 @@ void DBCManager::removeMsg(const MessageId &id) { } void DBCManager::addSignal(const MessageId &id, const Signal &sig) { - if (auto m = const_cast(msg(id.address))) { - auto &s = m->sigs[sig.name.c_str()]; - s = sig; - emit signalAdded(id.address, &s); + if (auto m = const_cast(msg(id.address))) { + m->sigs.push_back(sig); + auto s = &m->sigs.last(); + sortSignalsByAddress(m->sigs); + emit signalAdded(id.address, s); } } void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig) { - if (auto m = const_cast(msg(id))) { - // change key name - QString new_name = QString::fromStdString(sig.name); - auto node = m->sigs.extract(sig_name); - node.key() = new_name; - auto it = m->sigs.insert(std::move(node)); - auto &s = m->sigs[new_name]; - s = sig; - emit signalUpdated(&s); + if (auto m = const_cast(msg(id))) { + if (auto s = (Signal *)m->sig(sig_name)) { + *s = sig; + sortSignalsByAddress(m->sigs); + emit signalUpdated(s); + } } } void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { - if (auto m = const_cast(msg(id))) { - auto it = m->sigs.find(sig_name); + if (auto m = const_cast(msg(id))) { + auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [&](auto &s) { return s.name == sig_name; }); if (it != m->sigs.end()) { - emit signalRemoved(&(it->second)); + emit signalRemoved(&(*it)); m->sigs.erase(it); } } @@ -108,16 +157,6 @@ DBCManager *dbc() { return &dbc_manager; } -// DBCMsg - -std::vector DBCMsg::getSignals() const { - std::vector ret; - ret.reserve(sigs.size()); - for (auto &[_, 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 = []() { @@ -128,13 +167,8 @@ static QVector BIG_ENDIAN_START_BITS = []() { return ret; }(); -int bigEndianStartBitsIndex(int start_bit) { - return BIG_ENDIAN_START_BITS[start_bit]; -} - -int bigEndianBitIndex(int index) { - return BIG_ENDIAN_START_BITS.indexOf(index); -} +int bigEndianStartBitsIndex(int start_bit) { return BIG_ENDIAN_START_BITS[start_bit]; } +int bigEndianBitIndex(int index) { return BIG_ENDIAN_START_BITS.indexOf(index); } double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) { int64_t val = 0; @@ -155,8 +189,7 @@ double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) { if (sig.is_signed) { val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0; } - double value = val * sig.factor + sig.offset; - return value; + return val * sig.factor + sig.offset; } void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size) { @@ -182,5 +215,50 @@ bool operator==(const Signal &l, const Signal &r) { l.start_bit == r.start_bit && l.msb == r.msb && l.lsb == r.lsb && l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian && - l.factor == r.factor && l.offset == r.offset; + l.factor == r.factor && l.offset == r.offset && + l.min == r.min && l.max == r.max && l.comment == r.comment && l.unit == r.unit && l.val_desc == r.val_desc; +} + +} // namespace dbcmanager + +#include "opendbc/can/common_dbc.h" +std::vector dbcmanager::DBCManager::allDBCNames() { return get_dbc_names(); } + +bool dbcmanager::DBCManager::open(const QString &name, const QString &content, QString *error) { + try { + std::istringstream stream(content.toStdString()); + auto dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); + msgs.clear(); + for (auto &msg : dbc->msgs) { + auto &m = msgs[msg.address]; + m.name = msg.name.c_str(); + m.size = msg.size; + for (auto &s : msg.sigs) { + m.sigs.push_back({}); + auto &sig = m.sigs.last(); + sig.name = s.name.c_str(); + sig.start_bit = s.start_bit; + sig.msb = s.msb; + sig.lsb = s.lsb; + sig.size = s.size; + sig.is_signed = s.is_signed; + sig.factor = s.factor; + sig.offset = s.offset; + sig.is_little_endian = s.is_little_endian; + } + sortSignalsByAddress(m.sigs); + } + parseExtraInfo(content); + name_ = name; + emit DBCFileChanged(); + delete dbc; + } catch (std::exception &e) { + if (error) *error = e.what(); + return false; + } + return true; +} + +uint qHash(const MessageId &item) { + return qHash(item.source) ^ qHash(item.address); } diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index b766c837b6..b438b3e1c2 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -1,9 +1,8 @@ #pragma once #include -#include +#include #include -#include "opendbc/can/common_dbc.h" struct MessageId { uint8_t source; @@ -30,40 +29,55 @@ struct MessageId { } }; +uint qHash(const MessageId &item); Q_DECLARE_METATYPE(MessageId); -uint qHash(const MessageId &item); +namespace dbcmanager { -struct DBCMsg { +typedef QList> ValueDescription; + +struct Signal { + QString name; + int start_bit, msb, lsb, size; + bool is_signed; + double factor, offset; + bool is_little_endian; + QString min, max, unit; + QString comment; + ValueDescription val_desc; +}; + +struct Msg { QString name; uint32_t size; - // signal must be saved as value in map to make undo stack work properly. - std::map sigs; - // return vector, sort by start_bits - std::vector getSignals() const; + QList sigs; + + const Signal *sig(const QString &sig_name) const { + auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; }); + return it != sigs.end() ? &(*it) : nullptr; + } }; class DBCManager : public QObject { Q_OBJECT public: - DBCManager(QObject *parent); - ~DBCManager(); - - void open(const QString &dbc_file_name); + DBCManager(QObject *parent) {} + ~DBCManager() {} + bool open(const QString &dbc_file_name, QString *error = nullptr); bool open(const QString &name, const QString &content, QString *error = nullptr); QString generateDBC(); void addSignal(const MessageId &id, const Signal &sig); void updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig); void removeSignal(const MessageId &id, const QString &sig_name); - inline static std::vector allDBCNames() { return get_dbc_names(); } - inline QString name() const { return dbc ? dbc->name.c_str() : ""; } + static std::vector allDBCNames(); + inline QString name() const { return name_; } void updateMsg(const MessageId &id, const QString &name, uint32_t size); void removeMsg(const MessageId &id); - inline const std::map &messages() const { return msgs; } - inline const DBCMsg *msg(const MessageId &id) const { return msg(id.address); } - inline const DBCMsg *msg(uint32_t address) const { + inline const std::map &messages() const { return msgs; } + inline const Msg *msg(const MessageId &id) const { return msg(id.address); } + inline const Msg *msg(uint32_t address) const { auto it = msgs.find(address); return it != msgs.end() ? &it->second : nullptr; } @@ -77,9 +91,9 @@ signals: void DBCFileChanged(); private: - void initMsgMap(); - DBC *dbc = nullptr; - std::map msgs; + void parseExtraInfo(const QString &content); + std::map msgs; + QString name_; }; const QString UNTITLED = "untitled"; @@ -97,3 +111,5 @@ inline QString msgName(const MessageId &id) { auto msg = dbc()->msg(id); return msg ? msg->name : UNTITLED; } + +} // namespace dbcmanager diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index f290b3b706..882ea932c6 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -6,8 +6,6 @@ #include #include "tools/cabana/commands.h" -#include "tools/cabana/dbcmanager.h" -#include "tools/cabana/streams/abstractstream.h" // DetailWidget @@ -153,13 +151,13 @@ void DetailWidget::refresh() { if (!msg_id) return; QStringList warnings; - const DBCMsg *msg = dbc()->msg(*msg_id); + auto msg = dbc()->msg(*msg_id); if (msg) { if (msg->size != can->lastMessage(*msg_id).dat.size()) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } for (auto s : binary_view->getOverlappingSignals()) { - warnings.push_back(tr("%1 has overlapping bits.").arg(s->name.c_str())); + warnings.push_back(tr("%1 has overlapping bits.").arg(s->name)); } } else { warnings.push_back(tr("Drag-Select in binary view to create new signal.")); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 87968d495c..a1c671b68d 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -5,6 +5,7 @@ #include #include "tools/cabana/commands.h" +#include "tools/cabana/util.h" // HistoryLogModel @@ -30,7 +31,7 @@ void HistoryLogModel::refresh() { beginResetModel(); sigs.clear(); if (auto dbc_msg = dbc()->msg(*msg_id)) { - sigs = dbc_msg->getSignals(); + sigs = dbc_msg->sigs; } last_fetch_time = 0; has_more_data = true; @@ -47,9 +48,9 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return show_signals ? QString::fromStdString(sigs[section - 1]->name).replace('_', ' ') : "Data"; + return show_signals ? sigs[section - 1].name : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { - return QBrush(getColor(sigs[section - 1])); + return QBrush(getColor(&sigs[section - 1])); } } return {}; @@ -113,7 +114,7 @@ std::deque HistoryLogModel::fetchData(InputIt first, I if (msg_id->address == c.getAddress() && msg_id->source == c.getSrc()) { const auto dat = c.getDat(); for (int i = 0; i < sigs.size(); ++i) { - values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *(sigs[i])); + values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), sigs[i]); } if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { auto &m = msgs.emplace_back(); @@ -170,8 +171,8 @@ QSize HeaderView::sectionSizeFromContents(int logicalIndex) const { return time_col_size; } else { int default_size = qMax(100, (rect().width() - time_col_size.width()) / (model()->columnCount() - 1)); - const QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); - const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text); + QString text = model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString(); + const QRect rect = fontMetrics().boundingRect({0, 0, default_size, 2000}, defaultAlignment(), text.replace(QChar('_'), ' ')); QSize size = rect.size() + QSize{10, 6}; return QSize{qMax(size.width(), default_size), size.height()}; } @@ -183,7 +184,7 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI painter->fillRect(rect, bg_role.value()); } QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString(); - painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text); + painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text.replace(QChar('_'), ' ')); } // LogsWidget @@ -253,8 +254,8 @@ void LogsWidget::refresh() { bool has_signal = model->sigs.size(); if (has_signal) { signals_cb->clear(); - for (auto s : model->sigs) { - signals_cb->addItem(s->name.c_str()); + for (auto &s : model->sigs) { + signals_cb->addItem(s.name); } } value_edit->clear(); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 00a8f73836..a1b7bc0098 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -11,6 +11,7 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class HeaderView : public QHeaderView { public: @@ -63,7 +64,7 @@ public: uint64_t last_fetch_time = 0; std::function filter_cmp = nullptr; std::deque messages; - std::vector sigs; + QList sigs; bool dynamic_mode = true; bool display_signals_mode = true; }; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 81ebc6af20..42ac22865c 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -7,8 +7,6 @@ #include #include -#include "tools/cabana/dbcmanager.h" - MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); @@ -140,8 +138,8 @@ void MessageListModel::setFilterString(const QString &string) { if (id.toString().contains(txt, cs) || msgName(id).contains(txt, cs)) return true; // Search by signal name if (const auto msg = dbc()->msg(id)) { - for (auto &signal : msg->getSignals()) { - if (QString::fromStdString(signal->name).contains(txt, cs)) return true; + for (auto &signal : msg->sigs) { + if (signal.name.contains(txt, cs)) return true; } } return false; diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 562069c3ae..d88def3acb 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -9,7 +9,9 @@ #include #include +#include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class MessageListModel : public QAbstractTableModel { Q_OBJECT diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index e2be5c85d0..d5099da6f4 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,5 +1,6 @@ #include "tools/cabana/signaledit.h" +#include #include #include #include @@ -23,9 +24,9 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p } void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig) { - Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name.c_str(), .type = Item::Sig}; + Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name, .type = Item::Sig}; parent_item->children.insert(pos, item); - QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum", "Maximum", "Description"}; + QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"}; for (int i = 0; i < std::size(titles); ++i) { item->children.push_back(new Item{.sig = sig, .parent = item, .title = titles[i], .type = (Item::Type)(i + Item::Name)}); } @@ -47,9 +48,9 @@ void SignalModel::refresh() { beginResetModel(); root.reset(new SignalModel::Item); if (auto msg = dbc()->msg(msg_id)) { - for (auto &s : msg->getSignals()) { - if (filter_str.isEmpty() || QString::fromStdString(s->name).contains(filter_str, Qt::CaseInsensitive)) { - insertItem(root.get(), root->children.size(), s); + for (auto &s : msg->sigs) { + if (filter_str.isEmpty() || s.name.contains(filter_str, Qt::CaseInsensitive)) { + insertItem(root.get(), root->children.size(), &s); } } } @@ -115,14 +116,25 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { const Item *item = getItem(index); if (role == Qt::DisplayRole || role == Qt::EditRole) { if (index.column() == 0) { - return item->type == Item::Sig ? QString::fromStdString(item->sig->name) : item->title; + return item->type == Item::Sig ? item->sig->name : item->title; } else { switch (item->type) { case Item::Sig: return item->sig_val; - case Item::Name: return QString::fromStdString(item->sig->name); + case Item::Name: return item->sig->name; case Item::Size: return item->sig->size; case Item::Offset: return QString::number(item->sig->offset, 'f', 6); case Item::Factor: return QString::number(item->sig->factor, 'f', 6); + case Item::Unit: return item->sig->unit; + case Item::Comment: return item->sig->comment; + case Item::Min: return item->sig->min; + case Item::Max: return item->sig->max; + case Item::Desc: { + QString val_desc; + for (auto &[val, desc] : item->sig->val_desc) { + val_desc += QString("%1 \"%2\"").arg(val, desc); + } + return val_desc; + } default: break; } } @@ -142,12 +154,17 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r Item *item = getItem(index); Signal s = *item->sig; switch (item->type) { - case Item::Name: s.name = value.toString().toStdString(); break; + case Item::Name: s.name = value.toString(); break; case Item::Size: s.size = value.toInt(); break; case Item::Endian: s.is_little_endian = value.toBool(); break; case Item::Signed: s.is_signed = value.toBool(); break; case Item::Offset: s.offset = value.toDouble(); break; case Item::Factor: s.factor = value.toDouble(); break; + case Item::Unit: s.unit = value.toString(); break; + case Item::Comment: s.comment = value.toString(); break; + case Item::Min: s.min = value.toString(); break; + case Item::Max: s.max = value.toString(); break; + case Item::Desc: s.val_desc = value.value(); break; default: return false; } bool ret = saveSignal(item->sig, s); @@ -172,8 +189,8 @@ void SignalModel::showExtraInfo(const QModelIndex &index) { bool SignalModel::saveSignal(const Signal *origin_s, Signal &s) { auto msg = dbc()->msg(msg_id); - if (s.name != origin_s->name && msg->sigs.count(s.name.c_str()) != 0) { - QString text = tr("There is already a signal with the same name '%1'").arg(s.name.c_str()); + if (s.name != origin_s->name && msg->sig(s.name) != nullptr) { + QString text = tr("There is already a signal with the same name '%1'").arg(s.name); QMessageBox::warning(nullptr, tr("Failed to save signal"), text); return false; } @@ -212,8 +229,8 @@ void SignalModel::addSignal(int start_bit, int size, bool 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; + sig.name = QString("NEW_SIGNAL_%1").arg(i); + if (msg->sig(sig.name) == nullptr) break; } updateSigSizeParamsFromRange(sig, start_bit, size); UndoStack::push(new AddSigCommand(msg_id, sig)); @@ -266,8 +283,8 @@ void SignalModel::handleSignalRemoved(const Signal *sig) { SignalItemDelegate::SignalItemDelegate(QObject *parent) { name_validator = new NameValidator(this); double_validator = new QDoubleValidator(this); - small_font.setPointSize(8); double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system + small_font.setPointSize(8); } void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -304,7 +321,8 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (SignalModel::Item *)index.internalPointer(); - if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Offset || item->type == SignalModel::Item::Factor) { + if (item->type == SignalModel::Item::Name || item->type == SignalModel::Item::Offset || + item->type == SignalModel::Item::Factor || item->type == SignalModel::Item::Min || item->type == SignalModel::Item::Max) { QLineEdit *e = new QLineEdit(parent); e->setFrame(false); e->setValidator(index.row() == 0 ? name_validator : double_validator); @@ -314,6 +332,13 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie spin->setFrame(false); spin->setRange(1, 64); return spin; + } else if (item->type == SignalModel::Item::Desc) { + ValueDescriptionDlg dlg(item->sig->val_desc, parent); + dlg.setWindowTitle(item->sig->name); + if (dlg.exec()) { + ((QAbstractItemModel *)index.model())->setData(index, QVariant::fromValue(dlg.val_desc)); + } + return nullptr; } return QStyledItemDelegate::createEditor(parent, option, index); } @@ -437,7 +462,7 @@ void SignalView::expandSignal(const Signal *sig) { void SignalView::updateChartState() { int i = 0; for (auto item : model->root->children) { - auto plot_btn = tree->indexWidget(model->index(i, 1))->findChildren()[0]; + auto plot_btn = tree->indexWidget(model->index(i, 1))->findChildren()[0]; bool chart_opened = charts->hasSignal(msg_id, item->sig); plot_btn->setChecked(chart_opened); plot_btn->setToolTip(chart_opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened plot")); @@ -459,3 +484,70 @@ void SignalView::leaveEvent(QEvent *event) { emit highlight(nullptr); QWidget::leaveEvent(event); } + +// ValueDescriptionDlg + +ValueDescriptionDlg::ValueDescriptionDlg(const ValueDescription &descriptions, QWidget *parent) : QDialog(parent) { + QHBoxLayout *toolbar_layout = new QHBoxLayout(); + QPushButton *add = new QPushButton(utils::icon("plus"), ""); + QPushButton *remove = new QPushButton(utils::icon("dash"), ""); + remove->setEnabled(false); + toolbar_layout->addWidget(add); + toolbar_layout->addWidget(remove); + toolbar_layout->addStretch(0); + + table = new QTableWidget(descriptions.size(), 2, this); + table->setItemDelegate(new Delegate(this)); + table->setHorizontalHeaderLabels({"Value", "Description"}); + table->horizontalHeader()->setStretchLastSection(true); + table->setSelectionBehavior(QAbstractItemView::SelectRows); + table->setSelectionMode(QAbstractItemView::SingleSelection); + table->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); + table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + int row = 0; + for (auto &[val, desc] : descriptions) { + table->setItem(row, 0, new QTableWidgetItem(val)); + table->setItem(row, 1, new QTableWidgetItem(desc)); + ++row; + } + + auto btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->addLayout(toolbar_layout); + main_layout->addWidget(table); + main_layout->addWidget(btn_box); + setMinimumWidth(500); + + QObject::connect(btn_box, &QDialogButtonBox::accepted, this, &ValueDescriptionDlg::save); + QObject::connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); + QObject::connect(add, &QPushButton::clicked, [this]() { + table->setRowCount(table->rowCount() + 1); + table->setItem(table->rowCount() - 1, 0, new QTableWidgetItem); + table->setItem(table->rowCount() - 1, 1, new QTableWidgetItem); + }); + QObject::connect(remove, &QPushButton::clicked, [this]() { table->removeRow(table->currentRow()); }); + QObject::connect(table, &QTableWidget::itemSelectionChanged, [=]() { + remove->setEnabled(table->currentRow() != -1); + }); +} + +void ValueDescriptionDlg::save() { + for (int i = 0; i < table->rowCount(); ++i) { + QString val = table->item(i, 0)->text().trimmed(); + QString desc = table->item(i, 1)->text().trimmed(); + if (!val.isEmpty() && !desc.isEmpty()) { + val_desc.push_back({val, desc}); + } + } + QDialog::accept(); +} + +QWidget *ValueDescriptionDlg::Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + QLineEdit *edit = new QLineEdit(parent); + edit->setFrame(false); + if (index.column() == 0) { + edit->setValidator(new QIntValidator(edit)); + } + return edit; +} diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 7e5015f707..efdc653584 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -4,11 +4,10 @@ #include #include #include +#include #include #include "tools/cabana/chartswidget.h" -#include "tools/cabana/dbcmanager.h" -#include "tools/cabana/streams/abstractstream.h" class SignalModel : public QAbstractItemModel { Q_OBJECT @@ -62,6 +61,21 @@ private: friend class SignalView; }; +class ValueDescriptionDlg : public QDialog { +public: + ValueDescriptionDlg(const ValueDescription &descriptions, QWidget *parent); + ValueDescription val_desc; + +private: + struct Delegate : public QStyledItemDelegate { + Delegate(QWidget *parent) : QStyledItemDelegate(parent) {} + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + }; + + void save(); + QTableWidget *table; +}; + class SignalItemDelegate : public QStyledItemDelegate { public: SignalItemDelegate(QObject *parent); diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index b768b94327..ebd969be61 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -1,7 +1,5 @@ #include "tools/cabana/streams/replaystream.h" -#include "tools/cabana/dbcmanager.h" - ReplayStream::ReplayStream(uint32_t replay_flags, QObject *parent) : replay_flags(replay_flags), AbstractStream(parent, false) { QObject::connect(&settings, &Settings::changed, [this]() { if (replay) replay->setSegmentCacheLimit(settings.max_cached_minutes); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 69fb738ab8..3505f6abf4 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -1,6 +1,5 @@ #pragma once -#include "opendbc/can/common_dbc.h" #include "tools/cabana/streams/abstractstream.h" #include "tools/cabana/settings.h" diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 586422ffc8..9a8ab710bc 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -2,8 +2,10 @@ #include "opendbc/can/common.h" #undef INFO #include "catch2/catch.hpp" -#include "tools/cabana/dbcmanager.h" #include "tools/replay/logreader.h" +#include "tools/cabana/dbcmanager.h" +#include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; // demo route, first segment const std::string TEST_RLOG_URL = "https://commadata2.blob.core.windows.net/commadata2/4cf7a6ad03080c90/2021-09-29--13-46-36/0/rlog.bz2"; @@ -18,12 +20,13 @@ TEST_CASE("DBCManager::generateDBC") { auto &new_msgs = dbc_from_generated.messages(); REQUIRE(msgs.size() == new_msgs.size()); for (auto &[address, m] : msgs) { - auto new_m = new_msgs.at(address); + auto &new_m = new_msgs.at(address); REQUIRE(m.name == new_m.name); REQUIRE(m.size == new_m.size); REQUIRE(m.sigs.size() == new_m.sigs.size()); - for (auto &[name, sig] : m.sigs) - REQUIRE(sig == new_m.sigs[name]); + for (int i = 0; i < m.sigs.size(); ++i) { + REQUIRE(m.sigs[i] == new_m.sigs[i]); + } } } @@ -37,13 +40,13 @@ TEST_CASE("Parse can messages") { REQUIRE(log.events.size() > 0); for (auto e : log.events) { if (e->which == cereal::Event::Which::CAN) { - std::map, std::vector> values_1; + std::map, std::vector> values_1; for (const auto &c : e->event.getCan()) { const auto msg = dbc.msg(c.getAddress()); if (c.getSrc() == 0 && msg) { - for (auto &[name, sig] : msg->sigs) { + for (auto &sig : msg->sigs) { double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), sig); - values_1[{c.getAddress(), name.toStdString()}].push_back(val); + values_1[{c.getAddress(), sig.name}].push_back(val); } } } @@ -53,7 +56,7 @@ TEST_CASE("Parse can messages") { for (auto &[key, v1] : values_1) { bool found = false; for (auto &v2 : values_2) { - if (v2.address == key.first && v2.name == key.second) { + if (v2.address == key.first && key.second == v2.name.c_str()) { REQUIRE(v2.all_values.size() == v1.size()); REQUIRE(v2.all_values == v1); found = true; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index ffb0e54b0e..27cb7bced8 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -9,6 +9,7 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) { setWindowTitle(tr("Find similar bits")); diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 53d7806a8f..ba9b063baf 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -7,6 +7,7 @@ #include #include "tools/cabana/dbcmanager.h" +using namespace dbcmanager; class FindSimilarBitsDlg : public QDialog { Q_OBJECT diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 9843a3f00c..6415cc8e16 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -106,7 +106,7 @@ QColor getColor(const Signal *sig) { float h = 19 * (float)sig->lsb / 64.0; h = fmod(h, 1.0); - size_t hash = qHash(QString::fromStdString(sig->name)); + size_t hash = qHash(sig->name); float s = 0.25 + 0.25 * (float)(hash & 0xff) / 255.0; float v = 0.75 + 0.25 * (float)((hash >> 8) & 0xff) / 255.0; diff --git a/tools/cabana/util.h b/tools/cabana/util.h index eb5203fb0b..2717451061 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -9,7 +9,9 @@ #include #include -#include "opendbc/can/common_dbc.h" +#include "tools/cabana/dbcmanager.h" +using namespace dbcmanager; + class ChangeTracker { public: @@ -37,7 +39,7 @@ public: inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } -QColor getColor(const Signal *sig); +QColor getColor(const dbcmanager::Signal *sig); class NameValidator : public QRegExpValidator { Q_OBJECT diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 51197eedd6..1a7e27f1b3 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -11,7 +11,9 @@ #include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/qt/widgets/controls.h" +#include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +using namespace dbcmanager; class Slider : public QSlider { Q_OBJECT From eb8bdc0026b49de2fc5107746baeadbd42f58550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 17 Feb 2023 19:58:30 -0800 Subject: [PATCH 0976/1179] MPC path in UI (#27380) * 10s lat * Full length MPC * redfine N * Leave controls the same for now * Updates * use long plan in lat plan * interp plan * simplergit add selfdrive/controls/plannerd.py selfdrive/controls/ * expand to 10s * revert this * fix linter * vizualize * fix long test * typo * cleanup * compiles * unused * unused * bump cereal * bump cereal * use model if no uiplanm * update replay * update ref commit * bump cereal to master --- cereal | 2 +- .../controls/lib/longitudinal_planner.py | 3 ++- selfdrive/controls/plannerd.py | 20 +++++++++++++++-- selfdrive/modeld/models/driving.cc | 4 ++-- .../test/longitudinal_maneuvers/plant.py | 6 ++--- .../test/process_replay/process_replay.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- selfdrive/ui/qt/maps/map_helpers.cc | 2 +- selfdrive/ui/qt/maps/map_helpers.h | 2 +- selfdrive/ui/qt/onroad.cc | 2 +- selfdrive/ui/ui.cc | 22 ++++++++++++------- selfdrive/ui/ui.h | 10 +++++---- 12 files changed, 51 insertions(+), 26 deletions(-) diff --git a/cereal b/cereal index 162a26ca2d..b88523f05a 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 162a26ca2d7e5bc9a42bb5ea11e98194f722027b +Subproject commit b88523f05ac958f87a8f6d57c3f4bb20da55f216 diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 0febfbafd9..2ef9051122 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -121,7 +121,8 @@ class LongitudinalPlanner: x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error) self.mpc.update(sm['radarState'], v_cruise, x, v, a, j) - self.v_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.v_solution) + self.v_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.v_solution) + self.v_desired_trajectory = self.v_desired_trajectory_full[:CONTROL_N] self.a_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.a_solution) self.j_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC[:-1], self.mpc.j_solution) diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 93d0c80dac..543274d841 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -1,12 +1,28 @@ #!/usr/bin/env python3 +import numpy as np from cereal import car from common.params import Params from common.realtime import Priority, config_realtime_process from system.swaglog import cloudlog +from selfdrive.modeld.constants import T_IDXS from selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner from selfdrive.controls.lib.lateral_planner import LateralPlanner import cereal.messaging as messaging +def cumtrapz(x, t): + return np.concatenate([[0], np.cumsum(((x[0:-1] + x[1:])/2) * np.diff(t))]) + +def publish_ui_plan(sm, pm, lateral_planner, longitudinal_planner): + plan_odo = cumtrapz(longitudinal_planner.v_desired_trajectory_full, T_IDXS) + model_odo = cumtrapz(lateral_planner.v_plan, T_IDXS) + + ui_send = messaging.new_message('uiPlan') + ui_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'modelV2']) + uiPlan = ui_send.uiPlan + uiPlan.position.x = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,0]).tolist() + uiPlan.position.y = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,1]).tolist() + uiPlan.position.z = np.interp(plan_odo, model_odo, lateral_planner.path_xyz[:,2]).tolist() + pm.send('uiPlan', ui_send) def plannerd_thread(sm=None, pm=None): config_realtime_process(5, Priority.CTRL_LOW) @@ -24,7 +40,7 @@ def plannerd_thread(sm=None, pm=None): poll=['radarState', 'modelV2'], ignore_avg_freq=['radarState']) if pm is None: - pm = messaging.PubMaster(['longitudinalPlan', 'lateralPlan']) + pm = messaging.PubMaster(['longitudinalPlan', 'lateralPlan', 'uiPlan']) while True: sm.update() @@ -34,7 +50,7 @@ def plannerd_thread(sm=None, pm=None): lateral_planner.publish(sm, pm) longitudinal_planner.update(sm) longitudinal_planner.publish(sm, pm) - + publish_ui_plan(sm, pm, lateral_planner, longitudinal_planner) def main(sm=None, pm=None): plannerd_thread(sm, pm) diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index ac101bfee7..5538d6ff9b 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -200,7 +200,7 @@ void fill_meta(cereal::ModelDataV2::MetaData::Builder meta, const ModelOutputMet } template -void fill_xyzt(cereal::ModelDataV2::XYZTData::Builder xyzt, const std::array &t, +void fill_xyzt(cereal::XYZTData::Builder xyzt, const std::array &t, const std::array &x, const std::array &y, const std::array &z) { xyzt.setT(to_kj_array_ptr(t)); xyzt.setX(to_kj_array_ptr(x)); @@ -209,7 +209,7 @@ void fill_xyzt(cereal::ModelDataV2::XYZTData::Builder xyzt, const std::array -void fill_xyzt(cereal::ModelDataV2::XYZTData::Builder xyzt, const std::array &t, +void fill_xyzt(cereal::XYZTData::Builder xyzt, const std::array &t, const std::array &x, const std::array &y, const std::array &z, const std::array &x_std, const std::array &y_std, const std::array &z_std) { fill_xyzt(xyzt, t, x, y, z); diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index bd0556aa07..8febbf4022 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -99,13 +99,13 @@ class Plant: # Simulate model predicting slightly faster speed # this is to ensure lead policy is effective when model # does not predict slowdown in e2e mode - position = log.ModelDataV2.XYZTData.new_message() + position = log.XYZTData.new_message() position.x = [float(x) for x in (self.speed + 0.5) * np.array(T_IDXS)] model.modelV2.position = position - velocity = log.ModelDataV2.XYZTData.new_message() + velocity = log.XYZTData.new_message() velocity.x = [float(x) for x in (self.speed + 0.5) * np.ones_like(T_IDXS)] model.modelV2.velocity = velocity - acceleration = log.ModelDataV2.XYZTData.new_message() + acceleration = log.XYZTData.new_message() acceleration.x = [float(x) for x in np.zeros_like(T_IDXS)] model.modelV2.acceleration = acceleration diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 28fc9c452c..7dc0b139a3 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -292,7 +292,7 @@ CONFIGS = [ ProcessConfig( proc_name="plannerd", pub_sub={ - "modelV2": ["lateralPlan", "longitudinalPlan"], + "modelV2": ["lateralPlan", "longitudinalPlan", "uiPlan"], "carControl": [], "carState": [], "controlsState": [], "radarState": [], }, ignore=["logMonoTime", "valid", "longitudinalPlan.processingDelay", "longitudinalPlan.solverExecutionTime", "lateralPlan.solverExecutionTime"], diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 4a670b11ff..e9016cc27c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -086896986a3fcdb1a03d9afd00a9abc928f9ef25 +70753c5f491de7432ff22f4ef560820ce9919b2e diff --git a/selfdrive/ui/qt/maps/map_helpers.cc b/selfdrive/ui/qt/maps/map_helpers.cc index 8d5d4e1715..95db4f2bbd 100644 --- a/selfdrive/ui/qt/maps/map_helpers.cc +++ b/selfdrive/ui/qt/maps/map_helpers.cc @@ -31,7 +31,7 @@ QGeoCoordinate to_QGeoCoordinate(const QMapbox::Coordinate &in) { QMapbox::CoordinatesCollections model_to_collection( const cereal::LiveLocationKalman::Measurement::Reader &calibratedOrientationECEF, const cereal::LiveLocationKalman::Measurement::Reader &positionECEF, - const cereal::ModelDataV2::XYZTData::Reader &line){ + const cereal::XYZTData::Reader &line){ Eigen::Vector3d ecef(positionECEF.getValue()[0], positionECEF.getValue()[1], positionECEF.getValue()[2]); Eigen::Vector3d orient(calibratedOrientationECEF.getValue()[0], calibratedOrientationECEF.getValue()[1], calibratedOrientationECEF.getValue()[2]); diff --git a/selfdrive/ui/qt/maps/map_helpers.h b/selfdrive/ui/qt/maps/map_helpers.h index 6bd5b0f067..f9c56107e3 100644 --- a/selfdrive/ui/qt/maps/map_helpers.h +++ b/selfdrive/ui/qt/maps/map_helpers.h @@ -20,7 +20,7 @@ QGeoCoordinate to_QGeoCoordinate(const QMapbox::Coordinate &in); QMapbox::CoordinatesCollections model_to_collection( const cereal::LiveLocationKalman::Measurement::Reader &calibratedOrientationECEF, const cereal::LiveLocationKalman::Measurement::Reader &positionECEF, - const cereal::ModelDataV2::XYZTData::Reader &line); + const cereal::XYZTData::Reader &line); QMapbox::CoordinatesCollections coordinate_to_collection(const QMapbox::Coordinate &c); QMapbox::CoordinatesCollections capnp_coordinate_list_to_collection(const capnp::List::Reader &coordinate_list); QMapbox::CoordinatesCollections coordinate_list_to_collection(const QList &coordinate_list); diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 33b1ea8e27..98c636b0a4 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -674,7 +674,7 @@ void AnnotatedCameraWidget::paintGL() { if (s->worldObjectsVisible()) { if (sm.rcv_frame("modelV2") > s->scene.started_frame) { - update_model(s, sm["modelV2"].getModelV2()); + update_model(s, sm["modelV2"].getModelV2(), sm["uiPlan"].getUiPlan()); if (sm.rcv_frame("radarState") > s->scene.started_frame) { update_leads(s, radar_state, sm["modelV2"].getModelV2().getPosition()); } diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 6c850b8ca4..50843de68e 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -35,7 +35,7 @@ static bool calib_frame_to_full_frame(const UIState *s, float in_x, float in_y, return false; } -int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height) { +int get_path_length_idx(const cereal::XYZTData::Reader &line, const float path_height) { const auto line_x = line.getX(); int max_idx = 0; for (int i = 1; i < TRAJECTORY_SIZE && line_x[i] <= path_height; ++i) { @@ -44,7 +44,7 @@ int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const return max_idx; } -void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::ModelDataV2::XYZTData::Reader &line) { +void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line) { for (int i = 0; i < 2; ++i) { auto lead_data = (i == 0) ? radar_state.getLeadOne() : radar_state.getLeadTwo(); if (lead_data.getStatus()) { @@ -54,7 +54,7 @@ void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, con } } -void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, +void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) { const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ(); QPolygonF left_points, right_points; @@ -79,10 +79,15 @@ void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Rea *pvd = left_points + right_points; } -void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { +void update_model(UIState *s, + const cereal::ModelDataV2::Reader &model, + const cereal::UiPlan::Reader &plan) { UIScene &scene = s->scene; - auto model_position = model.getPosition(); - float max_distance = std::clamp(model_position.getX()[TRAJECTORY_SIZE - 1], + auto plan_position = plan.getPosition(); + if (plan_position.getX().size() < TRAJECTORY_SIZE){ + plan_position = model.getPosition(); + } + float max_distance = std::clamp(plan_position.getX()[TRAJECTORY_SIZE - 1], MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); // update lane lines @@ -108,8 +113,8 @@ void update_model(UIState *s, const cereal::ModelDataV2::Reader &model) { const float lead_d = lead_one.getDRel() * 2.; max_distance = std::clamp((float)(lead_d - fmin(lead_d * 0.35, 10.)), 0.0f, max_distance); } - max_idx = get_path_length_idx(model_position, max_distance); - update_line_data(s, model_position, 0.9, 1.22, &scene.track_vertices, max_idx, false); + max_idx = get_path_length_idx(plan_position, max_distance); + update_line_data(s, plan_position, 0.9, 1.22, &scene.track_vertices, max_idx, false); } void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd) { @@ -248,6 +253,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "gnssMeasurements", + "uiPlan", }); Params params; diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index e3eb97a762..ad2a1fe1f4 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -198,9 +198,11 @@ public slots: }; void ui_update_params(UIState *s); -int get_path_length_idx(const cereal::ModelDataV2::XYZTData::Reader &line, const float path_height); -void update_model(UIState *s, const cereal::ModelDataV2::Reader &model); +int get_path_length_idx(const cereal::XYZTData::Reader &line, const float path_height); +void update_model(UIState *s, + const cereal::ModelDataV2::Reader &model, + const cereal::UiPlan::Reader &plan); void update_dmonitoring(UIState *s, const cereal::DriverStateV2::Reader &driverstate, float dm_fade_state, bool is_rhd); -void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::ModelDataV2::XYZTData::Reader &line); -void update_line_data(const UIState *s, const cereal::ModelDataV2::XYZTData::Reader &line, +void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line); +void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert); From 7acb4a94cc77a5d2b19b86fccdf373489bcb6f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 17 Feb 2023 20:12:31 -0800 Subject: [PATCH 0977/1179] Update RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index ff5b686e0c..0ea4241a35 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,6 @@ Version 0.9.2 (2023-03-XX) ======================== - +* Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. Version 0.9.1 (2023-02-23) ======================== From 8d9f99b835aeb0d317337d1f87a961e75f8d6468 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 18 Feb 2023 21:48:13 -0800 Subject: [PATCH 0978/1179] cabana: add space to help message (#27384) add space --- tools/cabana/mainwin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 07d37df4e4..2cba29bf5e 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -176,7 +176,7 @@ void MainWindow::createStatusBar() { progress_bar->setTextVisible(true); progress_bar->setFixedSize({230, 16}); progress_bar->setVisible(false); - statusBar()->addWidget(new QLabel(tr("For Help,Press F1"))); + statusBar()->addWidget(new QLabel(tr("For Help, Press F1"))); statusBar()->addPermanentWidget(progress_bar); } From 8e3cb0fb2075cc0e21f0362dad467cd992291c3a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 20 Feb 2023 07:14:13 +0800 Subject: [PATCH 0979/1179] cabana: add qrc resource file (#27386) * add qrc resource file * remove export --- selfdrive/ui/SConscript | 1 - tools/cabana/SConscript | 10 ++++++++-- tools/cabana/assets/.gitignore | 1 + tools/cabana/assets/assets.qrc | 5 +++++ 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 tools/cabana/assets/.gitignore create mode 100644 tools/cabana/assets/assets.qrc diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 0f28f5ccc3..a8c8463bd7 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -42,7 +42,6 @@ assets_src = "#selfdrive/assets/assets.qrc" qt_env.Command(assets, assets_src, f"rcc $SOURCES -o $TARGET") qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, "#selfdrive/assets/assets.o"])) asset_obj = qt_env.Object("assets", assets) -Export('asset_obj') # build soundd qt_env.Program("soundd/_soundd", ["soundd/main.cc", "soundd/sound.cc"], LIBS=qt_libs) diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index 166b3d5548..ddd6208c07 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -1,6 +1,6 @@ import os Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'replay_lib', - 'cereal', 'transformations', 'widgets', 'opendbc', 'asset_obj') + 'cereal', 'transformations', 'widgets', 'opendbc') base_frameworks = qt_env['FRAMEWORKS'] base_libs = [common, messaging, cereal, visionipc, transformations, 'zmq', @@ -20,11 +20,17 @@ cabana_env = qt_env.Clone() opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc").abspath) cabana_env['CXXFLAGS'] += [opendbc_path] +# build assets +assets = "assets/assets.cc" +assets_src = "assets/assets.qrc" +cabana_env.Command(assets, assets_src, f"rcc $SOURCES -o $TARGET") +cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "assets/assets.o"])) + prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', 'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) -cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, asset_obj], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) +cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if arch == "Darwin": cabana_env.Execute('install_name_tool -change opendbc/can/libdbc.dylib @loader_path/../../opendbc/can/libdbc.dylib ./_cabana') diff --git a/tools/cabana/assets/.gitignore b/tools/cabana/assets/.gitignore new file mode 100644 index 0000000000..283034ca8b --- /dev/null +++ b/tools/cabana/assets/.gitignore @@ -0,0 +1 @@ +*.cc diff --git a/tools/cabana/assets/assets.qrc b/tools/cabana/assets/assets.qrc new file mode 100644 index 0000000000..b42f2a82b1 --- /dev/null +++ b/tools/cabana/assets/assets.qrc @@ -0,0 +1,5 @@ + + + ../../../third_party/bootstrap/bootstrap-icons.svg + + From c7cc36d9ee22aea2e07aab61d51f0f949b64bcf5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 13:15:59 -0800 Subject: [PATCH 0980/1179] cabana: add window icon (#27109) * add logos * most zoomed in * add alt * slightly zoomed more * add images * add draft images * best image * not working * 96px icon image to reduce compiled size * remove from selfdrive assets * fixes --- tools/cabana/assets/assets.qrc | 1 + tools/cabana/assets/cabana-icon.png | Bin 0 -> 18008 bytes tools/cabana/cabana.cc | 1 + 3 files changed, 2 insertions(+) create mode 100644 tools/cabana/assets/cabana-icon.png diff --git a/tools/cabana/assets/assets.qrc b/tools/cabana/assets/assets.qrc index b42f2a82b1..6a8e5a3414 100644 --- a/tools/cabana/assets/assets.qrc +++ b/tools/cabana/assets/assets.qrc @@ -1,5 +1,6 @@ ../../../third_party/bootstrap/bootstrap-icons.svg + cabana-icon.png diff --git a/tools/cabana/assets/cabana-icon.png b/tools/cabana/assets/cabana-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..86add806fd1cabcd145ceef74a3995bc609d34fb GIT binary patch literal 18008 zcmV)CK*GO?P)PyA07*naRCr#^T?LpO<<)*iuIpY|_l+kcAwmLy1PB(S6iIO{MOw7Dv_%Wli&Lz4 za0`|YG(d>EZnCb|-R92x&pC59rTu|~mO=+MyLzg%c;yj0#)^6M0 z_Q9HM8a z#bb~}8KNj6ole7Mvq6$1IGs-PbanH0Nfe=K8edj89OmyPqft{8HL$65>st>$^}+*- zSFBhGpzyzN?LVjj#`yjAlYV;o&-UMY>ZJmNdY8+ETrP)1JOPi_14S*ePzMJCsHiAM zHk(0F(ICq*1VMlXjTPW_yOE41kV+}P-7GdEV%qCbY7Nk-sWV2Z)xja-&g)ECOnar?S zY$y~8{5KK$h*cDvLaZ9NO`di0@-7cX72_50ox-=_k^pPllPb5A<@sNV^I z!)PWU%ZNpzFv=3_4m+EgLa_*k!--5L4X@XOSS*TQFo=eRMub9PR903Z7E7Rz&%@<$ zK`APbL<6FcC@gj>3)ybBBQQ7sS(1>?=b$JGR8@u5>OdkMN0C0m=|Dc8MX{(tQvpeo zkjZ7cAA08bv!8wC^@ZP;BEAm=2-jb7;ROdDuG6Ap8$A%`K zFQB`#6T?T2Vz836UWR>XI%fL~p9$;opL-1iBC(Ih34323SUi-{0O2z7OJY`Z&Jx5Hmm1y8vj zW{VB!REmY?u-jQ!Mxzm3-JPhese##IK`xs`JQim=U0z;}LP0?|6hd`f4OF#=&dv_x zvss3vUay~>wW?}}Cz22}4TXG;g(@3N2m}YgyYkh{d6)Dl+LbOja|j zHajw@G@~HNAhUq1W)rXYd|rWp%#Fj2-tI1T@PqyRXlZIfAQ0s9NawPsuBnA48z9RP ztX3P+w3C7Z5H%Hg)g+Y?=@v`N2+;-2S*M3(@_)ZisdGzS2 zNALg3dVfWQhs=$lww;d(6H!Tz<)if*?qA!ep-ryVq7!A{vb# zl}@o!Ba=Z`-060~;c_7zjU$;#!tF1Ir_6^;Cdn5siV_Pvok^jxx)w&+fLJs}CV&H} zk)uapFc5&N%tH|_`Z~MW7o;;;6bgA%R#l>ZV33iL&1z?VU@{re-rmkiHd!njQPcZ& z_jF^@o|BNyrjbsk(ACw2VNJ~pYZVQ!*sLJ9+`eNwa;Y>#XpF)}j2Z=_(HuSM?9)fB zU*9(HpD5u!Qow~jJ@e$tFFfz*0!6RMBs?AuN2G&;{ivy`=2c4pmZBCQsC4pChytJq zK!v{?9o=2<_{*UxDhFe#svw)rFpA0M^K6R=YAX3Wl7xPs!DhF!qc(^}c>G?Zk}1ec zRghCH@_V>lE)4V!urDxMt^ByjXvSb)Kd)?)#e`TW!sdvaxXkx~@7~YK-IRfEe5Zzs!sI95RKwyB) z0ugFvgA73g67duSNrb<=9N|cm1G4^}9yB&Ipr@~&cThAIgV|_-)9vQnL@@;^hJre$ z!-jY)#!+r{bv45lQb;D9gWKsuHlG98CN-CbY&J4FB7ag=R>l!D`4d89sbm_WEW_jT zKr3o68jK7Ag24c6Rx6A)3!A-cHlzOT?gyqm_T0UQrHBEn;wB z0A7y=k}Sb&weZd&lSR9V0yDeSf^Z}ZNtR(U6KYbK;LD~mFq&lkoqz%DKzeTq+-TBUg&b*|g++E<$>i7!&<-MnmRDDzZQFL{ zaSBSF&BvCu4lMd?83N%Lws&+QkxH|GNH`SL`aET*uc^kNv-U%CLmk6egDfMT$-wD$ z@*)Wb11PT~N3SuWA_Nr(Qqbk#z|L;7vNP}Q>|!2@;tq=1%gS8n>+R*$PJtl#F*b{e z0%#f>b_X_X-HiIWM)iVU-#B{Bn$6#ePx@90IQyiz`~LF0vp*qwUteF3L?Xos7etZm zbCI^S(ZIHsPzDLf;c`MP7Lm*7urZU%B9qQAw9E0&Sq`d_sWcjg4MW?G?ab>C|MS7J zRd{W|BE*yW=j_fwbo7XpCj9oAD;ZU}%iJ&+4KT1AFqzQa*2X)t zzOjK`RnT~UmT~}L&&W=ugUq_h>W|JA+-JSWL{o=~14c*;3 z55616ZYyB)=+Ra4?)^iT+vS!*;V|rW2dq{Lb27A2%vLj-4yU_}p&i*>@&g8|3DHmp zF1LFp^dxv#U0I2(+qR;vwjN4RMPGj(n;U|u+d8{(%U$;)8c*!TC4BW$XqC>KHU($R zJ%*!R3hMY`RSk(m43!m?>|f|Qylyv}rBEcyE1eWj*VKf9T107yXd=i%5Rk&IKE6P$7MiB-Fs0NPyz$g393A26Fu9+kGR1|3ooybMQSu~}d? z8KjA2a;sI94CN1V&1nWiRMf>t=eXR_(ML(^$SR1_-^tx;87%k;Ns z5D^K7;BwlTKA|1l-Q9`$x_ZbaBMe3}1_lS1YszHvpUgUX?#$h}h}}}aN3TBr?ucQ{ zhxGOJGNDC?!)P$Eqa#~M*qaapIb(8kbdaMW0*!*0d@%>7vy1~QQcffsL{D2gY8vaI zXd>)R7h=gc&bsIdtlhYIch37;Kj++&=VHd>JyGUz@{S-IPQakKsR@E8p|YwP;ZT@? zf}_lhqN<{|tB27T?QnWcUvD3ifV7a*qKf|he)!A%fGk52B#x?+$rv<2!t*b^c;&C} zyz39UI?-J!;Oa{*IQg{Wj($4Hj#Po!W@RB0zIQoX$mg;gd|53PRsvDHw4w-6P+UNM zfN(#p@JuGfFfSSoQC0*tmy?4lRTJ>@8*ah2wvJt$?|=07Q-6FE4xPCVC~nE6GpMbt zfzf2-T!d2881+QLVbs^vF&U>8@|`;=(Y%(%WWh3*LNI-*%P;iiAg`Tb+)YR3Y zKmfzx)ajH&8reb)R;!uKDEYOe%a>!!_%Z#>lV??P#P>DFH!7f~b>nBbbZT$6OV7(v za)V5c*-Q*&j?If8XrS=6sDOn}KL-cT9nlcv7dE$U z$BAbX)BF7$fBo%E7(H?X;_(EUo0}mMb)CsVmIPGR)nl-?6SguZ!hr}zj2(+eFo;wv z%ruE48If1=Fq+KJ1QC^l2BTqE%yy}IIDW5*UGA>DlP+2{Y}TPxt4(@s0^ zj@y2{D4R?%Tr-;qS}GtvFl<;0`g?i_cruJ5p_f$>#_M1+o8WRfnbNkJOt6}baCys_ z#r4-zAsz@Z8A#Fh%P+lvDO08*lgVM^$Puu)%GhZq31}pu3~$XwGrBsvkWXjO*w}#O zpL~R2w0_0>xs1`49?9C@(8X0^+dGfe-d&ei|{OXRcL`7ezfD2DQ z>E{PcpL{O`CR}?X0uc(^1+XnoB;trh!(2LIFWsxROmU?jg5#0 z!*F`aIFM->F%ru@{REwDZK$ko#BC2hf%fj6A4CE4p=Td93m%sPCPFp&JhJIHYO1R+ zddwcoC&gn?5bQ3ms>GU=D=>WAcvwwFeE#`o*l+)Xkf6V-Dw|Ux=j>J+K3TMgfy&GS zXQO@FW_0anW8iV`OAE$yghHGC^AP@xkW?~wNix-U&E5qt= zGAF-j>o&mU$3w5Y^@A#aKKz);qhXRo*i2?PttLn%;6S#Vpf%Cw1fhwHBNC7jOH{wq z+uh5kNH&>ZFdGpG>iG^TpXurD;Q*E3X;*JIOrn5LID+@qcZ~?-a@)Rq(f_&wgkKys zBbF=V9ppTT9Gfz2I)Z)uoRlCki};Xr>(-&5s2DlC8J(SN7(RRiwrtsgrp6|;wzfhx znPD~>JG4v!we_`VZ|g*Lg^v+@PhTIJn}@MqAl6nYs))rx$mMhJR@NXAiNa(s zaC)?*Wf+2?0Qv_5$QKmMoH+}v+qUv^C|AC;E#L|R@u3UctFiWHlg8kv$H zG(}r9lg%TO%j1*Y=*}YAA6g3sk7)+MZ9-?`hBt6guK*c!ResLKb@vazY_Y>(w{Y;4 zj>q8lm7%A%4;8ib*xI@Ssz7XT2E&_%VQXtEa(T*)7j?uaima^QU=U`1`JD?lwO{j9 z3b3EQ{~ih1Xhm<|AVQ%SR6*eMTTN{ZJWdya!G354BMUehPr)DvXsYp}vA%&5CInHb zb|)N(Q_UsRVu5*mm(Ro01f>aScS(`~?|1$1=4VI<%`OY7Tz166VT@?5LugS?IhDU(5&+XBgA zzn_3`=l zyd@l>h7sj%Wa4pD`8`O*<1m>m)P#U^D#=A&ieNxTEzI)jydH=pX23Q@yk&GbWVJGbG)qfY~+94v1PkaT}xn!u|v| zDfLG*1aUutp@2|41&h;%o`DDir2vOnhTrRfld?{M09TfgNy_FjFdAf}iC-}okt--r zxllxd%jv?$-C?dg_+L0|l7I%g5l)K{`E(Wn2VYhwRC{Egw4I8qD5I&mg0GKq+-6zi z`lL`Q3z<@wiVE2P)YsHwpl<;6bv2x1vY1PidTIgbRGN|DU_ABMvQXjdFDt;Zuh)>K zNQ)drE?eLf9l=aWev?@ljD{f_HN+!n1hWNXxcEwgMbzLe({rbyq9PSb!eErSoI}eK zubzd=?Ls(4CQan@UuC5qpLItN%l=RFNI(_^OsaIkAZUF4#0|OK4k${F>qZ0p15gYm zI86qor3I)QIVUoCB$OhT zh|n?xjsfVMvw0O(qr_Eek!YMN6x5=EmZmyv3B<8(;NQ=9eV03jgfQAEz)oq>WEv8{ z)fHqusGKDh4kIrbVH7k7q6S$KVX~T#%@&YUR9FonnMD?ifJK}7ze_p(NAESI&cleONNg=s-T_v#6JC!Sn>VbZDlLdADL_S4Wd$U&iD{N_ zG7XC;Le`3Kcs_Aa=u-&(qtQa?W96aSUShaW&0)YrD1Sj%2 zxXOL_$&HUdt{V-bnnvp<@4)3N!^bZ@ib$vv4woMVO@WI{)v#&r-Fe3!4kiVd?w$Wh zHn@2?gk%td9j$N~0IS)IUZR(qhC_6D5$WkbF5ZW2D^?}AIwW12fq5*x~RB53=iFac0iw|JTp3{&s*ichlhqPdgUpV(rmoRz% zqefkR|GZ84L=^dW0Af*r5bZ-QrdKw{Qwg{#8jue6qi5;6*!1bAh-ETJf)tQMwbugK zY)9kRaWIGm?AW-D1DZ0A5B;Gi#!TA>!>1pC*Y3WF12C8^IPj#iFl_1}_~g}R@Z_WS z{!hTsORu>ZgYBEpx_A*JEsF`Wk3n^%58iSgUVZ#NWK)E41g5ITPoILC#%8R1_f7P6 z^#R#5v}^{hno690&zms%8X#x_(uD&1RIOM<-?kO-)C@x;l7f%QF(Kf%iB6Mn_RaU6 zIs3#59;1?RRm*ex5GWs-&q5LfWYZ}~CJTg23@abI3GGWiK{$~@S~R1OieW@^IlSI- z)Q=pAWFm*nYgQs1i^5Bha3G4k4w{47$+Pj&@2_K;+Fad;Q-AYUsGuJ39=wHzji6NcK{h&&?`qsNJ zxOoM3eD*G&INm7LeIvHhz6)Cpd9_7Bqkqx zBu4IYIG(!sV$K`bt6K2Wzs}?6c;y>UEu?_u*zx%S zh=nZnJoYR&%o@slm00}p6BvwUVUUWP#NTtj{owZbvGM(PFc65KNVP<%6ub>}IQ5S& z!r`ZK8z94VqY|%Z3e*%$<9La_NT?sa@!SoV8C@_dZI)=V2o4E9w@~FXR29pjs9DD44 z3?94T0;YUz<;^(v-WRy+W91u9;*|&gi1MakIOwd)@%yWOhDh)~D!2c))JHJ|K~jG^sp?0Iq(J3O;}PwP%H=HmM02f?Z)@lhAb&L|>GgFhGPs zP+>q3pWSsa?|?)ii>$?pL?ntmr%u4|y$|4ogpwFUf9qx>LUB0U4g_OaOgeZD#?AUM zp8U;4OwU?;b-4I%uOUMUc=KtzeDCj2(KH-KUV1BcvCO;YcC26a$-gDYfA>Yi`&@D3 zpU|`JQ*}gK6cY(S}SSiP3wE#<>0GAVMvpi692IZ$>d z#LA8shpGD?&b(7k`&N8B|GC|JEr6<;I-Gmyuh72gLv()e0pwy4v(LW@g=jyVWj?G~ z@B;dJLV!`?rooXDCv#4_bLA&kyK*%g1`$Fg2YW?1esufuaMX|C&*n}|LF7`-q4^b5 zra80)Qjy>m;gxNwTGTXwsOLhFY`;dI1B)ndl7gU@q^ih4#qI+-E&u=^07*naRFc15 zg6;3UfkZlk2#hEcvKT#f48|XLI70nB9C`=awjdEo!tS;sm`G#F{zsr`#$kB*_N$P| z6(Be~xbms@QBX8&{P<1y(Iv0jDeinGEceTCE~2iKXfV(#JhQ359#;oS0*ugLHj3QINRX83^GRz2saD>1 zCE6Cgj6^zxxL`$I$za&9;h1vR5xfIpJv|7tZRLcv!)3={B8dt69Ewqg%*BhhUZ&U9 z+kLqFiT6=}gzZaS!!x&C4SQt`&i%tY_6yle7P(A{1x^js*=(A7zo<5es?G>g)5%NF zAWAZ{5~?6;OGcC^5u(QLx#2waIlFW0chKROamcagUGo8YmMny%s5tE6Un3prg3al{ z+66Bn6pTWo{I(=v%+wihmscUaV=cCASdUCF1hJ5Zt)d)9-|;M5_2c#4=F$?NMnU!l zBu`D_ia54rG0q(hysyS!NS_Vb9xQ{4NY zNfO3R+ZS%HADQlL*tBL9vY{}vTn>(M9}c_aNjMw!WOJ@C+98uZWY~3d$%|bD;?co? z@WdunfuIo$%333)PxsyQB$hLQae~2HsVhK}(7XOqJapYTaQMn`!F}_gr~=pF z(27?IIW8Ti#yDzwr5Ys)>#1>C-_1Ilqb;q`843ayk5M0THkrU}=l_@q!QDB2deN1r zYMFqZ&)-1z@(&@Xc^r7buaOCKz**+Us<&T2I-BR+Cz_2Iwbu-e^s_zNv3c!kq^bWn zpJSyQc+216YSEkgNOlZr_=JaIEIlW}4T7Oyhw%8uVpb4f`ll1+=awKSdu$bgR>b-T zuR!~UFCm#MAZxN99Z#WocrEt%(N7Q<>_fb_2f-a%P)KKCFLPrs9LJc0jz;6OgE9ZN zS0PUYtd+Gm=YhAN3PucW_zaI+b2hAHeq8v-yHJWEhwikBN!TPz>K`MMLgs{&z|z;3 z2QLe?qyREK6zCKRIi#Xt-2BtScSrUd7@c$3b*O9{i_TA9Mfb7~A!-T^IR6Hu`#a$D z`LTAv%SdJNP$|o2k}-Pk{kS7P-Ms^w)~rNoFu)3Mc)d92#=pZod>Y$)imPb#bN%d) z@745baoQKraB#iw$Oa`Q34)W-hb;DgSv6#9=?y3-TXWyVX#en4Br`>1BqK73G%H~G zkv~Bw*pFCW7ed>&LdoXgpkW%3D8|nIG3uuujMr|toCRvDs>9j$y$MZ_5!|vA4_|R6 zEM-1i^w>fun#4AoObI1E_&fiuLZj7BCttb{{+Xi{Hju0wR#rBRSfCfbIcxV6U@;hQ z_7%T|zhM-*K6(k=OW)^i`B~>(kMuw%oL(y;m%aIhIgL{3ku-N(hb)%FB556z_^^?9HhsR%ClK)QJK)M^s zSJK-^C}QpX7o+3j*O5pSkd@6y#gk|mUWaK%o`B$B4-$i&2(`ANm?s7J&=-kd!okO( zdeQ-SV%t~Xq07&J+3m%JtN>#PH?NB&+VJQxC8ZtEJ(aVIVLEb z4I!c-*R**4vyYJiKDK-O`wb~z=&XmPOX)U@f-(hb@4pb8AJ0c3tsrkOBNjXkFZm5zb;Ho{?o;Sr_92_wz0SGb;-I|EfKb79-N+C0=Tcl6t&-UQ|26pP=7y?fi8sF^c_G7=nMog zWzJkwPMnF?Z@ZMYu(`4kXWsh;6j4TI$4dO|m#4D=e*VY@P(%|W94?Dwb2xNHUqUm2 zrXw|Sz`UAN&axGXy7|ecQ@Hy0eUM7*y5ybeK`YCgIN|bJ;i?;swznR`;L4An5gB*J z70}Wl9&NDs{a2C88xT(?VKRuAaqs~!njF}+Y6-%w%U`uk`Hyv>1F zLXf$eytcxQ#&HvoiKUQAgpmpcdDWV%PDJu~G*8(FQw~21FVPNAa*+IWIQM~f0Z~G{ za}6H6=qIo^%W&}%A0sEw4jAG>^pzknX4b(QUkdkw(240m7uBz#s6r{wJfH-Z&|iAw zgxx|w_2qs@s)AFl`xETdjc9%2VGJyP4=5;@dd6iKXkCMRIEqN;M#Ks-cl%gm0i#9@ zgJzI1uys2xlq}7-P;;<2JedBA8_~4?2_-W_D2-Zp1$OMZFV@*nlIbrGpHeQgOr2Rb z_m;;x8P>73$imWSNDT%-MzAMwA2>MTlofHF*TazHF3PV?l4+yg6^C@&~UW>CSBeZ!1ikUQ~9CH@(u^{YL1J*5lA9>Y`R3-(B1dM2DhS_OD-=VmpW}39nRX`|e3h?($xTURib8~_-MDY9ftHqh>%!K&AP52> zo!%7-fJiT-Tn0iWiflRoMUy%EmFd|6DI7vd6_62(Q1dj!N`Td5hhQ_IkV-+xW|3Dk zoN9;=W zypvA3>^E5P+(XFc6FBA8zro_G#fB$-kHIyI82}u5;u+YmbTNW~0XR)E(y$_yioq(1 zm@s2+tY5km#$pDUtcGMJ4P$|(J(@7`z(cWO@u#rZ9Z*dUu9hATj^1?Br3$q_q6 z$X)AJy!e+h4xh^k_~nc5J=QRK!kIa$?SYKMhi|~4#PP|SFF+JzOx$C<2sRl6j+fcmEk5zWK^76|l!1dtlP!saUh{4Px%_qw_9;z08NzZ#;{5M?2T; zjGsCUy{%heqynr&2nE54a6Af|Y{aDLdt%GVl~C0JQmG>1nJmmyNoX-*-0Xv}=Ce;> za(bYc?5L%cHP=QP#k1w`#VacXl zH+qk$@u1P~f{FTp4M3T@3^o%9OW@r=4J0(JE7{eFsA}LU?=p`annpY^;Tb|-3Icrt zaCtp22u5V{8IHoaO;-T7@=|H0%jHLwijxg0j5a^&C+!RGnDOwB9zS?goxkGC&>w%> z*uF+;UpM}h8!m>xgY~iy6dHt05@ot;X8=LxN`9Q8P#u*FQ8WTi#$rWL`c2b=@d}#- zA*BFWGICOz2I!~^Xt6TX6lEQ{#glQEXylFA%mEnV z3l)f_GI)0B)?M}+*i8mZsrQ5GZ4I)(L!xLA7)m>j3X+M^AlBAiC}JR;<7=b_6hiV$ zQt0xT>A=J)j!B3&<~ADO%qb#)P&tP%|^$;e9<9DmE*=#6D=zy9Q7uKOni9Dn8Y zb5B42+~+%9`a52||BrB+3`h}wFY4(toz)-(>w;%KgR3S;_&RZ+se0r}f^m7=JTWDi zj55~N3vF`_?A1zmRdoK{%P61sb7QlW0Tn8GE6t1A1Y zqEv{zB(Ob>5euAb1NRYDj= zsIXZb++j$~7&KFd1V%v-mfb8(XRn-88Q9*ax4pdiHz+y6# z5-a+ECNgbo=jn4)4J)_zV!@i$T{_-6w;iJ!>S426pd>;N^I4e5XBlKrn-bYH5+qG? z;T2abqM#LEpvYAaF&GMPQFq>8n zjg;4SLo$}BKQ287dTL<_*a2hM@j?uM3+ zV##NVxf{i37P$qskjwL|HtN`+oJ?K=V(9|j-`umy#G_RfQSY{(wyG9Yl{N6%4OqS8 zLs$$lvz(kJB%aAc*Gi^F)GIj1L>7zOaFU_1HnOD4fK3aTBT@*(0VVsugqjM2q>p8z z3@Xi@$P^XWy?)g0xi=Dyx}X2;&YSQ5N(D5JY94Xm@Tx6Js29a#8hNNZtd8OX%7Ss$ zj134S8z`R^2L&J*k{mlbzakH5MVY@mq`k~+6FkP zN3pYS-?AFjRh6(itWb&>&ONgWV$&ya`%f&D#v|{o;GOtQ2X(<8IAJ7;`2s?LAV!Sb z19r0!b|Hbz^&5D8G)bS$EG7Tw%t{F#J(mlP#&fE|07D{wL_%kitdC08&7!VF-DK-K zoD@JvO)wf^v^r3bTqA#(H+PP( zoumSz(s$i9tL)75JdW-w=w=L5>P}{ehT@TJq^o4UiA)I%{h(E6wV*GY!i4<}Lb4#j zX{M@%?HD(H6sQz{6i*nR%niLZo=R~8#FHPa;EVfa$SLB8y(e(lJeii>z5vqMB1VlE z2fs^3=bFV_ghdXMh0m5&=DrBp0hF1edRIb5MM2`e0U8=ei%J&&`HqrBAV*A#Pn20c z)Wj{QB09UfpcsrOP|<_g_00Umt55mzIsZQejB2VrWI~nWUF1@nl_Hxta`YIU60&;L zDvo|>Fp+)|y6K@z6ya-K0Xj=bwKXQOWbgTJ`Ibw-#rW$`#T$pSU`OH8N*iE^NoE{SaOX+cpF9!=6^D9u(t zWgjx+Si1B0e+r<#9JANRK?CxB=0VwH=q83v zl2dJ8%1Y@)Mk1G;Q!0^uCc!EKxB!*f`z=-~?KbFCb193(rYw1<0QngDzZu* z^WS<0cmMH^@RfVn_R{<|p7o#2aR>g-Zn&0N$!|Ky1e|sBF=(i*h1G0fvX5Gd1|l)s z_`Ba@;>c0hd&+cJoi^0la`@=om-J+ho?vFWfG&}CAMyWrItS6Lv%{ryqHcin+?JkA zBw6WaC5r}*lQ?rh6Bz|jhs{3ys;l0k7ZUDfY)e~^QIh@4q0=-5=29j3t3jkKk|2uZ9c^86cg+K#PZC0#Zv=UBxC5E+(!H&Ux zy#4V|@=y$VZ0*Jkxa+Y;(AC$wOW`-w*5cSh4&#+>F@V~$K zJU(5qd*dsoO_+$8Q}^Owg4A+KriX@&P#i(`eY4P=mUu^)xm=vcvn9)yW5@RGXx*|E zXPSbt~u_6+kk7vSTnRL2%G=Cs?Yl{ZfSj!-XNilZy0cb*KQ9ofiGQn1wXZk633H z*1q)`27*0E7X^&<_)%9;iT*$jwnXA+sjWv(D2SKeeVb9wt`57!in(*&H7yIuu1s!1(*{ZQ9$`Xtw z5w5B-VjT7SG?`U4t$MUig3x;>XmOH{Bn+iHal(5%rJ|G9G~ zUi`=VSCKu-km!pF5%_S`R+4uPwX{e0?#3(d3Gdx8!4dlv&BfnpBV;| zL7#k1ciRwYwx@m*IJ&RFWAmQDi?7Yc{*x!;!ZS|77pph3!{#oQd;xu(+cD|1bKssd z6-806#vsA&JQx+}zYm#bTJ#oPDVfA%#L5pwUg zrXi~ox#NTI4+)-c_9eKf*=IH5jMGlX zk54~|tFL$GpdlH@9(pL>8IQPp${U-FCbsqDba}tDoek&qvm z_cZ3cJ|Aw26~DXgYApPG6;lVa)Ts(Cv}q-dJnup@AAd4CR2_2u!|LwrcHx~d^miSg z-u3IN4|?&z2X}cJtld%o3Ffg?n^%?j{1bIUucMm+IoVPGLQE)aL&gZDYHLCR(Oe!q zPdwCoLBt7mjoOr}hY-%VFBJ;uu zFc@Gq=xB$KkBROJBgqhDiGwc^^w7f4IW~<42GVioy?@2#wlzCFTMgz#~!a=^H9LWOMVDKmae;W?WBm$7rgVAYfeAmvfWuwyR85!Qkd5j z7$_E1H$hP9_~sTgiWUVCCQ4=s;7SVO^@*d&78S$`Mf5%W5C+z)fXm_F5yhLkdT`QD zPDN8wGvB}Kua7*4kCuG)|IU}3YI9vZX6-eN?K;;+@U5z3jz8!-1#9#?GBf(hmvwVf zx?vnc5JmE5@3p4kc zj>+TqC|xF%p%bE_RZXj&gk0JMtOQ*VWQK->PgDu5W~K{x;3}TZt$ z`&J5|6P|YT(PPfM>u>8s6?9`+JuoRz)wKGlRD+zffl5pS3H`|&dR}@8Yud9xoSzgW!8Bf0aJeI9qg~{W_W7@=tI{lnic(#yUh()xnZp(=hCgC!!ClkY_ zMpp>=1Fq~S*?K)fr2$bA?+!v%1Q2A|07257F)bW=|6pJcOO~xhGMhtD6i~=y5ZbsL zr~m10SoWC0rj-Ly;$tZnQKA}j^Tr@Oe$9xECrp|)Yu0k| zHbeJanbJHAT7?gWVZ)i!qKY=!83Tz7+MaqCAHDDt%A5{3Y<5(Xxv>AN+3;7_Ft5Xv z&4mJwJEIbIDm5HRX0QNB0bjD|yoy=)y5Q+|R>qK0SXuwzW^@x&a=;}LO;>=(K7)pG zrxOXRUA>0Wh=b`QPr3@NU5?Z5dJtmEsL~D)7+f%=s1?z*_)|__rc%lD6Mwn0sie0DAM`{+fvsM~_$`$|4;&Y~NYvvfJT5{uEA465pdq8saGhp|@VbdyhYi zN}mgZ!4MiNEAiu_jzMipi+=xKnO3~s2S8u6@`w7t=(A{j(W)n56H3v|iyr>-4rDW< zn;gzYl{#kFN^=cq37t{lREeP_{+SV5$w$y_4Hv!jHWPR4gCTsld>M?fAg+DpWuT@W z(5O5fpnf6>DnkSPc<$WOpeUL6`rd)Ma5(&}gp;0UHM7`Fjknzw+9*Cf5J}1^P)uK~xgzDt&z4MvvW& zW9Iw_jiW|l`}Xaqs;+`UDZql>1ICRRl+7sh1F!;kr4!2HP>5rUQu_m&Trw*pc!Hlg z^wiH+7ry=)+A%{gl%6o;oayg`-><#px7;EXPp0{9ejbB_-`xK=gpngq5L6iHd{iJ+ zETXNw1MgpdY45_%7Y_&Ut<27sCHZgffT1^WI2_*b4Go)5I_xN4uiFjR$v;JoIdTE^ zyawOra6E(B@(P@M>~UxwK8&Yv>8rHVdc;)~^fNVR3^ixy{Q;bh zBl3%%L%U?C8iQ`&OsuT#aCL#}P?I?V9yHWsu&X0a_%2j*Z z_=h{GCTR4kk5L!sMMRO%kx1dM4?V>9?4p%Srr_{{55_(d$8+jZxAUcJSt*IZJEGL} z$m!=&z&F&k#DvID#J96XXQ-o-6i_lZB}1$8HznSRoif!X>B8q7C`$O{uWsV`rg??N z%&71=tho0tf945b+ZMhDt!bF@*tV^QEqmnNT}HUO68zBLzf%R!n>Ngx*>w5ESARC5 zZF^-#G9XA5a+w?+p7#_Z9?Fc_Ep{9#pxrtD({U=(3%?;P*l)7U`5hZ&= zir^|bUiEbP9E6l^CQ(WbF%;FEHOqf!;z-FnaUfZ0@}NEl-YuexoB#YLL}E$3KSEPs zl{H*+?s*tBY7`A0|Kh^yubI6oZfAD||6fx;>5YXuF1h5!#^K|CRVWk${mvSiezzhD zmgu&HoV3v6NmbEj%yB$X$~fur)*sh9l=L0JO?%wFRO042a4MOR5+B2r2}DPfRz2Bx z&RY*f$fO`9(e(Bc+L3x1QdczH7l$|{x{vXO4IA>GE?<7i%M0dzEv5Wzh5ns7;cxoz z+S*#r&6i#Ks;|tmpUGIH?1)R%a3pvNnuc}&*YcEd z(_Eu7R2EWVD9NPgw^-33Dt|8tekV0iDs3bM4^bFQHPB5(vsta9r~A>LU4H2WUzbez zPXzzp-U0t~Zj;7M8hztcSG`c?c8}$YFRfnYR7$p8U*Ytnr}2tvVW(0^@Dvwtxk!l+ z(<=k?FP#$5oiV3MS>U?RY3I?XNcx%PVGKpeJ85KkZV3quDW;>V>#eJ9zva}mGAC95Wcz@Rx2{Xr2Pue$FI)+5WS#^na*IjeWtF8lOuA ztE?!F27d+6dXO0!j&R-Q<@N+(R$k3Ho)%tosk$hVx*yQq((y`59S}Zz!1_ z`kffip-6bBF}9Iew0{%%~ZSH z#7UE7NgO+-Wq6$i%@2TvUmHrVp;n(H1PrX%xVb|Tq;(&B{@KbvUu0uze=FTucDMQY fT}tdbe!~9&ZRyor+0M!j00000NkvXXu0mjfA#`jm literal 0 HcmV?d00001 diff --git a/tools/cabana/cabana.cc b/tools/cabana/cabana.cc index e028e383c2..5c182f435f 100644 --- a/tools/cabana/cabana.cc +++ b/tools/cabana/cabana.cc @@ -14,6 +14,7 @@ int main(int argc, char *argv[]) { initApp(argc, argv); QApplication app(argc, argv); app.setApplicationDisplayName("Cabana"); + app.setWindowIcon(QIcon(":cabana-icon.png")); QCommandLineParser cmd_parser; cmd_parser.addHelpOption(); From a20f07144beb26e4ade7b3c5dc6e4be40ff5a12d Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 20 Feb 2023 16:19:17 -0500 Subject: [PATCH 0981/1179] Hyundai CAN-FD: common PT bus function cleanup (#27397) * Hyundai CAN-FD: common PT bus function cleanup * use CP * Update selfdrive/car/hyundai/hyundaicanfd.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 2a909b6e2e..1dd91ac888 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -2,6 +2,7 @@ from cereal import car from panda import Panda from common.conversions import Conversions as CV +from selfdrive.car.hyundai.hyundaicanfd import get_e_can_bus from selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config @@ -247,8 +248,7 @@ class CarInterface(CarInterfaceBase): # *** feature detection *** if candidate in CANFD_CAR: - bus = 5 if ret.flags & HyundaiFlags.CANFD_HDA2 else 4 - ret.enableBsm = 0x1e5 in fingerprint[bus] + ret.enableBsm = 0x1e5 in fingerprint[get_e_can_bus(ret)] else: ret.enableBsm = 0x58b in fingerprint[0] From 4918daaf5d8578c467f9626afc0ae0d6dafd9422 Mon Sep 17 00:00:00 2001 From: Matt Crum Date: Mon, 20 Feb 2023 15:25:46 -0600 Subject: [PATCH 0982/1179] Added FW for 2023 Hyundai Santa Cruz Limited (#27395) * Update values.py Added additional firmware version for Santa Cruz 1st Gen forward camera Updated CAR.SANTA_CRUZ_1ST_GEN's information to include 2023 models * Update values.py added fwdRadar firmware version * Update CARS.md Updated to include 2023 Hyundai Santa Cruz --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 8860299360..5a29a63f45 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -79,7 +79,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O|| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|| |Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Hyundai|Santa Cruz 2021-22[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Santa Cruz 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| |Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| |Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| |Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index d0a4e4dd1a..7a16b47a4d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -191,7 +191,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Hyundai Tucson 2023", "All", harness=Harness.hyundai_n), ], CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), - CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-22", harness=Harness.hyundai_n), + CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-23", harness=Harness.hyundai_n), # Kia CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), @@ -1597,9 +1597,11 @@ FW_VERSIONS = { CAR.SANTA_CRUZ_1ST_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW000 14M', + b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-CW010 14X', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00NX4__ 1.00 1.00 99110-K5000 ', + b'\xf1\x00NX4__ 1.01 1.00 99110-K5000 ', ], }, CAR.KIA_SPORTAGE_5TH_GEN: { From 927289cda8cd8465c1161e64026d7839cc4fc938 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 Feb 2023 13:25:52 -0800 Subject: [PATCH 0983/1179] increase fetch depth for release submodule check --- release/check-submodules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/check-submodules.sh b/release/check-submodules.sh index bc85a43c57..2585db6bd7 100755 --- a/release/check-submodules.sh +++ b/release/check-submodules.sh @@ -1,7 +1,7 @@ #!/bin/bash while read hash submodule ref; do - git -C $submodule fetch --depth 200 origin master + git -C $submodule fetch --depth 300 origin master git -C $submodule branch -r --contains $hash | grep "origin/master" if [ "$?" -eq 0 ]; then echo "$submodule ok" From 55da5175aea1a4d206001f2c51d66f4cdf6799c2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 13:29:37 -0800 Subject: [PATCH 0984/1179] HKG: update Santa Cruz model years (#27401) 2021 Santa Cruz doesn't exist --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 5a29a63f45..1b2ec8a2c8 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -79,7 +79,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O|| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|| |Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| -|Hyundai|Santa Cruz 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| +|Hyundai|Santa Cruz 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| |Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|| |Hyundai|Santa Fe 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| |Hyundai|Santa Fe Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 7a16b47a4d..49645fb0b1 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -191,7 +191,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Hyundai Tucson 2023", "All", harness=Harness.hyundai_n), ], CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022", "All", harness=Harness.hyundai_n), - CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2021-23", harness=Harness.hyundai_n), + CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", harness=Harness.hyundai_n), # Kia CAR.KIA_FORTE: HyundaiCarInfo("Kia Forte 2019-21", harness=Harness.hyundai_g), From 1f89afd1401176641443090fde6ca7a787c890a9 Mon Sep 17 00:00:00 2001 From: ntegan1 Date: Mon, 20 Feb 2023 16:31:30 -0500 Subject: [PATCH 0985/1179] cabana: missing includes (#27390) --- tools/cabana/dbcmanager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index b438b3e1c2..267157b31a 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -2,6 +2,8 @@ #include #include +#include +#include #include struct MessageId { From bd469d7c54a0cf32b0d038e1d2e72b737071eb94 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 Feb 2023 13:32:52 -0800 Subject: [PATCH 0986/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 0d2ee00921..d2c2d5f926 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 0d2ee009218009173f26c73a16aefa12dd169de8 +Subproject commit d2c2d5f926537a132a253277998ef350fe866d27 From 10ed70d95293375a36d57d103b7173dc637e861a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 21 Feb 2023 05:52:16 +0800 Subject: [PATCH 0987/1179] cabana: show command's text in statusbar (#27398) --- tools/cabana/commands.cc | 24 +++++++++++++----------- tools/cabana/commands.h | 4 ++-- tools/cabana/mainwin.cc | 22 ++++++++++++++++++++++ tools/cabana/mainwin.h | 3 +++ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index e03d6d1b11..70700b33b9 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -4,24 +4,26 @@ // EditMsgCommand -EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &title, int size, QUndoCommand *parent) - : id(id), new_title(title), new_size(size), QUndoCommand(parent) { +EditMsgCommand::EditMsgCommand(const MessageId &id, const QString &name, int size, QUndoCommand *parent) + : id(id), new_name(name), new_size(size), QUndoCommand(parent) { if (auto msg = dbc()->msg(id)) { - old_title = msg->name; + old_name = msg->name; old_size = msg->size; + setText(QObject::tr("edit message %1:%2").arg(name).arg(id.address)); + } else { + setText(QObject::tr("new message %1:%2").arg(name).arg(id.address)); } - setText(QObject::tr("Edit message %1:%2").arg(id.address).arg(title)); } void EditMsgCommand::undo() { - if (old_title.isEmpty()) + if (old_name.isEmpty()) dbc()->removeMsg(id); else - dbc()->updateMsg(id, old_title, old_size); + dbc()->updateMsg(id, old_name, old_size); } void EditMsgCommand::redo() { - dbc()->updateMsg(id, new_title, new_size); + dbc()->updateMsg(id, new_name, new_size); } // RemoveMsgCommand @@ -29,7 +31,7 @@ void EditMsgCommand::redo() { RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : id(id), QUndoCommand(parent) { if (auto msg = dbc()->msg(id)) { message = *msg; - setText(QObject::tr("Remove message %1:%2").arg(id.address).arg(message.name)); + setText(QObject::tr("remove message %1:%2").arg(message.name).arg(id.address)); } } @@ -50,7 +52,7 @@ void RemoveMsgCommand::redo() { AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent) : id(id), signal(sig), QUndoCommand(parent) { - setText(QObject::tr("Add signal %1 to %2").arg(sig.name).arg(id.address)); + setText(QObject::tr("add signal %1 to %2:%3").arg(sig.name).arg(msgName(id)).arg(id.address)); } void AddSigCommand::undo() { dbc()->removeSignal(id, signal.name); } @@ -60,7 +62,7 @@ void AddSigCommand::redo() { dbc()->addSignal(id, signal); } RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent) : id(id), signal(*sig), QUndoCommand(parent) { - setText(QObject::tr("Remove signal %1 from %2").arg(signal.name).arg(id.address)); + setText(QObject::tr("remove signal %1 from %2:%3").arg(signal.name).arg(msgName(id)).arg(id.address)); } void RemoveSigCommand::undo() { dbc()->addSignal(id, signal); } @@ -70,7 +72,7 @@ void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name); } EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { - setText(QObject::tr("Edit signal %1").arg(old_signal.name)); + setText(QObject::tr("edit signal %1 in %2:%3").arg(old_signal.name).arg(msgName(id)).arg(id.address)); } void EditSignalCommand::undo() { dbc()->updateSignal(id, new_signal.name, old_signal); } diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 57df664974..3565211eb9 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -9,13 +9,13 @@ using namespace dbcmanager; class EditMsgCommand : public QUndoCommand { public: - EditMsgCommand(const MessageId &id, const QString &title, int size, QUndoCommand *parent = nullptr); + EditMsgCommand(const MessageId &id, const QString &name, int size, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: const MessageId id; - QString old_title, new_title; + QString old_name, new_name; int old_size = 0, new_size = 0; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 2cba29bf5e..47ad3a4a6d 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -65,6 +65,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); + QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MainWindow::undoStackIndexChanged); } void MainWindow::createActions() { @@ -186,7 +187,28 @@ void MainWindow::createShortcuts() { // TODO: add more shortcuts here. } +void MainWindow::undoStackIndexChanged(int index) { + int count = UndoStack::instance()->count(); + if (count >= 0) { + QString command_text; + if (index == count) { + command_text = (count == prev_undostack_count ? "Redo " : "") + UndoStack::instance()->text(index - 1); + } else if (index < prev_undostack_index) { + command_text = tr("Undo %1").arg(UndoStack::instance()->text(index)); + } else if (index > prev_undostack_index) { + command_text = tr("Redo %1").arg(UndoStack::instance()->text(index - 1)); + } + statusBar()->showMessage(command_text, 2000); + } + prev_undostack_index = index; + prev_undostack_count = count; +} + void MainWindow::undoStackCleanChanged(bool clean) { + if (clean) { + prev_undostack_index = 0; + prev_undostack_count = 0; + } setWindowModified(!clean); } diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index e7a39adab7..85d221a231 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -54,6 +54,7 @@ protected: void setOption(); void findSimilarBits(); void undoStackCleanChanged(bool clean); + void undoStackIndexChanged(int index); void onlineHelp(); VideoWidget *video_widget = nullptr; @@ -70,6 +71,8 @@ protected: enum { MAX_RECENT_FILES = 15 }; QAction *recent_files_acts[MAX_RECENT_FILES] = {}; QMenu *open_recent_menu = nullptr; + int prev_undostack_index = 0; + int prev_undostack_count = 0; friend class OnlineHelp; }; From ba3d3bd940d1796c863b80a7d27291c9c6249440 Mon Sep 17 00:00:00 2001 From: Chris Hart Date: Mon, 20 Feb 2023 14:03:42 -0800 Subject: [PATCH 0988/1179] SANTA_FE_2022: add missing transmission FW (#27369) * Added new fingerprints for updated SANTAFE_2022 * Update values.py fixed missing comma that was breaking build * Revert "Update values.py" This reverts commit 58837eadd4cfb57ec56a45592c21b251e6c52957. * Revert "Added new fingerprints for updated SANTAFE_2022" This reverts commit 3bec6e0196e9fcac83a34f79b7b860f2e24aa763. * add FW, remove radar FW from long query --------- Co-authored-by: Chris Hart Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 49645fb0b1..4b7a295246 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -751,7 +751,6 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ', b'\xf1\x8799110S1500\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ', - b'\xf1\x8799110S1500\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ', b'\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ', ], (Ecu.abs, 0x7d1, None): [ @@ -785,6 +784,7 @@ FW_VERSIONS = { b'\xf1\x00TMA MFC AT USA LHD 1.00 1.01 99211-S2500 210205', ], (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x00T02601BL T02900A1 VTMPT25XXX900NSA\xf3\xf4Uj', b'\xf1\x87SDMXCA9087684GN1VfvgUUeVwwgwwwwwffffU?\xfb\xff\x97\x88\x7f\xff+\xa4\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00', b'\xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7', b'\xf1\x87SDMXCA8653204GN1EVugEUuWwwwwww\x87wwwwwv/\xfb\xff\xa8\x88\x9f\xff\xa5\x9c\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00', From 1bd15f00a70b72caa99e7be87571595adb5ea074 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 14:07:22 -0800 Subject: [PATCH 0989/1179] Toyota: expand C-HR Hybrid model years (#27402) we probably support 2021 too --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 1b2ec8a2c8..59eece1e4b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -179,7 +179,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|C-HR Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index b6a556438d..8e118293ee 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -120,7 +120,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), - CAR.CHRH_TSS2: ToyotaCarInfo("Toyota C-HR Hybrid 2022"), + CAR.CHRH_TSS2: ToyotaCarInfo("Toyota C-HR Hybrid 2021-22"), CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ ToyotaCarInfo("Toyota Corolla 2020-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"), From e1051e5e5c52267407cca864f984fee2328c2cce Mon Sep 17 00:00:00 2001 From: kaischiefer-srd <106266385+kaischiefer-srd@users.noreply.github.com> Date: Mon, 20 Feb 2023 17:11:46 -0500 Subject: [PATCH 0990/1179] Toyota: add engine FW for 2021 NX300 (#27326) added engine fw for our 2021 NX300 F sport --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 8e118293ee..0fcabe163c 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1726,6 +1726,7 @@ FW_VERSIONS = { (Ecu.engine, 0x700, None): [ b'\x018966378B2100\x00\x00\x00\x00', b'\x018966378B3000\x00\x00\x00\x00', + b'\x018966378B4100\x00\x00\x00\x00', b'\x018966378G3000\x00\x00\x00\x00', b'\x018966378B2000\x00\x00\x00\x00', ], From 4efd246bac004f3b6f1f7d733e6e285b3fdc8322 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 21 Feb 2023 06:16:30 +0800 Subject: [PATCH 0991/1179] cabana: improve UI & fix bugs (#27387) * improve ui * keep splitter size after msg changed * no leading spaces allowed in msg filter and signal filter * draw color byte AlignCenter * always set as current index * reduce chart flickers while resizing * dispaly more info in tooltip for signal * narrow combobox * use   * typo * private sigs,fix bugs * merge #27383 * no expanding after undo/redo * gray color in tooltip * clear current_msg_id before reset model * dont call setmeesage if id is the same * fix bugs * cleanup * dont fetch logs if invisible * add new CenterWidget, make sure msg_id is always valid * cache icons * cleanup paint byte color * merge #27385 implement sizeHint * cleanup code * fillrect if alpha>0 --- tools/cabana/binaryview.cc | 90 +++++++++--------- tools/cabana/binaryview.h | 4 +- tools/cabana/chartswidget.cc | 29 +++--- tools/cabana/chartswidget.h | 2 +- tools/cabana/commands.cc | 4 +- tools/cabana/dbcmanager.cc | 53 ++++++----- tools/cabana/dbcmanager.h | 6 +- tools/cabana/detailwidget.cc | 122 +++++++++++++------------ tools/cabana/detailwidget.h | 27 +++--- tools/cabana/historylog.cc | 76 ++++++++------- tools/cabana/historylog.h | 17 ++-- tools/cabana/mainwin.cc | 10 +- tools/cabana/mainwin.h | 2 +- tools/cabana/messageswidget.cc | 28 +++--- tools/cabana/messageswidget.h | 3 - tools/cabana/signaledit.cc | 83 ++++++++--------- tools/cabana/signaledit.h | 6 +- tools/cabana/streams/abstractstream.cc | 10 +- tools/cabana/tests/test_cabana.cc | 14 +-- tools/cabana/util.cc | 49 +++++----- tools/cabana/util.h | 4 + tools/cabana/videowidget.cc | 4 +- 22 files changed, 344 insertions(+), 299 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 5ea5ea2d99..d9b00f6882 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -32,7 +32,6 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); verticalHeader()->setDefaultSectionSize(CELL_HEIGHT); horizontalHeader()->hide(); - setFrameShape(QFrame::NoFrame); setShowGrid(false); setMouseTracking(true); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -44,17 +43,17 @@ BinaryView::BinaryView(QWidget *parent) : QTableView(parent) { setWhatsThis(R"( Binary View
- Shortcuts:
+ Shortcuts
Delete Signal: - x , - Backspace , - Delete
- Change endianness: e
- Change singedness: s
+  x , +  Backspace , +  Delete 
+ Change endianness:  e 
+ Change singedness:  s 
Open chart: - c , - p , - g
+  c , +  p , +  g  )"); } @@ -108,14 +107,14 @@ void BinaryView::addShortcuts() { QObject::connect(shortcut_plot_c, &QShortcut::activated, shortcut_plot, &QShortcut::activated); QObject::connect(shortcut_plot, &QShortcut::activated, [=]{ if (hovered_sig != nullptr) { - emit showChart(*model->msg_id, hovered_sig, true, false); + emit showChart(model->msg_id, hovered_sig, true, false); } }); } QSize BinaryView::minimumSizeHint() const { - return {(horizontalHeader()->minimumSectionSize() + 1) * 9 + VERTICAL_HEADER_WIDTH, - CELL_HEIGHT * std::min(model->rowCount(), 10)}; + return {(horizontalHeader()->minimumSectionSize() + 1) * 9 + VERTICAL_HEADER_WIDTH + 2, + CELL_HEIGHT * std::min(model->rowCount(), 10) + 2}; } void BinaryView::highlight(const Signal *sig) { @@ -127,6 +126,16 @@ void BinaryView::highlight(const Signal *sig) { emit model->dataChanged(index, index, {Qt::DisplayRole}); } } + + if (sig && underMouse()) { + QString tooltip = tr(R"(%1
+ Size:%2 LE:%3 SGD:%4 + )").arg(sig->name).arg(sig->size).arg(sig->is_little_endian ? "Y" : "N").arg(sig->is_signed ? "Y" : "N"); + QToolTip::showText(QCursor::pos(), tooltip, this, rect()); + } else { + QToolTip::showText(QCursor::pos(), "", this, rect()); + } + hovered_sig = sig; emit signalHovered(hovered_sig); } @@ -169,7 +178,6 @@ void BinaryView::highlightPosition(const QPoint &pos) { auto item = (BinaryViewModel::Item *)index.internalPointer(); const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); highlight(sig); - QToolTip::showText(pos, sig ? sig->name : "", this, rect()); } } @@ -210,8 +218,6 @@ void BinaryView::setMessage(const MessageId &message_id) { } void BinaryView::refresh() { - if (!model->msg_id) return; - clearSelection(); anchor_index = QModelIndex(); resize_sig = nullptr; @@ -245,26 +251,26 @@ std::tuple BinaryView::getSelection(QModelIndex index) { void BinaryViewModel::refresh() { beginResetModel(); items.clear(); - if (auto dbc_msg = dbc()->msg(*msg_id)) { + if (auto dbc_msg = dbc()->msg(msg_id)) { row_count = dbc_msg->size; items.resize(row_count * column_count); - for (auto &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 " << sig.name << "out of bounds.start_bit:" << sig.start_bit << "size:" << sig.size; + qWarning() << "signal " << sig->name << "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; - items[idx].bg_color = getColor(&sig); - items[idx].sigs.push_back(&sig); + 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(sig); + items[idx].sigs.push_back(sig); } } } else { - row_count = can->lastMessage(*msg_id).dat.size(); + row_count = can->lastMessage(msg_id).dat.size(); items.resize(row_count * column_count); } endResetModel(); @@ -273,7 +279,7 @@ void BinaryViewModel::refresh() { void BinaryViewModel::updateState() { auto prev_items = items; - const auto &last_msg = can->lastMessage(*msg_id); + const auto &last_msg = can->lastMessage(msg_id); const auto &binary = last_msg.dat; // data size may changed. @@ -283,33 +289,29 @@ void BinaryViewModel::updateState() { items.resize(row_count * column_count); endInsertRows(); } + + double max_f = 255.0; + double factor = 0.25; + double scaler = max_f / log2(1.0 + factor); char hex[3] = {'\0'}; for (int i = 0; i < binary.size(); ++i) { for (int j = 0; j < 8; ++j) { - items[i * column_count + j].val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0'; - + auto &item = items[i * column_count + j]; + item.val = ((binary[i] >> (7 - j)) & 1) != 0 ? '1' : '0'; // Bit update frequency based highlighting - bool has_signal = items[i * column_count + j].sigs.size() > 0; - double offset = has_signal ? 50 : 0; - - double min_f = last_msg.bit_change_counts[i][7 - j] == 0 ? offset : offset + 25; - double max_f = 255.0; - - double factor = 0.25; - double scaler = max_f / log2(1.0 + factor); - - double alpha = std::clamp(offset + log2(1.0 + factor * (double)last_msg.bit_change_counts[i][7 - j] / (double)last_msg.count) * scaler, min_f, max_f); - items[i * column_count + j].bg_color.setAlpha(alpha); + double offset = !item.sigs.empty() ? 50 : 0; + auto n = last_msg.bit_change_counts[i][7 - j]; + double min_f = n == 0 ? offset : offset + 25; + double alpha = std::clamp(offset + log2(1.0 + factor * (double)n / (double)last_msg.count) * scaler, min_f, max_f); + item.bg_color.setAlpha(alpha); } hex[0] = toHex(binary[i] >> 4); hex[1] = toHex(binary[i] & 0xf); items[i * column_count + 8].val = hex; items[i * column_count + 8].bg_color = last_msg.colors[i]; } - for (int i = binary.size(); i < row_count; ++i) { - for (int j = 0; j < column_count; ++j) { - items[i * column_count + j].val = "-"; - } + for (int i = binary.size() * column_count; i < items.size(); ++i) { + items[i].val = "-"; } for (int i = 0; i < items.size(); ++i) { diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 1d6d5d0b07..681ac1fbf3 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -1,7 +1,5 @@ #pragma once -#include - #include #include #include @@ -50,7 +48,7 @@ public: }; std::vector items; - std::optional msg_id; + MessageId msg_id; int row_count = 0; const int column_count = 9; }; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8515ffcfe7..e315f82398 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -11,15 +11,16 @@ #include #include #include -#include #include #include const int MAX_COLUMN_COUNT = 4; // ChartsWidget -ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { +ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { + setFrameStyle(QFrame::StyledPanel | QFrame::Plain); QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); @@ -43,6 +44,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { range_lb_action = toolbar->addWidget(range_lb = new QLabel(this)); range_slider = new QSlider(Qt::Horizontal, this); + range_slider->setMaximumWidth(200); range_slider->setToolTip(tr("Set the chart range")); range_slider->setRange(1, settings.max_cached_minutes * 60); range_slider->setSingleStep(1); @@ -67,6 +69,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) { charts_main_layout->addStretch(0); QScrollArea *charts_scroll = new QScrollArea(this); + charts_scroll->setFrameStyle(QFrame::NoFrame); charts_scroll->setWidgetResizable(true); charts_scroll->setWidget(charts_container); charts_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -329,18 +332,12 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart); move_icon->setToolTip(tr("Drag and drop to combine charts")); - QToolButton *remove_btn = new QToolButton(); - remove_btn->setIcon(utils::icon("x")); - remove_btn->setAutoRaise(true); - remove_btn->setToolTip(tr("Remove Chart")); + QToolButton *remove_btn = toolButton("x", tr("Remove Chart")); close_btn_proxy = new QGraphicsProxyWidget(chart); close_btn_proxy->setWidget(remove_btn); close_btn_proxy->setZValue(chart->zValue() + 11); - QToolButton *manage_btn = new QToolButton(); - manage_btn->setToolButtonStyle(Qt::ToolButtonIconOnly); - manage_btn->setIcon(utils::icon("list")); - manage_btn->setAutoRaise(true); + QToolButton *manage_btn = toolButton("list", ""); QMenu *menu = new QMenu(this); line_series_action = menu->addAction(tr("Line"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeLine); }); line_series_action->setCheckable(true); @@ -434,12 +431,12 @@ void ChartView::manageSeries() { } void ChartView::resizeEvent(QResizeEvent *event) { - QChartView::resizeEvent(event); updatePlotArea(align_to); int x = event->size().width() - close_btn_proxy->size().width() - 11; close_btn_proxy->setPos(x, 8); manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); move_icon->setPos(11, 8); + QChartView::resizeEvent(event); } void ChartView::updatePlotArea(int left) { @@ -448,7 +445,7 @@ void ChartView::updatePlotArea(int left) { align_to = left; background->setRect(r); chart()->legend()->setGeometry(QRect(r.left(), r.top(), r.width(), 45)); - chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 22, r.height() - 80)); + chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 36, r.height() - 80)); chart()->layout()->invalidate(); } } @@ -570,7 +567,7 @@ void ChartView::updateAxisY() { QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; - y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 20; // left margin 20 + y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 emit axisYLabelWidthChanged(y_label_width); } } @@ -887,10 +884,10 @@ void SeriesSelector::updateAvailableList(int index) { available_list->clear(); MessageId msg_id = msgs_combo->itemData(index).value(); auto selected_items = seletedItems(); - for (auto &s : dbc()->msg(msg_id)->sigs) { - bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=&s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); + for (auto s : dbc()->msg(msg_id)->getSignals()) { + bool is_selected = std::any_of(selected_items.begin(), selected_items.end(), [=, sig=s](auto it) { return it->msg_id == msg_id && it->sig == sig; }); if (!is_selected) { - addItemToList(available_list, msg_id, &s); + addItemToList(available_list, msg_id, s); } } } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 7089b4eaee..a1dcf32513 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -92,7 +92,7 @@ private: friend class ChartsWidget; }; -class ChartsWidget : public QWidget { +class ChartsWidget : public QFrame { Q_OBJECT public: diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index 70700b33b9..9b9724aada 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -38,8 +38,8 @@ RemoveMsgCommand::RemoveMsgCommand(const MessageId &id, QUndoCommand *parent) : void RemoveMsgCommand::undo() { if (!message.name.isEmpty()) { dbc()->updateMsg(id, message.name, message.size); - for (auto &s : message.sigs) - dbc()->addSignal(id, s); + for (auto s : message.getSignals()) + dbc()->addSignal(id, *s); } } diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index ae3a65a99b..32113c2f22 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -10,10 +10,6 @@ namespace dbcmanager { -void sortSignalsByAddress(QList &sigs) { - std::sort(sigs.begin(), sigs.end(), [](auto &a, auto &b) { return a.start_bit < b.start_bit; }); -} - bool DBCManager::open(const QString &dbc_file_name, QString *error) { QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, dbc_file_name); QFile file(opendbc_file_path); @@ -83,27 +79,27 @@ QString DBCManager::generateDBC() { QString dbc_string, signal_comment, val_desc; for (auto &[address, m] : msgs) { dbc_string += QString("BO_ %1 %2: %3 XXX\n").arg(address).arg(m.name).arg(m.size); - for (auto &sig : m.sigs) { + for (auto sig : m.getSignals()) { dbc_string += QString(" SG_ %1 : %2|%3@%4%5 (%6,%7) [%8|%9] \"%10\" XXX\n") - .arg(sig.name) - .arg(sig.start_bit) - .arg(sig.size) - .arg(sig.is_little_endian ? '1' : '0') - .arg(sig.is_signed ? '-' : '+') - .arg(sig.factor, 0, 'g', std::numeric_limits::digits10) - .arg(sig.offset, 0, 'g', std::numeric_limits::digits10) - .arg(sig.min) - .arg(sig.max) - .arg(sig.unit); - if (!sig.comment.isEmpty()) { - signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig.name).arg(sig.comment); + .arg(sig->name) + .arg(sig->start_bit) + .arg(sig->size) + .arg(sig->is_little_endian ? '1' : '0') + .arg(sig->is_signed ? '-' : '+') + .arg(sig->factor, 0, 'g', std::numeric_limits::digits10) + .arg(sig->offset, 0, 'g', std::numeric_limits::digits10) + .arg(sig->min) + .arg(sig->max) + .arg(sig->unit); + if (!sig->comment.isEmpty()) { + signal_comment += QString("CM_ SG_ %1 %2 \"%3\";\n").arg(address).arg(sig->name).arg(sig->comment); } - if (!sig.val_desc.isEmpty()) { - QString text; - for (auto &[val, desc] : sig.val_desc) { - text += QString("%1 \"%2\"").arg(val, desc); + if (!sig->val_desc.isEmpty()) { + QStringList text; + for (auto &[val, desc] : sig->val_desc) { + text << QString("%1 \"%2\"").arg(val, desc); } - val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig.name).arg(text); + val_desc += QString("VAL_ %1 %2 %3;\n").arg(address).arg(sig->name).arg(text.join(" ")); } } dbc_string += "\n"; @@ -127,7 +123,6 @@ void DBCManager::addSignal(const MessageId &id, const Signal &sig) { if (auto m = const_cast(msg(id.address))) { m->sigs.push_back(sig); auto s = &m->sigs.last(); - sortSignalsByAddress(m->sigs); emit signalAdded(id.address, s); } } @@ -136,7 +131,6 @@ void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, cons if (auto m = const_cast(msg(id))) { if (auto s = (Signal *)m->sig(sig_name)) { *s = sig; - sortSignalsByAddress(m->sigs); emit signalUpdated(s); } } @@ -157,6 +151,16 @@ DBCManager *dbc() { return &dbc_manager; } +// Msg + +std::vector Msg::getSignals() const { + std::vector ret; + ret.reserve(sigs.size()); + for (auto &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 = []() { @@ -246,7 +250,6 @@ bool dbcmanager::DBCManager::open(const QString &name, const QString &content, Q sig.offset = s.offset; sig.is_little_endian = s.is_little_endian; } - sortSignalsByAddress(m.sigs); } parseExtraInfo(content); name_ = name; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 267157b31a..d877347796 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -52,12 +52,16 @@ struct Signal { struct Msg { QString name; uint32_t size; - QList sigs; + std::vector getSignals() const; const Signal *sig(const QString &sig_name) const { auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; }); return it != sigs.end() ? &(*it) : nullptr; } + +private: + QList sigs; + friend class DBCManager; }; class DBCManager : public QObject { diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 882ea932c6..01fbccf7db 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -3,15 +3,13 @@ #include #include #include -#include #include "tools/cabana/commands.h" // DetailWidget DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { - QWidget *main_widget = new QWidget(this); - QVBoxLayout *main_layout = new QVBoxLayout(main_widget); + QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); // tabbar @@ -23,22 +21,22 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart main_layout->addWidget(tabbar); // message title - QToolBar *toolbar = new QToolBar(this); - toolbar->setIconSize({16, 16}); - toolbar->addWidget(new QLabel("time:")); + QHBoxLayout *title_layout = new QHBoxLayout(); + title_layout->setContentsMargins(0, 6, 0, 0); time_label = new QLabel(this); - time_label->setStyleSheet("font-weight:bold"); - toolbar->addWidget(time_label); + time_label->setToolTip(tr("Current time")); + time_label->setStyleSheet("QLabel{font-weight:bold;}"); + title_layout->addWidget(time_label); name_label = new ElidedLabel(this); - name_label->setContentsMargins(5, 0, 5, 0); - name_label->setStyleSheet("font-weight:bold;"); + name_label->setStyleSheet("QLabel{font-weight:bold;}"); name_label->setAlignment(Qt::AlignCenter); name_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - toolbar->addWidget(name_label); - toolbar->addAction(utils::icon("pencil"), "", this, &DetailWidget::editMsg)->setToolTip(tr("Edit Message")); - remove_msg_act = toolbar->addAction(utils::icon("x-lg"), "", this, &DetailWidget::removeMsg); - remove_msg_act->setToolTip(tr("Remove Message")); - main_layout->addWidget(toolbar); + title_layout->addWidget(name_label); + auto edit_btn = toolButton("pencil", tr("Edit Message")); + title_layout->addWidget(edit_btn); + remove_btn = toolButton("x-lg", tr("Remove Message")); + title_layout->addWidget(remove_btn); + main_layout->addLayout(title_layout); // warning warning_widget = new QWidget(this); @@ -59,19 +57,18 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart splitter->setStretchFactor(1, 1); tab_widget = new QTabWidget(this); + tab_widget->setStyleSheet("QTabWidget::pane {border: none; margin-bottom: -2px;}"); tab_widget->setTabPosition(QTabWidget::South); tab_widget->addTab(splitter, utils::icon("file-earmark-ruled"), "&Msg"); tab_widget->addTab(history_log = new LogsWidget(this), utils::icon("stopwatch"), "&Logs"); main_layout->addWidget(tab_widget); - stacked_layout = new QStackedLayout(this); - stacked_layout->addWidget(new WelcomeWidget(this)); - stacked_layout->addWidget(main_widget); - + QObject::connect(edit_btn, &QToolButton::clicked, this, &DetailWidget::editMsg); + QObject::connect(remove_btn, &QToolButton::clicked, this, &DetailWidget::removeMsg); QObject::connect(binary_view, &BinaryView::resizeSignal, signal_view->model, &SignalModel::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, signal_view->model, &SignalModel::addSignal); QObject::connect(binary_view, &BinaryView::signalHovered, signal_view, &SignalView::signalHovered); - QObject::connect(binary_view, &BinaryView::signalClicked, signal_view, &SignalView::expandSignal); + QObject::connect(binary_view, &BinaryView::signalClicked, [this](const Signal *s) { signal_view->selectSignal(s, true); }); QObject::connect(binary_view, &BinaryView::editSignal, signal_view->model, &SignalModel::saveSignal); QObject::connect(binary_view, &BinaryView::removeSignal, signal_view->model, &SignalModel::removeSignal); QObject::connect(binary_view, &BinaryView::showChart, charts, &ChartsWidget::showChart); @@ -87,9 +84,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart setMessage(tabbar->tabData(index).value()); } }); - QObject::connect(tabbar, &QTabBar::tabCloseRequested, [this](int index) { - tabbar->removeTab(index); - }); + QObject::connect(tabbar, &QTabBar::tabCloseRequested, tabbar, &QTabBar::removeTab); QObject::connect(charts, &ChartsWidget::seriesChanged, signal_view, &SignalView::updateChartState); } @@ -108,18 +103,8 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) { } } -void DetailWidget::removeAll() { - msg_id = std::nullopt; - tabbar->blockSignals(true); - while (tabbar->count() > 0) { - tabbar->removeTab(0); - } - tabbar->blockSignals(false); - stacked_layout->setCurrentIndex(0); -} - void DetailWidget::setMessage(const MessageId &message_id) { - msg_id = message_id; + if (std::exchange(msg_id, message_id) == message_id) return; tabbar->blockSignals(true); int index = tabbar->count() - 1; @@ -135,25 +120,18 @@ void DetailWidget::setMessage(const MessageId &message_id) { tabbar->blockSignals(false); setUpdatesEnabled(false); - - signal_view->setMessage(*msg_id); - binary_view->setMessage(*msg_id); - history_log->setMessage(*msg_id); - - stacked_layout->setCurrentIndex(1); + signal_view->setMessage(msg_id); + binary_view->setMessage(msg_id); + history_log->setMessage(msg_id); refresh(); - splitter->setSizes({1, 2}); - setUpdatesEnabled(true); } void DetailWidget::refresh() { - if (!msg_id) return; - QStringList warnings; - auto msg = dbc()->msg(*msg_id); + auto msg = dbc()->msg(msg_id); if (msg) { - if (msg->size != can->lastMessage(*msg_id).dat.size()) { + if (msg->size != can->lastMessage(msg_id).dat.size()) { warnings.push_back(tr("Message size (%1) is incorrect.").arg(msg->size)); } for (auto s : binary_view->getOverlappingSignals()) { @@ -162,8 +140,8 @@ void DetailWidget::refresh() { } else { warnings.push_back(tr("Drag-Select in binary view to create new signal.")); } - remove_msg_act->setEnabled(msg != nullptr); - name_label->setText(msgName(*msg_id)); + remove_btn->setEnabled(msg != nullptr); + name_label->setText(msgName(msg_id)); if (!warnings.isEmpty()) { warning_label->setText(warnings.join('\n')); @@ -174,7 +152,7 @@ void DetailWidget::refresh() { void DetailWidget::updateState(const QHash *msgs) { time_label->setText(QString::number(can->currentSec(), 'f', 3)); - if (!msg_id || (msgs && !msgs->contains(*msg_id))) + if ((msgs && !msgs->contains(msg_id))) return; if (tab_widget->currentIndex() == 0) @@ -184,17 +162,16 @@ void DetailWidget::updateState(const QHash *msgs) { } void DetailWidget::editMsg() { - MessageId id = *msg_id; - auto msg = dbc()->msg(id); - int size = msg ? msg->size : can->lastMessage(id).dat.size(); - EditMessageDialog dlg(id, msgName(id), size, this); + auto msg = dbc()->msg(msg_id); + int size = msg ? msg->size : can->lastMessage(msg_id).dat.size(); + EditMessageDialog dlg(msg_id, msgName(msg_id), size, this); if (dlg.exec()) { - UndoStack::push(new EditMsgCommand(*msg_id, dlg.name_edit->text(), dlg.size_spin->value())); + UndoStack::push(new EditMsgCommand(msg_id, dlg.name_edit->text(), dlg.size_spin->value())); } } void DetailWidget::removeMsg() { - UndoStack::push(new RemoveMsgCommand(*msg_id)); + UndoStack::push(new RemoveMsgCommand(msg_id)); } // EditMessageDialog @@ -240,10 +217,34 @@ void EditMessageDialog::validateName(const QString &text) { btn_box->button(QDialogButtonBox::Ok)->setEnabled(valid); } -// WelcomeWidget +// CenterWidget -WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { +CenterWidget::CenterWidget(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->addWidget(welcome_widget = createWelcomeWidget()); +} + +void CenterWidget::setMessage(const MessageId &msg_id) { + if (!detail_widget) { + delete welcome_widget; + welcome_widget = nullptr; + layout()->addWidget(detail_widget = new DetailWidget(charts, this)); + } + detail_widget->setMessage(msg_id); +} + +void CenterWidget::clear() { + delete detail_widget; + detail_widget = nullptr; + if (!welcome_widget) { + layout()->addWidget(welcome_widget = createWelcomeWidget()); + } +} + +QWidget *CenterWidget::createWelcomeWidget() { + QWidget *w = new QWidget(this); + QVBoxLayout *main_layout = new QVBoxLayout(w); main_layout->addStretch(0); QLabel *logo = new QLabel("CABANA"); logo->setAlignment(Qt::AlignCenter); @@ -268,7 +269,8 @@ WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { main_layout->addLayout(newShortcutRow("WhatsThis", "Shift+F1")); main_layout->addStretch(0); - setStyleSheet("QLabel{color:darkGray;}"); - setBackgroundRole(QPalette::Base); - setAutoFillBackground(true); + w->setStyleSheet("QLabel{color:darkGray;}"); + w->setBackgroundRole(QPalette::Base); + w->setAutoFillBackground(true); + return w; } diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index b3e353d539..0bfd8a74af 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -2,9 +2,7 @@ #include #include -#include #include -#include #include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/binaryview.h" @@ -24,11 +22,6 @@ public: QSpinBox *size_spin; }; -class WelcomeWidget : public QWidget { -public: - WelcomeWidget(QWidget *parent); -}; - class DetailWidget : public QWidget { Q_OBJECT @@ -36,7 +29,6 @@ public: DetailWidget(ChartsWidget *charts, QWidget *parent); void setMessage(const MessageId &message_id); void refresh(); - void removeAll(); QSize minimumSizeHint() const override { return binary_view->minimumSizeHint(); } private: @@ -45,17 +37,30 @@ private: void removeMsg(); void updateState(const QHash * msgs = nullptr); - std::optional msg_id; + MessageId msg_id; QLabel *time_label, *warning_icon, *warning_label; ElidedLabel *name_label; QWidget *warning_widget; QTabBar *tabbar; QTabWidget *tab_widget; - QAction *remove_msg_act; + QToolButton *remove_btn; LogsWidget *history_log; BinaryView *binary_view; SignalView *signal_view; ChartsWidget *charts; QSplitter *splitter; - QStackedLayout *stacked_layout; +}; + +class CenterWidget : public QWidget { + Q_OBJECT +public: + CenterWidget(ChartsWidget* charts, QWidget *parent); + void setMessage(const MessageId &msg_id); + void clear(); + +private: + QWidget *createWelcomeWidget(); + DetailWidget *detail_widget = nullptr; + QWidget *welcome_widget = nullptr; + ChartsWidget *charts; }; diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index a1c671b68d..abf0b53af8 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -5,8 +5,6 @@ #include #include "tools/cabana/commands.h" -#include "tools/cabana/util.h" - // HistoryLogModel QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { @@ -27,17 +25,19 @@ void HistoryLogModel::setMessage(const MessageId &message_id) { msg_id = message_id; } -void HistoryLogModel::refresh() { +void HistoryLogModel::refresh(bool fetch_message) { beginResetModel(); sigs.clear(); - if (auto dbc_msg = dbc()->msg(*msg_id)) { - sigs = dbc_msg->sigs; + if (auto dbc_msg = dbc()->msg(msg_id)) { + sigs = dbc_msg->getSignals(); } last_fetch_time = 0; has_more_data = true; messages.clear(); hex_colors.clear(); - updateState(); + if (fetch_message) { + updateState(); + } endResetModel(); } @@ -48,9 +48,9 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return show_signals ? sigs[section - 1].name : "Data"; + return show_signals ? sigs[section - 1]->name : "Data"; } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { - return QBrush(getColor(&sigs[section - 1])); + return QBrush(getColor(sigs[section - 1])); } } return {}; @@ -79,17 +79,15 @@ void HistoryLogModel::setFilter(int sig_idx, const QString &value, std::function } void HistoryLogModel::updateState() { - if (msg_id) { - uint64_t current_time = (can->lastMessage(*msg_id).ts + can->routeStartTime()) * 1e9 + 1; - auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); - if (!new_msgs.empty()) { - beginInsertRows({}, 0, new_msgs.size() - 1); - messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); - endInsertRows(); - } - has_more_data = new_msgs.size() >= batch_size; - last_fetch_time = current_time; + uint64_t current_time = (can->lastMessage(msg_id).ts + can->routeStartTime()) * 1e9 + 1; + auto new_msgs = dynamic_mode ? fetchData(current_time, last_fetch_time) : fetchData(0); + if (!new_msgs.empty()) { + beginInsertRows({}, 0, new_msgs.size() - 1); + messages.insert(messages.begin(), std::move_iterator(new_msgs.begin()), std::move_iterator(new_msgs.end())); + endInsertRows(); } + has_more_data = new_msgs.size() >= batch_size; + last_fetch_time = current_time; } void HistoryLogModel::fetchMore(const QModelIndex &parent) { @@ -111,10 +109,10 @@ std::deque HistoryLogModel::fetchData(InputIt first, I for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - if (msg_id->address == c.getAddress() && msg_id->source == c.getSrc()) { + if (msg_id.address == c.getAddress() && msg_id.source == c.getSrc()) { const auto dat = c.getDat(); for (int i = 0; i < sigs.size(); ++i) { - values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), sigs[i]); + values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *sigs[i]); } if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { auto &m = msgs.emplace_back(); @@ -136,7 +134,7 @@ template std::deque HistoryLogModel::fetchData<>(std:: std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { auto events = can->events(); - const auto freq = can->lastMessage(*msg_id).freq; + const auto freq = can->lastMessage(msg_id).freq; const bool update_colors = !display_signals_mode || sigs.empty(); if (dynamic_mode) { @@ -189,7 +187,8 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI // LogsWidget -LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { +LogsWidget::LogsWidget(QWidget *parent) : QFrame(parent) { + setFrameStyle(QFrame::StyledPanel | QFrame::Plain); QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setSpacing(0); @@ -209,7 +208,8 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { h->addStretch(0); h->addWidget(dynamic_mode = new QCheckBox(tr("Dynamic")), 0, Qt::AlignRight); - display_type_cb->addItems({"Signal Value", "Hex Value"}); + display_type_cb->addItems({"Signal", "Hex"}); + display_type_cb->setToolTip(tr("Display signal value or raw hex value")); comp_box->addItems({">", "=", "!=", "<"}); value_edit->setClearButtonEnabled(true); value_edit->setValidator(new QDoubleValidator(-500000, 500000, 6, this)); @@ -219,10 +219,10 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { main_layout->addWidget(toolbar); QFrame *line = new QFrame(this); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); - main_layout->addWidget(line);; - + main_layout->addWidget(line); main_layout->addWidget(logs = new QTableView(this)); logs->setModel(model = new HistoryLogModel(this)); + delegate = new MessageBytesDelegate(this); logs->setItemDelegateForColumn(1, new MessageBytesDelegate(this)); logs->setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); logs->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); @@ -230,7 +230,10 @@ LogsWidget::LogsWidget(QWidget *parent) : QWidget(parent) { logs->verticalHeader()->setVisible(false); logs->setFrameShape(QFrame::NoFrame); - QObject::connect(display_type_cb, SIGNAL(activated(int)), model, SLOT(setDisplayType(int))); + QObject::connect(display_type_cb, qOverload(&QComboBox::activated), [this](int index) { + logs->setItemDelegateForColumn(1, index == 1 ? delegate : nullptr); + model->setDisplayType(index); + }); QObject::connect(dynamic_mode, &QCheckBox::stateChanged, model, &HistoryLogModel::setDynamicMode); QObject::connect(signals_cb, SIGNAL(activated(int)), this, SLOT(setFilter())); QObject::connect(comp_box, SIGNAL(activated(int)), this, SLOT(setFilter())); @@ -247,17 +250,16 @@ void LogsWidget::setMessage(const MessageId &message_id) { } void LogsWidget::refresh() { - if (!model->msg_id) return; - model->setFilter(0, "", nullptr); - model->refresh(); + model->refresh(isVisible()); bool has_signal = model->sigs.size(); if (has_signal) { signals_cb->clear(); - for (auto &s : model->sigs) { - signals_cb->addItem(s.name); + for (auto s : model->sigs) { + signals_cb->addItem(s->name); } } + logs->setItemDelegateForColumn(1, !has_signal || display_type_cb->currentIndex() == 1 ? delegate : nullptr); value_edit->clear(); comp_box->setCurrentIndex(0); filters_widget->setVisible(has_signal); @@ -276,3 +278,15 @@ void LogsWidget::setFilter() { model->setFilter(signals_cb->currentIndex(), value_edit->text(), cmp); model->refresh(); } + +void LogsWidget::updateState() { + if (isVisible() && dynamic_mode->isChecked()) { + model->updateState(); + } +} + +void LogsWidget::showEvent(QShowEvent *event) { + if (dynamic_mode->isChecked() || model->canFetchMore({}) && model->rowCount() == 0) { + model->refresh(); + } +} diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index a1b7bc0098..206d53bc8d 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -1,8 +1,6 @@ #pragma once #include -#include - #include #include #include @@ -11,6 +9,8 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" +#include "tools/cabana/util.h" + using namespace dbcmanager; class HeaderView : public QHeaderView { @@ -36,7 +36,7 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override { return display_signals_mode && !sigs.empty() ? sigs.size() + 1 : 2; } - void refresh(); + void refresh(bool fetch_message = true); public slots: void setDisplayType(int type); @@ -55,7 +55,7 @@ public: std::deque fetchData(InputIt first, InputIt last, uint64_t min_time); std::deque fetchData(uint64_t from_time, uint64_t min_time = 0); - std::optional msg_id; + MessageId msg_id; ChangeTracker hex_colors; bool has_more_data = true; const int batch_size = 50; @@ -64,19 +64,19 @@ public: uint64_t last_fetch_time = 0; std::function filter_cmp = nullptr; std::deque messages; - QList sigs; + std::vector sigs; bool dynamic_mode = true; bool display_signals_mode = true; }; -class LogsWidget : public QWidget { +class LogsWidget : public QFrame { Q_OBJECT public: LogsWidget(QWidget *parent); void setMessage(const MessageId &message_id); - void updateState() {if (dynamic_mode->isChecked()) model->updateState(); } - void showEvent(QShowEvent *event) override { if (dynamic_mode->isChecked()) model->refresh(); } + void updateState(); + void showEvent(QShowEvent *event) override; private slots: void setFilter(); @@ -90,4 +90,5 @@ private: QComboBox *signals_cb, *comp_box, *display_type_cb; QLineEdit *value_edit; QWidget *filters_widget; + MessageBytesDelegate *delegate; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 47ad3a4a6d..bc090b2cc0 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -27,8 +27,8 @@ void qLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const MainWindow::MainWindow() : QMainWindow() { createDockWindows(); - detail_widget = new DetailWidget(charts_widget, this); - setCentralWidget(detail_widget); + center_widget = new CenterWidget(charts_widget, this); + setCentralWidget(center_widget); createActions(); createStatusBar(); createShortcuts(); @@ -60,7 +60,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(this, &MainWindow::showMessage, statusBar(), &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); - QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, detail_widget, &DetailWidget::setMessage); + QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); @@ -175,7 +175,7 @@ void MainWindow::createStatusBar() { progress_bar = new QProgressBar(); progress_bar->setRange(0, 100); progress_bar->setTextVisible(true); - progress_bar->setFixedSize({230, 16}); + progress_bar->setFixedSize({300, 16}); progress_bar->setVisible(false); statusBar()->addWidget(new QLabel(tr("For Help, Press F1"))); statusBar()->addPermanentWidget(progress_bar); @@ -220,7 +220,7 @@ void MainWindow::DBCFileChanged() { void MainWindow::openRoute() { OpenRouteDialog dlg(this); if (dlg.exec()) { - detail_widget->removeAll(); + center_widget->clear(); charts_widget->removeAll(); statusBar()->showMessage(tr("Route %1 loaded").arg(can->routeName()), 2000); } else if (dlg.failedToLoad()) { diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 85d221a231..dd53b1f213 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -60,7 +60,7 @@ protected: VideoWidget *video_widget = nullptr; QDockWidget *video_dock; MessagesWidget *messages_widget; - DetailWidget *detail_widget; + CenterWidget *center_widget; ChartsWidget *charts_widget; QWidget *floating_window = nullptr; QVBoxLayout *charts_layout; diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index 42ac22865c..c880c61058 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -1,17 +1,17 @@ #include "tools/cabana/messageswidget.h" -#include -#include #include -#include #include #include MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0 ,0, 0, 0); // message filter filter = new QLineEdit(this); + QRegularExpression re("\\S+"); + filter->setValidator(new QRegularExpressionValidator(re, this)); filter->setClearButtonEnabled(true); filter->setPlaceholderText(tr("filter messages")); main_layout->addWidget(filter); @@ -44,11 +44,16 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { QObject::connect(dbc(), &DBCManager::DBCFileChanged, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgUpdated, model, &MessageListModel::sortMessages); QObject::connect(dbc(), &DBCManager::msgRemoved, model, &MessageListModel::sortMessages); - QObject::connect(model, &MessageListModel::modelReset, [this]() { selectMessage(*current_msg_id); }); + QObject::connect(model, &MessageListModel::modelReset, [this]() { + if (current_msg_id) { + selectMessage(*current_msg_id); + } + }); QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex ¤t, const QModelIndex &previous) { if (current.isValid() && current.row() < model->msgs.size()) { - if (model->msgs[current.row()] != *current_msg_id) { - current_msg_id = model->msgs[current.row()]; + auto &id = model->msgs[current.row()]; + if (!current_msg_id || id != *current_msg_id) { + current_msg_id = id; emit msgSelectionChanged(*current_msg_id); } } @@ -67,10 +72,10 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { setWhatsThis(tr(R"( Message View
- Byte color:
+ Byte color
constant changing
increasing
- decreasing
+ decreasing )")); } @@ -91,9 +96,10 @@ void MessagesWidget::updateSuppressedButtons() { } void MessagesWidget::reset() { + current_msg_id = std::nullopt; + table_widget->selectionModel()->clear(); model->reset(); filter->clear(); - current_msg_id = std::nullopt; updateSuppressedButtons(); } @@ -138,8 +144,8 @@ void MessageListModel::setFilterString(const QString &string) { if (id.toString().contains(txt, cs) || msgName(id).contains(txt, cs)) return true; // Search by signal name if (const auto msg = dbc()->msg(id)) { - for (auto &signal : msg->sigs) { - if (signal.name.contains(txt, cs)) return true; + for (auto s : msg->getSignals()) { + if (s->name.contains(txt, cs)) return true; } } return false; diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index d88def3acb..926d131c8d 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -1,12 +1,9 @@ #pragma once -#include - #include #include #include #include -#include #include #include "tools/cabana/dbcmanager.h" diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d5099da6f4..e862439b68 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "tools/cabana/commands.h" @@ -48,9 +47,9 @@ void SignalModel::refresh() { beginResetModel(); root.reset(new SignalModel::Item); if (auto msg = dbc()->msg(msg_id)) { - for (auto &s : msg->sigs) { - if (filter_str.isEmpty() || s.name.contains(filter_str, Qt::CaseInsensitive)) { - insertItem(root.get(), root->children.size(), &s); + for (auto s : msg->getSignals()) { + if (filter_str.isEmpty() || s->name.contains(filter_str, Qt::CaseInsensitive)) { + insertItem(root.get(), root->children.size(), s); } } } @@ -58,7 +57,7 @@ void SignalModel::refresh() { } void SignalModel::updateState(const QHash *msgs) { - if (!msgs || (msgs->contains(msg_id))) { + if (!msgs || msgs->contains(msg_id)) { auto &dat = can->lastMessage(msg_id).dat; int row = 0; for (auto item : root->children) { @@ -93,9 +92,8 @@ Qt::ItemFlags SignalModel::flags(const QModelIndex &index) const { } int SignalModel::signalRow(const Signal *sig) const { - auto &children = root->children; - for (int i = 0; i < children.size(); ++i) { - if (children[i]->sig == sig) return i; + for (int i = 0; i < root->children.size(); ++i) { + if (root->children[i]->sig == sig) return i; } return -1; } @@ -129,11 +127,11 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const { case Item::Min: return item->sig->min; case Item::Max: return item->sig->max; case Item::Desc: { - QString val_desc; + QStringList val_desc; for (auto &[val, desc] : item->sig->val_desc) { - val_desc += QString("%1 \"%2\"").arg(val, desc); + val_desc << QString("%1 \"%2\"").arg(val, desc); } - return val_desc; + return val_desc.join(" "); } default: break; } @@ -280,16 +278,24 @@ void SignalModel::handleSignalRemoved(const Signal *sig) { // SignalItemDelegate -SignalItemDelegate::SignalItemDelegate(QObject *parent) { +SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { name_validator = new NameValidator(this); double_validator = new QDoubleValidator(this); double_validator->setLocale(QLocale::C); // Match locale of QString::toDouble() instead of system small_font.setPointSize(8); } +QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { + QSize size = QStyledItemDelegate::sizeHint(option, index); + if (!index.parent().isValid() && index.column() == 0) { + size.rwidth() = std::min(((QWidget*)parent())->size().width() / 2, size.width() + color_label_width + 8); + } + return size; +} + void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto item = (SignalModel::Item *)index.internalPointer(); - if (item && !index.parent().isValid() && index.column() == 0) { + if (index.column() == 0 && item && item->type == SignalModel::Item::Sig) { painter->save(); painter->setRenderHint(QPainter::Antialiasing); if (option.state & QStyle::State_Selected) { @@ -298,7 +304,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // color label auto bg_color = getColor(item->sig); - QRect rc{option.rect.left(), option.rect.top(), 18, option.rect.height()}; + QRect rc{option.rect.left(), option.rect.top(), color_label_width, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 3, 3); @@ -345,22 +351,22 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie // SignalView -SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QWidget(parent) { +SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QFrame(parent) { + setFrameStyle(QFrame::StyledPanel | QFrame::Plain); // title bar QWidget *title_bar = new QWidget(this); title_bar->setAutoFillBackground(true); QHBoxLayout *hl = new QHBoxLayout(title_bar); hl->addWidget(signal_count_lb = new QLabel()); filter_edit = new QLineEdit(this); + QRegularExpression re("\\S+"); + filter_edit->setValidator(new QRegularExpressionValidator(re, this)); filter_edit->setClearButtonEnabled(true); - filter_edit->setPlaceholderText(tr("filter signals by name")); + filter_edit->setPlaceholderText(tr("filter signals")); hl->addWidget(filter_edit); hl->addStretch(1); - auto collapse_btn = new QToolButton(); - collapse_btn->setIcon(utils::icon("dash-square")); + auto collapse_btn = toolButton("dash-square", tr("Collapse All")); collapse_btn->setIconSize({12, 12}); - collapse_btn->setAutoRaise(true); - collapse_btn->setToolTip(tr("Collapse All")); hl->addWidget(collapse_btn); // tree view @@ -371,7 +377,8 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), tree->setHeaderHidden(true); tree->setMouseTracking(true); tree->setExpandsOnDoubleClick(false); - tree->header()->setSectionResizeMode(QHeaderView::Stretch); + tree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + tree->header()->setStretchLastSection(true); tree->setMinimumHeight(300); tree->setStyleSheet("QSpinBox{background-color:white;border:none;} QLineEdit{background-color:white;}"); @@ -389,7 +396,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); - QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { expandSignal(sig); }); + QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { selectSignal(sig); }); setWhatsThis(tr(R"( Signal view
@@ -404,16 +411,6 @@ void SignalView::setMessage(const MessageId &id) { } void SignalView::rowsChanged() { - auto create_btn = [](const QString &id, const QString &tooltip) { - auto btn = new QToolButton(); - btn->setIcon(utils::icon(id)); - btn->setToolTip(tooltip); - btn->setAutoRaise(true); - return btn; - }; - - signal_count_lb->setText(tr("Signals: %1").arg(model->rowCount())); - for (int i = 0; i < model->rowCount(); ++i) { auto index = model->index(i, 1); if (!tree->indexWidget(index)) { @@ -422,8 +419,8 @@ void SignalView::rowsChanged() { h->setContentsMargins(0, 2, 0, 2); h->addStretch(1); - auto remove_btn = create_btn("x", tr("Remove signal")); - auto plot_btn = create_btn("graph-up", ""); + auto remove_btn = toolButton("x", tr("Remove signal")); + auto plot_btn = toolButton("graph-up", ""); plot_btn->setCheckable(true); h->addWidget(plot_btn); h->addWidget(remove_btn); @@ -436,6 +433,7 @@ void SignalView::rowsChanged() { }); } } + signal_count_lb->setText(tr("Signals: %1").arg(model->rowCount())); updateChartState(); } @@ -449,23 +447,26 @@ void SignalView::rowClicked(const QModelIndex &index) { } } -void SignalView::expandSignal(const Signal *sig) { +void SignalView::selectSignal(const Signal *sig, bool expand) { if (int row = model->signalRow(sig); row != -1) { auto idx = model->index(row, 0); - bool expand = !tree->isExpanded(idx); - tree->setExpanded(idx, expand); + if (expand) { + tree->setExpanded(idx, !tree->isExpanded(idx)); + } tree->scrollTo(idx, QAbstractItemView::PositionAtTop); - if (expand) tree->setCurrentIndex(idx); + tree->setCurrentIndex(idx); } } void SignalView::updateChartState() { int i = 0; for (auto item : model->root->children) { - auto plot_btn = tree->indexWidget(model->index(i, 1))->findChildren()[0]; bool chart_opened = charts->hasSignal(msg_id, item->sig); - plot_btn->setChecked(chart_opened); - plot_btn->setToolTip(chart_opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened plot")); + auto buttons = tree->indexWidget(model->index(i, 1))->findChildren(); + if (buttons.size() > 0) { + buttons[0]->setChecked(chart_opened); + buttons[0]->setToolTip(chart_opened ? tr("Close Plot") : tr("Show Plot\nSHIFT click to add to previous opened plot")); + } ++i; } } diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index efdc653584..3cb193b62f 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -80,12 +80,14 @@ class SignalItemDelegate : public QStyledItemDelegate { public: SignalItemDelegate(QObject *parent); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QValidator *name_validator, *double_validator; QFont small_font; + const int color_label_width = 18; }; -class SignalView : public QWidget { +class SignalView : public QFrame { Q_OBJECT public: @@ -93,7 +95,7 @@ public: void setMessage(const MessageId &id); void signalHovered(const Signal *sig); void updateChartState(); - void expandSignal(const Signal *sig); + void selectSignal(const Signal *sig, bool expand = false); void rowClicked(const QModelIndex &index); SignalModel *model = nullptr; diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 8fdfbd5c1b..3e631d3709 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -31,10 +31,12 @@ bool AbstractStream::updateEvent(const Event *event) { data.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); data.count = ++counters[id]; data.freq = data.count / std::max(1.0, current_sec); - change_trackers[id].compute(data.dat, data.ts, data.freq); - data.colors = change_trackers[id].colors; - data.last_change_t = change_trackers[id].last_change_t; - data.bit_change_counts = change_trackers[id].bit_change_counts; + + auto &tracker = change_trackers[id]; + tracker.compute(data.dat, data.ts, data.freq); + data.colors = tracker.colors; + data.last_change_t = tracker.last_change_t; + data.bit_change_counts = tracker.bit_change_counts; } double ts = millis_since_boot(); diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 9a8ab710bc..6f9f2d016b 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -23,9 +23,11 @@ TEST_CASE("DBCManager::generateDBC") { auto &new_m = new_msgs.at(address); REQUIRE(m.name == new_m.name); REQUIRE(m.size == new_m.size); - REQUIRE(m.sigs.size() == new_m.sigs.size()); - for (int i = 0; i < m.sigs.size(); ++i) { - REQUIRE(m.sigs[i] == new_m.sigs[i]); + REQUIRE(m.getSignals().size() == new_m.getSignals().size()); + auto sigs = m.getSignals(); + auto new_sigs = new_m.getSignals(); + for (int i = 0; i < sigs.size(); ++i) { + REQUIRE(*sigs[i] == *new_sigs[i]); } } } @@ -44,9 +46,9 @@ TEST_CASE("Parse can messages") { for (const auto &c : e->event.getCan()) { const auto msg = dbc.msg(c.getAddress()); if (c.getSrc() == 0 && msg) { - for (auto &sig : msg->sigs) { - double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), sig); - values_1[{c.getAddress(), sig.name}].push_back(val); + for (auto sig : msg->getSignals()) { + double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), *sig); + values_1[{c.getAddress(), sig->name}].push_back(val); } } } diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 6415cc8e16..4f79f9a3ac 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -73,32 +74,23 @@ MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegat } void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QStyleOptionViewItemV4 opt = option; - initStyleOption(&opt, index); - - auto byte_list = opt.text.split(" "); - if (byte_list.size() <= 1) { - QStyledItemDelegate::paint(painter, option, index); - return; - } - auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText: QPalette::Text; painter->setPen(option.palette.color(color_role)); painter->setFont(fixed_font); - QRect space = painter->boundingRect(opt.rect, opt.displayAlignment, " "); - QRect pos = painter->boundingRect(opt.rect, opt.displayAlignment, "00"); - pos.moveLeft(pos.x() + space.width()); - - int m = space.width() / 2; + int space = painter->boundingRect(option.rect, option.displayAlignment, " ").width(); + QRect pos = painter->boundingRect(option.rect, option.displayAlignment, "00").adjusted(0, 0, 2, 0); + pos.moveLeft(pos.x() + space); + int m = space / 2; const QMargins margins(m, m, m, m); auto colors = index.data(Qt::UserRole).value>(); + auto byte_list = index.data(Qt::DisplayRole).toString().split(" "); for (int i = 0; i < byte_list.size(); ++i) { - if (i < colors.size()) { + if (i < colors.size() && colors[i].alpha() > 0) { painter->fillRect(pos.marginsAdded(margins), colors[i]); } - painter->drawText(pos, opt.displayAlignment, byte_list[i]); - pos.moveLeft(pos.right() + space.width()); + painter->drawText(pos, Qt::AlignCenter, byte_list[i]); + pos.moveLeft(pos.right() + space); } } @@ -124,12 +116,25 @@ namespace utils { QPixmap icon(const QString &id) { static bool dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > QApplication::style()->standardPalette().color(QPalette::Background).value(); - QPixmap pm = bootstrapPixmap(id); - if (dark_theme) { - QPainter p(&pm); - p.setCompositionMode(QPainter::CompositionMode_SourceIn); - p.fillRect(pm.rect(), Qt::lightGray); + QPixmap pm; + QString key = "bootstrap_" % id % (dark_theme ? "1" : "0"); + if (!QPixmapCache::find(key, &pm)) { + pm = bootstrapPixmap(id); + if (dark_theme) { + QPainter p(&pm); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(pm.rect(), Qt::lightGray); + } + QPixmapCache::insert(key, pm); } return pm; } } // namespace utils + +QToolButton *toolButton(const QString &icon, const QString &tooltip) { + auto btn = new QToolButton(); + btn->setIcon(utils::icon(icon)); + btn->setToolTip(tooltip); + btn->setAutoRaise(true); + return btn; +}; diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 2717451061..b72ddfcaa0 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include #include #include "tools/cabana/dbcmanager.h" @@ -52,3 +54,5 @@ public: namespace utils { QPixmap icon(const QString &id); } + +QToolButton *toolButton(const QString &icon, const QString &tooltip); diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 2b5374d85f..536ae7ba97 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -28,9 +28,9 @@ inline QString formatTime(int seconds) { VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); QFrame *frame = new QFrame(this); - frame->setFrameShape(QFrame::StyledPanel); - frame->setFrameShadow(QFrame::Sunken); + frame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); main_layout->addWidget(frame); QVBoxLayout *frame_layout = new QVBoxLayout(frame); From 500b1b4a5c7e5a1402325092a92774805b95b324 Mon Sep 17 00:00:00 2001 From: Webomcar <124065911+Webomcar@users.noreply.github.com> Date: Tue, 21 Feb 2023 00:23:42 +0100 Subject: [PATCH 0992/1179] Add missing FW for Toyota C-HR Hybrid 2020 (#27366) * Update values.py * Verified C-HR 2020 is TSS-P --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 59eece1e4b..3bc918f784 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -178,7 +178,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 0fcabe163c..0639d46ec0 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -119,7 +119,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-23"), CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), - CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-19"), + CAR.CHRH: ToyotaCarInfo("Toyota C-HR Hybrid 2017-20"), CAR.CHRH_TSS2: ToyotaCarInfo("Toyota C-HR Hybrid 2021-22"), CAR.COROLLA: ToyotaCarInfo("Toyota Corolla 2017-19"), CAR.COROLLA_TSS2: [ @@ -712,6 +712,7 @@ FW_VERSIONS = { b'8646FF404000 ', b'8646FF406000 ', b'8646FF407000 ', + b'8646FF407100 ', ], }, CAR.CHRH_TSS2: { From c3ba2a025ba96684cd0371ae46b3847589b5c773 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 20 Feb 2023 16:28:32 -0700 Subject: [PATCH 0993/1179] GM: detect unplugged or missing radar (#27245) * Add flashed Volt fingerprint * Add another fingerprint * Detect radar header message * dashcamOnly if ASCM vehicle with radar unavailable May be able to change this in the future to OP long off with experimental long available * no submodule update * Revert minEnableSpeed * combine into one fingerprint * Don't use GM radar DBC Co-authored-by: Shane Smiskol * unused * add new FP * update docs * use_off_car_defaults use_off_car_defaults * update docs --------- Co-authored-by: Shane Smiskol --- selfdrive/car/gm/interface.py | 9 ++++++--- selfdrive/car/gm/values.py | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index c28274011e..032a49e761 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -6,7 +6,8 @@ from panda import Panda from common.numpy_fast import interp from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config -from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR +from selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG +from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus from selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD from selfdrive.controls.lib.drive_helpers import apply_center_deadzone @@ -87,6 +88,7 @@ class CarInterface(CarInterfaceBase): ret.carName = "gm" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)] ret.autoResumeSng = False + use_off_car_defaults = len(fingerprint[0]) == 0 # Pick sensible carParams during offline doc generation/CI jobs if candidate in EV_CAR: ret.transmissionType = TransmissionType.direct @@ -125,7 +127,7 @@ class CarInterface(CarInterfaceBase): else: # ASCM, OBD-II harness ret.openpilotLongitudinalControl = True ret.networkLocation = NetworkLocation.gateway - ret.radarUnavailable = False + ret.radarUnavailable = RADAR_HEADER_MSG not in fingerprint[CanBus.OBSTACLE] and not use_off_car_defaults ret.pcmCruise = False # stock non-adaptive cruise control is kept off # supports stop and go, but initial engage must (conservatively) be above 18mph ret.minEnableSpeed = 18 * CV.MPH_TO_MS @@ -138,7 +140,8 @@ class CarInterface(CarInterfaceBase): # These cars have been put into dashcam only due to both a lack of users and test coverage. # These cars likely still work fine. Once a user confirms each car works and a test route is # added to selfdrive/car/tests/routes.py, we can remove it from this list. - ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} + ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL, CAR.EQUINOX} or \ + (ret.networkLocation == NetworkLocation.gateway and ret.radarUnavailable) # Start with a baseline tuning for all GM vehicles. Override tuning as needed in each model section below. ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 207af6bb05..c4791738b8 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -151,6 +151,10 @@ FINGERPRINTS = { # Volt Premier w/ ACC 2018 { 170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 578: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 715: 8, 717: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1516: 8, 1601: 8, 1618: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1930: 7, 2016: 8, 2018: 8, 2020: 8, 2024: 8, 2028: 8 + }, + # Volt Premier 2018 w/ flashed firmware, no radar + { + 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 368: 8, 381: 2, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 5, 844: 8, 853: 8, 866: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7 }], CAR.BUICK_REGAL : [ # Regal TourX Essence w/ ACC 2018 From 14d44e444418e1b6bd23afe5a371db886e8273e2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 15:33:15 -0800 Subject: [PATCH 0994/1179] GM: remove redundant CarController class variable (#27280) * clean up * fix check * only set ts_nanos on update --- selfdrive/car/gm/carcontroller.py | 9 +++------ selfdrive/car/gm/carstate.py | 3 ++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 73085d30b0..42eaf7e88a 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -30,7 +30,6 @@ class CarController: self.cancel_counter = 0 self.lka_steering_cmd_counter = 0 - self.sent_lka_steering_cmd = False self.lka_icon_status_last = (False, False) self.params = CarControllerParams(self.CP) @@ -59,19 +58,17 @@ class CarController: # - until we're in sync with camera so counters align when relay closes, preventing a fault. # openpilot can subtly drift, so this is activated throughout a drive to stay synced out_of_sync = self.lka_steering_cmd_counter % 4 != (CS.cam_lka_steering_cmd_counter + 1) % 4 - if not self.sent_lka_steering_cmd or out_of_sync: + if CS.loopback_lka_steering_cmd_ts_nanos == 0 or out_of_sync: steer_step = self.params.STEER_STEP - if CS.loopback_lka_steering_cmd_updated: - self.lka_steering_cmd_counter += 1 - self.sent_lka_steering_cmd = True + self.lka_steering_cmd_counter += 1 if CS.loopback_lka_steering_cmd_updated else 0 # Avoid GM EPS faults when transmitting messages too close together: skip this transmit if we # received the ASCMLKASteeringCmd loopback confirmation too recently last_lka_steer_msg_ms = (now_nanos - CS.loopback_lka_steering_cmd_ts_nanos) * 1e-6 if (self.frame - self.last_steer_frame) >= steer_step and last_lka_steer_msg_ms > MIN_STEER_MSG_INTERVAL_MS: # Initialize ASCMLKASteeringCmd counter using the camera until we get a msg on the bus - if not self.sent_lka_steering_cmd: + if CS.loopback_lka_steering_cmd_ts_nanos == 0: self.lka_steering_cmd_counter = CS.pt_lka_steering_cmd_counter + 1 if CC.latActive: diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 3c7d35f2dc..2f9c952876 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -37,7 +37,8 @@ class CarState(CarStateBase): # Variables used for avoiding LKAS faults self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 - self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] + if self.loopback_lka_steering_cmd_updated: + self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] if self.CP.networkLocation == NetworkLocation.fwdCamera: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] From 79749a306c7621e047d1a57fae40493b40c25954 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 16:12:11 -0800 Subject: [PATCH 0995/1179] GM: add longitudinal delay to Escalade (#27406) * add delay to escalade too * order --- selfdrive/car/gm/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 032a49e761..44ece1d415 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -207,6 +207,7 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.95 # 116 inches in meters ret.steerRatio = 17.3 ret.centerToFront = ret.wheelbase * 0.5 + ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.ESCALADE_ESV: From dff054d4dfb6c08a471315778dadf6c0dc24207d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 16:13:01 -0800 Subject: [PATCH 0996/1179] Ford: filter steering pressed (#27123) * ford steering pressed filter * raise to 1.0 * Update ref_commit --- selfdrive/car/ford/carstate.py | 2 +- selfdrive/car/ford/values.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index f97225e9f2..21af1062f3 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -37,7 +37,7 @@ class CarState(CarStateBase): # steering wheel ret.steeringAngleDeg = cp.vl["SteeringPinion_Data"]["StePinComp_An_Est"] ret.steeringTorque = cp.vl["EPAS_INFO"]["SteeringColumnTorque"] - ret.steeringPressed = abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE + ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5) ret.steerFaultTemporary = cp.vl["EPAS_INFO"]["EPAS_Failure"] == 1 ret.steerFaultPermanent = cp.vl["EPAS_INFO"]["EPAS_Failure"] in (2, 3) # ret.espDisabled = False # TODO: find traction control signal diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 951cd09ba0..6be93269c4 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -24,7 +24,7 @@ class CarControllerParams: BUTTONS_STEP = 10 / 2 CURVATURE_MAX = 0.02 # Max curvature for steering command, m^-1 - STEER_DRIVER_ALLOWANCE = 0.8 # Driver intervention threshold, Nm + STEER_DRIVER_ALLOWANCE = 1.0 # Driver intervention threshold, Nm # Curvature rate limits # TODO: unify field names used by curvature and angle control cars diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index e9016cc27c..c158382fe8 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -70753c5f491de7432ff22f4ef560820ce9919b2e +f7ff7e7d37c276c31d8d44c73a0091b5996650b1 From ea419c5764739555673d5545f16cff7c05f9e6c0 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 20 Feb 2023 16:29:17 -0800 Subject: [PATCH 0997/1179] add 'remount device' to permanent calibration invalid alert (#27407) --- selfdrive/controls/lib/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index a85e48649f..4e664d8cf0 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -292,7 +292,7 @@ def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging rpy = sm['liveCalibration'].rpyCalib yaw = math.degrees(rpy[2] if len(rpy) == 3 else math.nan) pitch = math.degrees(rpy[1] if len(rpy) == 3 else math.nan) - angles = f"Pitch: {pitch:.1f}°, Yaw: {yaw:.1f}°" + angles = f"Remount Device (Pitch: {pitch:.1f}°, Yaw: {yaw:.1f}°)" return NormalPermanentAlert("Calibration Invalid", angles) From 3c66106539e5aad272c967009e23e4ff8508157c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Feb 2023 18:02:52 -0800 Subject: [PATCH 0998/1179] Chrysler Pacifica Hybrid 2017: add missing CAN FP (#27408) add missing 840: 8 --- selfdrive/car/chrysler/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 16ebb4fa11..2a5daf440c 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -93,7 +93,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { FINGERPRINTS = { CAR.PACIFICA_2017_HYBRID: [{ - 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 788:3, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 3, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1892: 8, 2016: 8, 2024: 8 + 168: 8, 257: 5, 258: 8, 264: 8, 268: 8, 270: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 291: 8, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 515: 7, 516: 7, 517: 7, 518: 7, 520: 8, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 653: 8, 654: 8, 655: 8, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 701: 8, 704: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 782: 8, 784: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 840: 8, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 878: 8, 882: 8, 897: 8, 908: 8, 924: 3, 926: 3, 929: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 958: 8, 959: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1082: 8, 1083: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1225: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1284: 8, 1537: 8, 1538: 8, 1562: 8, 1568: 8, 1856: 8, 1858: 8, 1860: 8, 1865: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1892: 8, 2016: 8, 2024: 8 }], CAR.PACIFICA_2018: [{ 55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 8, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8 From 2008332bd42528ae56d937a2ec0e9a1dd244b2ea Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Feb 2023 15:27:48 -0800 Subject: [PATCH 0999/1179] GM: revert custom Bolt torque tune (#27403) * Revert "GM: cleanup torque feedforward function (#27347)" This reverts commit 8c099dd4e5adf040f7f454714cf729725bee7f91. * Revert "Chevrolet Bolt: Non-linear torque tune (#27344)" This reverts commit e49748d571d06a65a4361dde1f2f63c7294da13a. * update refs --- selfdrive/car/gm/interface.py | 43 +-------------------- selfdrive/car/interfaces.py | 4 +- selfdrive/controls/lib/latcontrol_torque.py | 4 +- 3 files changed, 6 insertions(+), 45 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 44ece1d415..7e6e71c642 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -3,13 +3,11 @@ from cereal import car from math import fabs from panda import Panda -from common.numpy_fast import interp from common.conversions import Conversions as CV from selfdrive.car import STD_CARGO_KG, create_button_event, scale_tire_stiffness, get_safety_config from selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG from selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus -from selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD -from selfdrive.controls.lib.drive_helpers import apply_center_deadzone +from selfdrive.car.interfaces import CarInterfaceBase ButtonType = car.CarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -46,43 +44,6 @@ class CarInterface(CarInterfaceBase): else: return CarInterfaceBase.get_steer_feedforward_default - @staticmethod - def torque_from_lateral_accel_bolt(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, vego, friction_compensation): - friction_interp = interp( - apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), - [-FRICTION_THRESHOLD, FRICTION_THRESHOLD], - [-torque_params.friction, torque_params.friction] - ) - friction = friction_interp if friction_compensation else 0.0 - steer_torque = lateral_accel_value / torque_params.latAccelFactor - - # TODO: - # 1. Learn the correction factors from data - # 2. Generalize the logic to other GM torque control platforms - steer_break_pts = [-1.0, -0.9, -0.75, -0.5, 0.0, 0.5, 0.75, 0.9, 1.0] - steer_lataccel_factors = [1.5, 1.15, 1.02, 1.0, 1.0, 1.0, 1.02, 1.15, 1.5] - steer_correction_factor = interp( - steer_torque, - steer_break_pts, - steer_lataccel_factors - ) - - vego_break_pts = [0.0, 10.0, 15.0, 20.0, 100.0] - vego_lataccel_factors = [1.5, 1.5, 1.25, 1.0, 1.0] - vego_correction_factor = interp( - vego, - vego_break_pts, - vego_lataccel_factors, - ) - - return (steer_torque + friction) / (steer_correction_factor * vego_correction_factor) - - def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType: - if self.CP.carFingerprint == CAR.BOLT_EUV: - return self.torque_from_lateral_accel_bolt - else: - return self.torque_from_lateral_accel_linear - @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long): ret.carName = "gm" @@ -227,7 +188,7 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 16.8 ret.centerToFront = ret.wheelbase * 0.4 tire_stiffness_factor = 1.0 - ret.steerActuatorDelay = 0.12 + ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.SILVERADO: diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index f1e2081d05..249818369c 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,7 +18,7 @@ from selfdrive.controls.lib.vehicle_model import VehicleModel ButtonType = car.CarState.ButtonEvent.Type GearShifter = car.CarState.GearShifter EventName = car.CarEvent.EventName -TorqueFromLateralAccelCallbackType = Callable[[float, car.CarParams.LateralTorqueTuning, float, float, float, bool], float] +TorqueFromLateralAccelCallbackType = Callable[[float, car.CarParams.LateralTorqueTuning, float, float, bool], float] MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS ACCEL_MAX = 2.0 @@ -131,7 +131,7 @@ class CarInterfaceBase(ABC): return self.get_steer_feedforward_default @staticmethod - def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, vego, friction_compensation): + def torque_from_lateral_accel_linear(lateral_accel_value, torque_params, lateral_accel_error, lateral_accel_deadzone, friction_compensation): # The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction) friction_interp = interp( apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone), diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 9129693e5a..2f56094379 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -64,10 +64,10 @@ class LatControlTorque(LatControl): error = setpoint - measurement gravity_adjusted_lateral_accel = desired_lateral_accel - params.roll * ACCELERATION_DUE_TO_GRAVITY pid_log.error = self.torque_from_lateral_accel(error, self.torque_params, error, - lateral_accel_deadzone, CS.vEgo, friction_compensation=False) + lateral_accel_deadzone, friction_compensation=False) ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params, desired_lateral_accel - actual_lateral_accel, - lateral_accel_deadzone, CS.vEgo, friction_compensation=True) + lateral_accel_deadzone, friction_compensation=True) freeze_integrator = steer_limited or CS.steeringPressed or CS.vEgo < 5 output_torque = self.pid.update(pid_log.error, From 1504c10760627406ce26478bcb98957c64deafac Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Feb 2023 15:48:10 -0800 Subject: [PATCH 1000/1179] GM: revert steering limits update (#27413) * Revert " GM: update steering limits (#27331)" This reverts commit 1cdf80003dcaea79375cf398ec65849424f2f44b. * update refs * bump panda --- panda | 2 +- selfdrive/car/gm/values.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panda b/panda index d2c2d5f926..9fe24bd368 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit d2c2d5f926537a132a253277998ef350fe866d27 +Subproject commit 9fe24bd3683377146b04c68ab94d0935f0bd9d78 diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index c4791738b8..2ac418b629 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -14,8 +14,8 @@ class CarControllerParams: STEER_STEP = 3 # Active control frames per command (~33hz) INACTIVE_STEER_STEP = 10 # Inactive control frames per command (10hz) STEER_DELTA_UP = 10 # Delta rates require review due to observed EPS weakness - STEER_DELTA_DOWN = 15 - STEER_DRIVER_ALLOWANCE = 65 + STEER_DELTA_DOWN = 25 + STEER_DRIVER_ALLOWANCE = 50 STEER_DRIVER_MULTIPLIER = 4 STEER_DRIVER_FACTOR = 100 NEAR_STOP_BRAKE_PHASE = 0.5 # m/s diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index c158382fe8..07fe22b022 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f7ff7e7d37c276c31d8d44c73a0091b5996650b1 +4ad02871365f4cbd83c6b4c4f8ad6bb73015a626 \ No newline at end of file From f381b694013ef662c5d7638fe7b706315ce9547d Mon Sep 17 00:00:00 2001 From: huifan0114 <108561744+huifan0114@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:14:19 +0800 Subject: [PATCH 1001/1179] =?UTF-8?q?=C5=A0koda:=20add=20missing=20FW=20ve?= =?UTF-8?q?rsions=20for=202019=20Kodiaq=20(#27410)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update values.py * remove duplicate --------- Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index cd30bef73b..158a178b03 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1050,6 +1050,7 @@ FW_VERSIONS = { b'\xf1\x8704E906027DD\xf1\x893123', b'\xf1\x8704L906026DE\xf1\x895418', b'\xf1\x875NA907115E \xf1\x890003', + b'\xf1\x875NA907115E \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870D9300043 \xf1\x895202', @@ -1058,8 +1059,8 @@ FW_VERSIONS = { b'\xf1\x870DL300013G \xf1\x892119', ], (Ecu.srs, 0x715, None): [ - b'\xf1\x873Q0959655BJ\xf1\x890703\xf1\x82\0161213001211001205212111052100', - b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\0161213001211001205212112052100', + b'\xf1\x873Q0959655BJ\xf1\x890703\xf1\x82\x0e1213001211001205212111052100', + b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', ], (Ecu.eps, 0x712, None): [ From 72539fa177a4e3f320daf3257038ef3f2e4893ac Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Feb 2023 21:34:02 -0800 Subject: [PATCH 1002/1179] AGNOS system reset: handle ABL reset (#27418) * AGNOS system reset: handle ABL reset * no more tapping * eta --- selfdrive/ui/qt/setup/reset.cc | 49 ++++++++++++++++-------- selfdrive/ui/qt/setup/reset.h | 11 +++++- selfdrive/ui/translations/main_de.ts | 21 +++++----- selfdrive/ui/translations/main_ja.ts | 21 +++++----- selfdrive/ui/translations/main_ko.ts | 21 +++++----- selfdrive/ui/translations/main_pt-BR.ts | 21 +++++----- selfdrive/ui/translations/main_zh-CHS.ts | 21 +++++----- selfdrive/ui/translations/main_zh-CHT.ts | 21 +++++----- 8 files changed, 107 insertions(+), 79 deletions(-) diff --git a/selfdrive/ui/qt/setup/reset.cc b/selfdrive/ui/qt/setup/reset.cc index 582217c1d7..ccf9bf8053 100644 --- a/selfdrive/ui/qt/setup/reset.cc +++ b/selfdrive/ui/qt/setup/reset.cc @@ -11,14 +11,11 @@ #define NVME "/dev/nvme0n1" #define USERDATA "/dev/disk/by-partlabel/userdata" -void Reset::doReset() { - // best effort to wipe nvme and sd card +void Reset::doErase() { + // best effort to wipe nvme std::system("sudo umount " NVME); std::system("yes | sudo mkfs.ext4 " NVME); - // we handle two cases here - // * user-prompted factory reset - // * recovering from a corrupt userdata by formatting int rm = std::system("sudo rm -rf /data/*"); std::system("sudo umount " USERDATA); int fmt = std::system("yes | sudo mkfs.ext4 " USERDATA); @@ -30,22 +27,26 @@ void Reset::doReset() { rebootBtn->show(); } +void Reset::startReset() { + body->setText(tr("Resetting device...\nThis may take up to a minute.")); + rejectBtn->hide(); + rebootBtn->hide(); + confirmBtn->hide(); +#ifdef __aarch64__ + QTimer::singleShot(100, this, &Reset::doErase); +#endif +} + void Reset::confirm() { const QString confirm_txt = tr("Are you sure you want to reset your device?"); if (body->text() != confirm_txt) { body->setText(confirm_txt); } else { - body->setText(tr("Resetting device...")); - rejectBtn->hide(); - rebootBtn->hide(); - confirmBtn->hide(); -#ifdef __aarch64__ - QTimer::singleShot(100, this, &Reset::doReset); -#endif + startReset(); } } -Reset::Reset(bool recover, QWidget *parent) : QWidget(parent) { +Reset::Reset(ResetMode mode, QWidget *parent) : QWidget(parent) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(45, 220, 45, 45); main_layout->setSpacing(0); @@ -56,7 +57,7 @@ Reset::Reset(bool recover, QWidget *parent) : QWidget(parent) { main_layout->addSpacing(60); - body = new QLabel(tr("System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot.")); + body = new QLabel(tr("Press confirm to erase all content and settings. Press cancel to resume boot.")); body->setWordWrap(true); body->setStyleSheet("font-size: 80px; font-weight: light;"); main_layout->addWidget(body, 1, Qt::AlignTop | Qt::AlignLeft); @@ -82,10 +83,16 @@ Reset::Reset(bool recover, QWidget *parent) : QWidget(parent) { blayout->addWidget(confirmBtn); QObject::connect(confirmBtn, &QPushButton::clicked, this, &Reset::confirm); + bool recover = mode == ResetMode::RECOVER; rejectBtn->setVisible(!recover); rebootBtn->setVisible(recover); if (recover) { - body->setText(tr("Unable to mount data partition. Press confirm to reset your device.")); + body->setText(tr("Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device.")); + } + + // automatically start if we're just finishing up an ABL reset + if (mode == ResetMode::FORMAT) { + startReset(); } setStyleSheet(R"( @@ -108,9 +115,17 @@ Reset::Reset(bool recover, QWidget *parent) : QWidget(parent) { } int main(int argc, char *argv[]) { - bool recover = argc > 1 && strcmp(argv[1], "--recover") == 0; + ResetMode mode = ResetMode::USER_RESET; + if (argc > 1) { + if (strcmp(argv[1], "--recover") == 0) { + mode = ResetMode::RECOVER; + } else if (strcmp(argv[1], "--format") == 0) { + mode = ResetMode::FORMAT; + } + } + QApplication a(argc, argv); - Reset reset(recover); + Reset reset(mode); setMainWindow(&reset); return a.exec(); } diff --git a/selfdrive/ui/qt/setup/reset.h b/selfdrive/ui/qt/setup/reset.h index 3a4994077c..04a191d829 100644 --- a/selfdrive/ui/qt/setup/reset.h +++ b/selfdrive/ui/qt/setup/reset.h @@ -2,18 +2,25 @@ #include #include +enum ResetMode { + USER_RESET, // user initiated a factory reset from openpilot + RECOVER, // userdata is corrupt for some reason, give a chance to recover + FORMAT, // finish up an ABL factory reset +}; + class Reset : public QWidget { Q_OBJECT public: - explicit Reset(bool recover = false, QWidget *parent = 0); + explicit Reset(ResetMode mode, QWidget *parent = 0); private: QLabel *body; QPushButton *rejectBtn; QPushButton *rebootBtn; QPushButton *confirmBtn; - void doReset(); + void doErase(); + void startReset(); private slots: void confirm(); diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index b40812af7c..77670ede3b 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -576,18 +576,10 @@ location set Are you sure you want to reset your device? Bist du sicher, dass du das Gerät auf Werkseinstellungen zurücksetzen möchtest?
- - Resetting device... - Gerät wird zurückgesetzt... - System Reset System auf Werkseinstellungen zurücksetzen - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Zurücksetzen auf Werkseinstellungen wurde ausgewählt. Drücke Annehmen, um alle Inhalte und Einstellungen zu löschen. Drücke Abbrechen, um mit dem Starten des Gerätes fortzufahren. - Cancel Abbrechen @@ -601,8 +593,17 @@ location set Bestätigen - Unable to mount data partition. Press confirm to reset your device. - Datenpartition kann nicht geöffnet werden. Drücke Annehmen, um dein Gerät auf Werkseinstellungen zurückzusetzen. + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + + + + Press confirm to erase all content and settings. Press cancel to resume boot. + + + + Resetting device... +This may take up to a minute. +
diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index ed08a52df5..856beee7bc 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -574,18 +574,10 @@ location set Are you sure you want to reset your device? 初期化してもよろしいですか? - - Resetting device... - デバイスが初期化されます... - System Reset システムを初期化 - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - システムの初期化をリクエストしました。「確認」ボタンを押すとデバイスが初期化されます。「キャンセル」ボタンを押すと起動を続行します。 - Cancel キャンセル @@ -599,8 +591,17 @@ location set 確認 - Unable to mount data partition. Press confirm to reset your device. - 「data」パーティションをマウントできません。「確認」ボタンを押すとデバイスが初期化されます。 + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + + + + Press confirm to erase all content and settings. Press cancel to resume boot. + + + + Resetting device... +This may take up to a minute. + diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 7b742a5048..ee5bb4fd36 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -574,18 +574,10 @@ location set Are you sure you want to reset your device? 장치를 초기화 하시겠습니까? - - Resetting device... - 장치 초기화중... - System Reset 장치 초기화 - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - 장치를 초기화 합니다. 확인버튼을 누르면 모든 내용과 설정이 초기화됩니다. 부팅을 재개하려면 취소를 누르세요. - Cancel 취소 @@ -599,8 +591,17 @@ location set 확인 - Unable to mount data partition. Press confirm to reset your device. - 데이터 파티션을 마운트할 수 없습니다. 확인 버튼을 눌러 장치를 리셋합니다. + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + + + + Press confirm to erase all content and settings. Press cancel to resume boot. + + + + Resetting device... +This may take up to a minute. + diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index a25c51de3c..156b6f16c1 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -578,18 +578,10 @@ trabalho definido Are you sure you want to reset your device? Tem certeza que quer resetar seu dispositivo? - - Resetting device... - Resetando dispositivo... - System Reset Resetar Sistema - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Solicitado reset do sistema. Confirme para apagar todo conteúdo e configurações. Aperte cancelar para continuar boot. - Cancel Cancelar @@ -603,8 +595,17 @@ trabalho definido Confirmar - Unable to mount data partition. Press confirm to reset your device. - Não foi possível montar a partição de dados. Pressione confirmar para resetar seu dispositivo. + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + + + + Press confirm to erase all content and settings. Press cancel to resume boot. + + + + Resetting device... +This may take up to a minute. + diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 68c1bb766f..f295a72938 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -572,18 +572,10 @@ location set Are you sure you want to reset your device? 您确定要重置您的设备吗? - - Resetting device... - 正在重置设备…… - System Reset 恢复出厂设置 - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - 已触发系统重置:确认以删除所有内容和设置。取消以正常启动设备。 - Cancel 取消 @@ -597,8 +589,17 @@ location set 确认 - Unable to mount data partition. Press confirm to reset your device. - 无法挂载数据分区。 确认以重置您的设备。 + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + + + + Press confirm to erase all content and settings. Press cancel to resume boot. + + + + Resetting device... +This may take up to a minute. + diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 71315e118f..b7636c18c5 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -574,18 +574,10 @@ location set Are you sure you want to reset your device? 您確定要重置你的設備嗎? - - Resetting device... - 重置設備中… - System Reset 系統重置 - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - 系統重置已觸發。請按確認刪除所有內容和設置。按取消恢復啟動。 - Cancel 取消 @@ -599,8 +591,17 @@ location set 確認 - Unable to mount data partition. Press confirm to reset your device. - 無法掛載數據分區。請按確認重置您的設備。 + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + + + + Press confirm to erase all content and settings. Press cancel to resume boot. + + + + Resetting device... +This may take up to a minute. + From 58cd96536b852949f65309fea37684a6fa16668e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Feb 2023 03:44:53 +0800 Subject: [PATCH 1003/1179] cabana: small improvements to SignalView (#27419) --- tools/cabana/signaledit.cc | 34 ++++++++++++++++++++++++---------- tools/cabana/signaledit.h | 2 +- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index e862439b68..c614ecb247 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -61,16 +61,26 @@ void SignalModel::updateState(const QHash *msgs) { auto &dat = can->lastMessage(msg_id).dat; int row = 0; for (auto item : root->children) { - double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig); - item->sig_val = QString::number(value); - emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); + QString value = QString::number(get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig)); + if (value != item->sig_val) { + item->sig_val = value; + emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); + } ++row; } } } +SignalModel::Item *SignalModel::getItem(const QModelIndex &index) const { + SignalModel::Item *item = nullptr; + if (index.isValid()) { + item = (SignalModel::Item *)index.internalPointer(); + } + return item ? item : root.get(); +} + int SignalModel::rowCount(const QModelIndex &parent) const { - if (parent.column() > 0) return 0; + if (parent.isValid() && parent.column() > 0) return 0; auto parent_item = getItem(parent); int row_count = parent_item->children.size(); @@ -99,14 +109,19 @@ int SignalModel::signalRow(const Signal *sig) const { } QModelIndex SignalModel::index(int row, int column, const QModelIndex &parent) const { - if (!hasIndex(row, column, parent)) return {}; - return createIndex(row, column, getItem(parent)->children[row]); + if (parent.isValid() && parent.column() != 0) return {}; + + auto parent_item = getItem(parent); + if (parent_item && row < parent_item->children.size()) { + return createIndex(row, column, parent_item->children[row]); + } + return {}; } QModelIndex SignalModel::parent(const QModelIndex &index) const { if (!index.isValid()) return {}; Item *parent_item = getItem(index)->parent; - return parent_item == root.get() ? QModelIndex() : createIndex(parent_item->row(), 0, parent_item); + return !parent_item || parent_item == root.get() ? QModelIndex() : createIndex(parent_item->row(), 0, parent_item); } QVariant SignalModel::data(const QModelIndex &index, int role) const { @@ -287,8 +302,8 @@ SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(pa QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = QStyledItemDelegate::sizeHint(option, index); - if (!index.parent().isValid() && index.column() == 0) { - size.rwidth() = std::min(((QWidget*)parent())->size().width() / 2, size.width() + color_label_width + 8); + if (index.column() == 0 && !index.parent().isValid()) { + size.rwidth() = std::min(option.widget->size().width() / 2, size.width() + color_label_width + 8); } return size; } @@ -355,7 +370,6 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), setFrameStyle(QFrame::StyledPanel | QFrame::Plain); // title bar QWidget *title_bar = new QWidget(this); - title_bar->setAutoFillBackground(true); QHBoxLayout *hl = new QHBoxLayout(title_bar); hl->addWidget(signal_count_lb = new QLabel()); filter_edit = new QLineEdit(this); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 3cb193b62f..73a107f5c9 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -42,7 +42,7 @@ public: bool saveSignal(const Signal *origin_s, Signal &s); void resizeSignal(const Signal *sig, int start_bit, int size); void removeSignal(const Signal *sig); - inline Item *getItem(const QModelIndex &index) const { return index.isValid() ? (Item *)index.internalPointer() : root.get(); } + Item *getItem(const QModelIndex &index) const; int signalRow(const Signal *sig) const; void showExtraInfo(const QModelIndex &index); From e0a6074d00df9fafaa2b6d5e2d0fa01b154cce2f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Feb 2023 03:45:05 +0800 Subject: [PATCH 1004/1179] cabana: remove setUpdatesEnabled and setLabelFormat after updateAxisY (#27421) --- tools/cabana/chartswidget.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index e315f82398..8a3a59d989 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -154,12 +154,10 @@ void ChartsWidget::updateState() { can->seekTo(zoomed_range.first); } - charts_layout->parentWidget()->setUpdatesEnabled(false); const auto &range = is_zoomed ? zoomed_range : display_range; for (auto c : charts) { c->updatePlot(cur_sec, range.first, range.second); } - charts_layout->parentWidget()->setUpdatesEnabled(true); } void ChartsWidget::setMaxChartRange(int value) { @@ -213,7 +211,6 @@ ChartView *ChartsWidget::createChart() { } void ChartsWidget::showChart(const MessageId &id, const Signal *sig, bool show, bool merge) { - setUpdatesEnabled(false); ChartView *chart = findChart(id, sig); if (show && !chart) { chart = merge && charts.size() > 0 ? charts.back() : createChart(); @@ -223,7 +220,6 @@ void ChartsWidget::showChart(const MessageId &id, const Signal *sig, bool show, chart->removeIf([&](auto &s) { return s.msg_id == id && s.sig == sig; }); } updateToolBar(); - setUpdatesEnabled(true); } void ChartsWidget::setColumnCount(int n) { @@ -568,6 +564,7 @@ void ChartView::updateAxisY() { QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 + axis_y->setLabelFormat(QString("%.%1f").arg(n)); emit axisYLabelWidthChanged(y_label_width); } } From f2982340f8aed49559713f573b751e6095e51504 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Feb 2023 14:09:16 -0800 Subject: [PATCH 1005/1179] Ford: adjust curvature rate limits (#27423) * Update values.py * Update values.py * make consistent * Update ref_commit --- selfdrive/car/ford/values.py | 5 +++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 6be93269c4..1c8917446a 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -28,8 +28,9 @@ class CarControllerParams: # Curvature rate limits # TODO: unify field names used by curvature and angle control cars - ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.005, 0.00056, 0.0002]) - ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.008, 0.00089, 0.00032]) + # ~2 m/s^3 up, -3 m/s^3 down + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.004, 0.00044, 0.0002]) + ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.006, 0.00066, 0.00024]) ACCEL_MAX = 2.0 # m/s^s max acceleration ACCEL_MIN = -3.5 # m/s^s max deceleration diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 07fe22b022..1d807d75cd 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -4ad02871365f4cbd83c6b4c4f8ad6bb73015a626 \ No newline at end of file +5f45771d28c8e7112d474edcdd991689c6440acf From 6b4ac801e7ecb1addf74c9018958469741b609a3 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 22 Feb 2023 14:11:04 -0800 Subject: [PATCH 1006/1179] laikad: use new cache param (#27404) * add backward compatibility * rename laikad cache file * rm and update --------- Co-authored-by: Kurt Nistelberger Co-authored-by: Adeeb Shihadeh --- common/params.cc | 2 +- selfdrive/locationd/laikad.py | 2 +- selfdrive/loggerd/tests/test_loggerd.py | 8 ++++---- tools/gpstest/rpc_server.py | 2 +- tools/gpstest/test_laikad.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/params.cc b/common/params.cc index 5e3361a70f..2ba4f7e8ab 100644 --- a/common/params.cc +++ b/common/params.cc @@ -138,7 +138,7 @@ std::unordered_map keys = { {"IsReleaseBranch", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, - {"LaikadEphemeris", PERSISTENT | DONT_LOG}, + {"LaikadEphemerisV2", PERSISTENT | DONT_LOG}, {"LanguageSetting", PERSISTENT}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastGPSPosition", PERSISTENT}, diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index e85cd0ad42..2eb1e94526 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -28,7 +28,7 @@ from selfdrive.locationd.models.gnss_kf import States as GStates from system.swaglog import cloudlog MAX_TIME_GAP = 10 -EPHEMERIS_CACHE = 'LaikadEphemeris' +EPHEMERIS_CACHE = 'LaikadEphemerisV2' DOWNLOADS_CACHE_FOLDER = "/tmp/comma_download_cache/" CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 diff --git a/selfdrive/loggerd/tests/test_loggerd.py b/selfdrive/loggerd/tests/test_loggerd.py index 9c3565d130..857dc5c4e9 100755 --- a/selfdrive/loggerd/tests/test_loggerd.py +++ b/selfdrive/loggerd/tests/test_loggerd.py @@ -86,7 +86,7 @@ class TestLoggerd(unittest.TestCase): params.clear_all() for k, _, v in fake_params: params.put(k, v) - params.put("LaikadEphemeris", "abc") + params.put("LaikadEphemerisV2", "abc") lr = list(LogReader(str(self._gen_bootlog()))) initData = lr[0].initData @@ -103,14 +103,14 @@ class TestLoggerd(unittest.TestCase): # check params logged_params = {entry.key: entry.value for entry in initData.params.entries} - expected_params = set(k for k, _, __ in fake_params) | {'LaikadEphemeris'} + expected_params = set(k for k, _, __ in fake_params) | {'LaikadEphemerisV2'} assert set(logged_params.keys()) == expected_params, set(logged_params.keys()) ^ expected_params - assert logged_params['LaikadEphemeris'] == b'', f"DONT_LOG param value was logged: {repr(logged_params['LaikadEphemeris'])}" + assert logged_params['LaikadEphemerisV2'] == b'', f"DONT_LOG param value was logged: {repr(logged_params['LaikadEphemerisV2'])}" for param_key, initData_key, v in fake_params: self.assertEqual(getattr(initData, initData_key), v) self.assertEqual(logged_params[param_key].decode(), v) - params.put("LaikadEphemeris", "") + params.put("LaikadEphemerisV2", "") def test_rotation(self): os.environ["LOGGERD_TEST"] = "1" diff --git a/tools/gpstest/rpc_server.py b/tools/gpstest/rpc_server.py index b35c66d02d..a368566982 100644 --- a/tools/gpstest/rpc_server.py +++ b/tools/gpstest/rpc_server.py @@ -17,7 +17,7 @@ ALT_DELTA = 30 MATCH_NUM = 10 REPORT_STATS = 10 -EPHEM_CACHE = "/data/params/d/LaikadEphemeris" +EPHEM_CACHE = "/data/params/d/LaikadEphemerisV2" DOWNLOAD_CACHE = "/tmp/comma_download_cache" SERVER_LOG_FILE = "/tmp/fuzzy_server.log" diff --git a/tools/gpstest/test_laikad.py b/tools/gpstest/test_laikad.py index 613ac991b1..410a9c70d3 100644 --- a/tools/gpstest/test_laikad.py +++ b/tools/gpstest/test_laikad.py @@ -39,7 +39,7 @@ class TestLaikad(unittest.TestCase): def setUp(self): # ensure laikad cold start - Params().remove("LaikadEphemeris") + Params().remove("LaikadEphemerisV2") os.environ["LAIKAD_NO_INTERNET"] = "1" managed_processes['laikad'].start() From 9d64fb2d1abeb35d0b716b9e54169d473222ab21 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 22 Feb 2023 14:11:29 -0800 Subject: [PATCH 1007/1179] improved fan malfunction detection (#27405) --- selfdrive/controls/controlsd.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 2c359ec32a..f49b58212a 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -280,8 +280,9 @@ class Controls: # Alert if fan isn't spinning for 5 seconds if self.sm['peripheralState'].pandaType != log.PandaState.PandaType.unknown: - if self.sm['peripheralState'].fanSpeedRpm == 0 and self.sm['deviceState'].fanSpeedPercentDesired > 50: - if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 5.0: + if self.sm['peripheralState'].fanSpeedRpm < 500 and self.sm['deviceState'].fanSpeedPercentDesired > 50: + # allow enough time for the fan controller in the panda to recover from stalls + if (self.sm.frame - self.last_functional_fan_frame) * DT_CTRL > 15.0: self.events.add(EventName.fanMalfunction) else: self.last_functional_fan_frame = self.sm.frame From b00eb57bb735a8c533a28a22ee3aed534afd4a7c Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Feb 2023 15:59:07 -0800 Subject: [PATCH 1008/1179] Ford: adjust curvature rate limits (#27427) * fix up * Update ref_commit --- selfdrive/car/ford/values.py | 4 ++-- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 1c8917446a..3bc56eb9dd 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -28,8 +28,8 @@ class CarControllerParams: # Curvature rate limits # TODO: unify field names used by curvature and angle control cars - # ~2 m/s^3 up, -3 m/s^3 down - ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.004, 0.00044, 0.0002]) + # ~2 m/s^3 up, ~-3 m/s^3 down + ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.004, 0.00044, 0.00016]) ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[5, 15, 25], angle_v=[0.006, 0.00066, 0.00024]) ACCEL_MAX = 2.0 # m/s^s max acceleration diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 1d807d75cd..5e7a5c8c0a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5f45771d28c8e7112d474edcdd991689c6440acf +a38b267bd2d44945dcd664b2a84e6cd0a6163f91 From 90db46e7756e2eb6d61b1ff23f7cb4a7b356abb9 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Wed, 22 Feb 2023 17:26:37 -0800 Subject: [PATCH 1009/1179] setup: write installer URL to tmpfile (#27426) * setup: write installer URL to tmpfile * missed ptr type --- selfdrive/ui/qt/setup/setup.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 392be68a12..409d79796c 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -59,6 +59,11 @@ void Setup::download(QString url) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status); if (ret == CURLE_OK && res_status == 200 && is_elf(tmpfile)) { rename(tmpfile, "/tmp/installer"); + + FILE *fp_url = fopen("/tmp/installer_url", "w"); + fprintf(fp_url, "%s", url.toStdString().c_str()); + fclose(fp_url); + emit finished(true); } else { emit finished(false); From c1be6d945bb2efd6564f80f153c0ff71c59a3505 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Feb 2023 12:44:33 +0800 Subject: [PATCH 1010/1179] cabana: dispaly current FPS & cached minitues on statusbar (#27430) dispaly current FPS & cached minitues on statusbar --- tools/cabana/mainwin.cc | 17 +++++++++++++++++ tools/cabana/mainwin.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index bc090b2cc0..25e40e15aa 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -63,9 +63,11 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); QObject::connect(charts_widget, &ChartsWidget::dock, this, &MainWindow::dockCharts); QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); + QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::updateStatus); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MainWindow::undoStackIndexChanged); + QObject::connect(&settings, &Settings::changed, this, &MainWindow::updateStatus); } void MainWindow::createActions() { @@ -179,6 +181,9 @@ void MainWindow::createStatusBar() { progress_bar->setVisible(false); statusBar()->addWidget(new QLabel(tr("For Help, Press F1"))); statusBar()->addPermanentWidget(progress_bar); + + statusBar()->addPermanentWidget(status_label = new QLabel(this)); + updateStatus(); } void MainWindow::createShortcuts() { @@ -403,6 +408,18 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe } } +void MainWindow::updateStatus() { + float cached_minutes = 0; + if (!can->liveStreaming()) { + if (auto events = can->events(); !events->empty()) { + cached_minutes = (events->back()->mono_time - events->front()->mono_time) / (1e9 * 60); + } + } else { + settings.max_cached_minutes = settings.max_cached_minutes; + } + status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(cached_minutes, 0, 'f', 1).arg(settings.fps)); +} + void MainWindow::dockCharts(bool dock) { if (dock && floating_window) { floating_window->removeEventFilter(charts_widget); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index dd53b1f213..2aeb20aea8 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -56,6 +56,7 @@ protected: void undoStackCleanChanged(bool clean); void undoStackIndexChanged(int index); void onlineHelp(); + void updateStatus(); VideoWidget *video_widget = nullptr; QDockWidget *video_dock; @@ -65,6 +66,7 @@ protected: QWidget *floating_window = nullptr; QVBoxLayout *charts_layout; QProgressBar *progress_bar; + QLabel *status_label; QJsonDocument fingerprint_to_dbc; QSplitter *video_splitter;; QString current_file = ""; From 7b43a69089fa862c492eb4d4d1706b19662ff8b4 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 22 Feb 2023 21:04:40 -0800 Subject: [PATCH 1011/1179] Update RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 0ea4241a35..f71810784a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,7 +2,7 @@ Version 0.9.2 (2023-03-XX) ======================== * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. -Version 0.9.1 (2023-02-23) +Version 0.9.1 (2023-02-28) ======================== * New driving model * 30% improved height estimation resulting in better driving performance for tall cars From 4e0a3aa0d51c3abd96774bb12a6e28943082fa81 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 23 Feb 2023 19:44:53 +0100 Subject: [PATCH 1012/1179] cabana: show bus in own column (#27434) --- tools/cabana/messageswidget.cc | 33 +++++++++++++++++++++++---------- tools/cabana/messageswidget.h | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index c880c61058..cda3069ad9 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -20,11 +20,15 @@ MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) { table_widget = new QTableView(this); model = new MessageListModel(this); table_widget->setModel(model); - table_widget->setItemDelegateForColumn(4, new MessageBytesDelegate(table_widget)); + table_widget->setItemDelegateForColumn(5, new MessageBytesDelegate(table_widget)); table_widget->setSelectionBehavior(QAbstractItemView::SelectRows); table_widget->setSelectionMode(QAbstractItemView::SingleSelection); table_widget->setSortingEnabled(true); table_widget->sortByColumn(0, Qt::AscendingOrder); + table_widget->setColumnWidth(0, 150); + table_widget->setColumnWidth(1, 50); + table_widget->setColumnWidth(2, 50); + table_widget->setColumnWidth(3, 50); table_widget->horizontalHeader()->setStretchLastSection(true); table_widget->verticalHeader()->hide(); main_layout->addWidget(table_widget); @@ -108,7 +112,7 @@ void MessagesWidget::reset() { QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return (QString[]){"Name", "ID", "Freq", "Count", "Bytes"}[section]; + return (QString[]){"Name", "Bus", "ID", "Freq", "Count", "Bytes"}[section]; return {}; } @@ -119,12 +123,13 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return msgName(id); - case 1: return id.toString(); // TODO: put source and address in separate columns - case 2: return can_data.freq; - case 3: return can_data.count; - case 4: return toHex(can_data.dat); + case 1: return id.source; + case 2: return QString::number(id.address, 16);; + case 3: return can_data.freq; + case 4: return can_data.count; + case 5: return toHex(can_data.dat); } - } else if (role == Qt::UserRole && index.column() == 4) { + } else if (role == Qt::UserRole && index.column() == 5) { QVector colors = can_data.colors; if (!suppressed_bytes.empty()) { for (int i = 0; i < colors.size(); i++) { @@ -171,15 +176,23 @@ void MessageListModel::sortMessages() { }); } else if (sort_column == 1) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { - return sort_order == Qt::AscendingOrder ? l < r : l > r; + auto ll = std::pair{l.source, l}; + auto rr = std::pair{r.source, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); } else if (sort_column == 2) { + std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { + auto ll = std::pair{l.address, l}; + auto rr = std::pair{r.address, r}; + return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; + }); + } else if (sort_column == 3) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { auto ll = std::pair{can->lastMessage(l).freq, l}; auto rr = std::pair{can->lastMessage(r).freq, r}; return sort_order == Qt::AscendingOrder ? ll < rr : ll > rr; }); - } else if (sort_column == 3) { + } else if (sort_column == 4) { std::sort(msgs.begin(), msgs.end(), [this](auto &l, auto &r) { auto ll = std::pair{can->lastMessage(l).count, l}; auto rr = std::pair{can->lastMessage(r).count, r}; @@ -200,7 +213,7 @@ void MessageListModel::msgsReceived(const QHash *new_msgs) { } for (int i = 0; i < msgs.size(); ++i) { if (new_msgs->contains(msgs[i])) { - for (int col = 2; col < columnCount(); ++col) + for (int col = 3; col < columnCount(); ++col) emit dataChanged(index(i, col), index(i, col), {Qt::DisplayRole}); } } diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index 926d131c8d..ed9e241b0c 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -16,7 +16,7 @@ Q_OBJECT public: MessageListModel(QObject *parent) : QAbstractTableModel(parent) {} QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 5; } + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 6; } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex &parent = QModelIndex()) const override { return msgs.size(); } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; From a5644faa3f1095c2aa36b12e534fbba1b2ac921d Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 23 Feb 2023 19:45:13 +0100 Subject: [PATCH 1013/1179] cabana: show units (#27433) * show units on chart y axis * show in signal list * show in historyview * use clear() --- tools/cabana/chartswidget.cc | 12 +++++++++++- tools/cabana/historylog.cc | 10 +++++++++- tools/cabana/signaledit.cc | 3 +++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8a3a59d989..7f07490abd 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -542,9 +542,16 @@ void ChartView::updateAxisY() { double min = std::numeric_limits::max(); double max = std::numeric_limits::lowest(); + QString unit = sigs[0].sig->unit; + for (auto &s : sigs) { if (!s.series->isVisible()) continue; + // Only show unit when all signals have the same unit + if (unit != s.sig->unit) { + unit.clear(); + } + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); for (auto it = first; it != last; ++it) { @@ -552,6 +559,8 @@ void ChartView::updateAxisY() { if (it->y() > max) max = it->y(); } } + axis_y->setTitleText(unit); + if (min == std::numeric_limits::max()) min = 0; if (max == std::numeric_limits::lowest()) max = 0; @@ -563,7 +572,8 @@ void ChartView::updateAxisY() { QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; - y_label_width = qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 + int title_spacing = axis_y->titleText().isEmpty() ? 0 : 20; + y_label_width = title_spacing + qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 axis_y->setLabelFormat(QString("%.%1f").arg(n)); emit axisYLabelWidthChanged(y_label_width); } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index abf0b53af8..deee2f1724 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -48,7 +48,15 @@ QVariant HistoryLogModel::headerData(int section, Qt::Orientation orientation, i if (section == 0) { return "Time"; } - return show_signals ? sigs[section - 1]->name : "Data"; + if (show_signals) { + QString name = sigs[section - 1]->name; + if (!sigs[section - 1]->unit.isEmpty()) { + name += QString(" (%1)").arg(sigs[section - 1]->unit); + } + return name; + } else { + return "Data"; + } } else if (role == Qt::BackgroundRole && section > 0 && show_signals) { return QBrush(getColor(sigs[section - 1])); } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index c614ecb247..5fcfc116c1 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -62,6 +62,9 @@ void SignalModel::updateState(const QHash *msgs) { int row = 0; for (auto item : root->children) { QString value = QString::number(get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig)); + if (!item->sig->unit.isEmpty()){ + value += " " + item->sig->unit; + } if (value != item->sig_val) { item->sig_val = value; emit dataChanged(index(row, 1), index(row, 1), {Qt::DisplayRole}); From dc4ebeb29c569c2b3bc9c687778b6e4ed754d329 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 24 Feb 2023 02:45:59 +0800 Subject: [PATCH 1014/1179] cabana: added a new series type to chart: step line (#27422) * add step line series * create buttons in createToolButtons * add inline function clearTrackPoints * do not show tooltip if series is invisible * use QActionGroup --- tools/cabana/chartswidget.cc | 151 +++++++++++++++++++++-------------- tools/cabana/chartswidget.h | 19 +++-- tools/cabana/settings.cc | 2 +- 3 files changed, 106 insertions(+), 66 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 7f07490abd..d895191d86 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -1,5 +1,6 @@ #include "tools/cabana/chartswidget.h" +#include #include #include #include @@ -183,7 +184,7 @@ void ChartsWidget::settingChanged() { range_slider->setRange(1, settings.max_cached_minutes * 60); for (auto c : charts) { c->setFixedHeight(settings.chart_height); - c->setSeriesType(settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter); + c->setSeriesType((SeriesType)settings.chart_series_type); } } @@ -309,7 +310,7 @@ bool ChartsWidget::eventFilter(QObject *obj, QEvent *event) { // ChartView ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { - series_type = settings.chart_series_type == 0 ? QAbstractSeries::SeriesTypeLine : QAbstractSeries::SeriesTypeScatter; + series_type = (SeriesType)settings.chart_series_type; QChart *chart = new QChart(); chart->setBackgroundVisible(false); axis_x = new QValueAxis(this); @@ -325,31 +326,9 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { background->setPen(Qt::NoPen); background->setZValue(chart->zValue() - 1); - move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart); - move_icon->setToolTip(tr("Drag and drop to combine charts")); - - QToolButton *remove_btn = toolButton("x", tr("Remove Chart")); - close_btn_proxy = new QGraphicsProxyWidget(chart); - close_btn_proxy->setWidget(remove_btn); - close_btn_proxy->setZValue(chart->zValue() + 11); - - QToolButton *manage_btn = toolButton("list", ""); - QMenu *menu = new QMenu(this); - line_series_action = menu->addAction(tr("Line"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeLine); }); - line_series_action->setCheckable(true); - line_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeLine); - scatter_series_action = menu->addAction(tr("Scatter"), [this]() { setSeriesType(QAbstractSeries::SeriesTypeScatter); }); - scatter_series_action->setCheckable(true); - scatter_series_action->setChecked(series_type == QAbstractSeries::SeriesTypeScatter); - menu->addSeparator(); - menu->addAction(tr("Manage series"), this, &ChartView::manageSeries); - manage_btn->setMenu(menu); - manage_btn->setPopupMode(QToolButton::InstantPopup); - manage_btn_proxy = new QGraphicsProxyWidget(chart); - manage_btn_proxy->setWidget(manage_btn); - manage_btn_proxy->setZValue(chart->zValue() + 11); - setChart(chart); + + createToolButtons(); setRenderHint(QPainter::Antialiasing); // TODO: enable zoomIn/seekTo in live streaming mode. setRubberBand(can->liveStreaming() ? QChartView::NoRubberBand : QChartView::HorizontalRubberBand); @@ -358,7 +337,43 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); QObject::connect(dbc(), &DBCManager::msgRemoved, this, &ChartView::msgRemoved); QObject::connect(dbc(), &DBCManager::msgUpdated, this, &ChartView::msgUpdated); +} + +void ChartView::createToolButtons() { + move_icon = new QGraphicsPixmapItem(utils::icon("grip-horizontal"), chart()); + move_icon->setToolTip(tr("Drag and drop to combine charts")); + + QToolButton *remove_btn = toolButton("x", tr("Remove Chart")); + close_btn_proxy = new QGraphicsProxyWidget(chart()); + close_btn_proxy->setWidget(remove_btn); + close_btn_proxy->setZValue(chart()->zValue() + 11); + + // series types + QMenu *menu = new QMenu(this); + auto change_series_group = new QActionGroup(menu); + change_series_group->setExclusive(true); + QStringList types{tr("line"), tr("Step Line"), tr("Scatter")}; + for (int i = 0; i < types.size(); ++i) { + QAction *act = new QAction(types[i], change_series_group); + act->setData(i); + act->setCheckable(true); + act->setChecked(i == (int)series_type); + menu->addAction(act); + } + menu->addSeparator(); + menu->addAction(tr("Manage series"), this, &ChartView::manageSeries); + + QToolButton *manage_btn = toolButton("list", ""); + manage_btn->setMenu(menu); + manage_btn->setPopupMode(QToolButton::InstantPopup); + manage_btn_proxy = new QGraphicsProxyWidget(chart()); + manage_btn_proxy->setWidget(manage_btn); + manage_btn_proxy->setZValue(chart()->zValue() + 11); + QObject::connect(remove_btn, &QToolButton::clicked, this, &ChartView::remove); + QObject::connect(change_series_group, &QActionGroup::triggered, [this](QAction *action) { + setSeriesType((SeriesType)action->data().toInt()); + }); } void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) { @@ -476,7 +491,7 @@ void ChartView::updateSeriesPoints() { int num_points = std::max(end - begin, 1); int pixels_per_point = width() / num_points; - if (series_type == QAbstractSeries::SeriesTypeScatter) { + if (series_type == SeriesType::Scatter) { ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8)); } else { s.series->setPointsVisible(pixels_per_point > 20); @@ -490,7 +505,9 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even if (!sig || s.sig == sig) { if (clear) { s.vals.clear(); + s.step_vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz + s.step_vals.reserve(settings.max_cached_minutes * 60 * 100 * 2); s.last_value_mono_time = 0; } s.series->setColor(getColor(s.sig)); @@ -498,6 +515,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even struct Chunk { std::vector::const_iterator first, second; QVector vals; + QVector step_vals; }; // split into one minitue chunks QVector chunks; @@ -510,6 +528,7 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even QtConcurrent::blockingMap(chunks, [&](Chunk &chunk) { chunk.vals.reserve(60 * 100); // 100 hz + chunk.step_vals.reserve(60 * 100 * 2); // 100 hz double route_start_time = can->routeStartTime(); for (auto it = chunk.first; it != chunk.second; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { @@ -519,6 +538,10 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even double value = get_raw_value((uint8_t *)dat.begin(), dat.size(), *s.sig); double ts = ((*it)->mono_time / (double)1e9) - route_start_time; // seconds chunk.vals.push_back({ts, value}); + if (!chunk.step_vals.empty()) { + chunk.step_vals.push_back({ts, chunk.step_vals.back().y()}); + } + chunk.step_vals.push_back({ts,value}); } } } @@ -526,11 +549,12 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even }); for (auto &c : chunks) { s.vals.append(c.vals); + s.step_vals.append(c.step_vals); } if (events->size()) { s.last_value_mono_time = events->back()->mono_time; } - s.series->replace(s.vals); + s.series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); } } updateAxisY(); @@ -607,7 +631,7 @@ qreal ChartView::niceNumber(qreal x, bool ceiling) { } void ChartView::leaveEvent(QEvent *event) { - track_pts.clear(); + clearTrackPoints(); scene()->update(); QChartView::leaveEvent(event); } @@ -663,26 +687,31 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); const auto plot_area = chart()->plotArea(); - track_pts.clear(); + clearTrackPoints(); + if (!is_zooming && plot_area.contains(ev->pos())) { - track_pts.resize(sigs.size()); QStringList text_list; const double sec = chart()->mapToValue(ev->pos()).x(); - for (int i = 0; i < sigs.size(); ++i) { - QString value = "--"; + qreal x = -1; + for (auto &s : sigs) { + if (!s.series->isVisible()) continue; + // use reverse iterator to find last item <= sec. - auto it = std::lower_bound(sigs[i].vals.rbegin(), sigs[i].vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); - if (it != sigs[i].vals.rend() && it->x() >= axis_x->min()) { - value = QString::number(it->y()); - track_pts[i] = chart()->mapToPosition(*it); + auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); + if (it != s.vals.rend() && it->x() >= axis_x->min()) { + s.track_pt = chart()->mapToPosition(*it); + x = std::max(x, s.track_pt.x()); } - text_list.push_back(QString("%2: %3").arg(sigs[i].series->color().name(), sigs[i].sig->name, value)); + text_list.push_back(QString("%2: %3") + .arg(s.series->color().name(), s.sig->name, + s.track_pt.isNull() ? "--" : QString::number(s.track_pt.y()))); } - auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); - auto pt = (max == track_pts.end()) ? ev->pos() : *max; - text_list.push_front(QString::number(chart()->mapToValue(pt).x(), 'f', 3)); - QPointF tooltip_pt(pt.x() + 12, plot_area.top() - 20); - QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), pt.isNull() ? "" : text_list.join("
"), this, plot_area.toRect()); + if (x < 0) { + x = ev->pos().x(); + } + text_list.push_front(QString::number(chart()->mapToValue({x, 0}).x(), 'f', 3)); + QPointF tooltip_pt(x + 12, plot_area.top() - 20); + QToolTip::showText(mapToGlobal(tooltip_pt.toPoint()), text_list.join("
"), this, plot_area.toRect()); scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } else { QToolTip::hideText(); @@ -727,6 +756,7 @@ void ChartView::dropEvent(QDropEvent *event) { } void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { + // draw time line qreal x = chart()->mapToPosition(QPointF{cur_sec, 0}).x(); x = std::clamp(x, chart()->plotArea().left(), chart()->plotArea().right()); qreal y1 = chart()->plotArea().top() - 2; @@ -734,18 +764,20 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(QPen(chart()->titleBrush().color(), 2)); painter->drawLine(QPointF{x, y1}, QPointF{x, y2}); - auto max = std::max_element(track_pts.begin(), track_pts.end(), [](auto &a, auto &b) { return a.x() < b.x(); }); - if (max != track_pts.end() && !max->isNull()) { - painter->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); - painter->drawLine(QPointF{max->x(), y1}, QPointF{max->x(), y2}); - painter->setPen(Qt::NoPen); - for (int i = 0; i < track_pts.size(); ++i) { - if (!track_pts[i].isNull() && i < sigs.size()) { - painter->setBrush(sigs[i].series->color().darker(125)); - painter->drawEllipse(track_pts[i], 5.5, 5.5); - } + // draw track points + painter->setPen(Qt::NoPen); + qreal track_line_x = -1; + for (auto &s : sigs) { + if (!s.track_pt.isNull() && s.series->isVisible()) { + painter->setBrush(s.series->color().darker(125)); + painter->drawEllipse(s.track_pt, 5.5, 5.5); + track_line_x = std::max(track_line_x, s.track_pt.x()); } } + if (track_line_x > 0) { + painter->setPen(QPen(Qt::darkGray, 1, Qt::DashLine)); + painter->drawLine(QPointF{track_line_x, y1}, QPointF{track_line_x, y2}); + } // paint points. OpenGL mode lacks certain features (such as showing points) painter->setPen(Qt::NoPen); @@ -761,11 +793,14 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } -QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor color) { +QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { QXYSeries *series = nullptr; - if (type == QAbstractSeries::SeriesTypeLine) { + if (type == SeriesType::Line) { series = new QLineSeries(this); chart()->legend()->setMarkerShape(QLegend::MarkerShapeRectangle); + } else if (type == SeriesType::StepLine) { + series = new QLineSeries(this); + chart()->legend()->setMarkerShape(QLegend::MarkerShapeFromSeries); } else { series = new QScatterSeries(this); chart()->legend()->setMarkerShape(QLegend::MarkerShapeCircle); @@ -786,9 +821,7 @@ QXYSeries *ChartView::createSeries(QAbstractSeries::SeriesType type, QColor colo return series; } -void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { - line_series_action->setChecked(type == QAbstractSeries::SeriesTypeLine); - scatter_series_action->setChecked(type == QAbstractSeries::SeriesTypeScatter); +void ChartView::setSeriesType(SeriesType type) { if (type != series_type) { series_type = type; for (auto &s : sigs) { @@ -797,7 +830,7 @@ void ChartView::setSeriesType(QAbstractSeries::SeriesType type) { } for (auto &s : sigs) { auto series = createSeries(series_type, getColor(s.sig)); - series->replace(s.vals); + series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); s.series = series; } updateSeriesPoints(); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index a1dcf32513..76943c1fe9 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -20,6 +20,12 @@ using namespace QtCharts; const int CHART_MIN_WIDTH = 300; +enum class SeriesType { + Line = 0, + StepLine, + Scatter +}; + class ChartView : public QChartView { Q_OBJECT @@ -29,7 +35,7 @@ public: bool hasSeries(const MessageId &msg_id, const Signal *sig) const; void updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); - void setSeriesType(QAbstractSeries::SeriesType type); + void setSeriesType(SeriesType type); void updatePlotArea(int left); struct SigItem { @@ -37,7 +43,9 @@ public: const Signal *sig = nullptr; QXYSeries *series = nullptr; QVector vals; + QVector step_vals; uint64_t last_value_mono_time = 0; + QPointF track_pt{}; }; signals: @@ -57,6 +65,7 @@ private slots: void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: + void createToolButtons(); void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *ev) override; @@ -70,15 +79,15 @@ private: void drawForeground(QPainter *painter, const QRectF &rect) override; std::tuple getNiceAxisNumbers(qreal min, qreal max, int tick_count); qreal niceNumber(qreal x, bool ceiling); - QXYSeries *createSeries(QAbstractSeries::SeriesType type, QColor color); + QXYSeries *createSeries(SeriesType type, QColor color); void updateSeriesPoints(); void removeIf(std::function predicate); + inline void clearTrackPoints() { for (auto &s : sigs) s.track_pt = {}; } int y_label_width = 0; int align_to = 0; QValueAxis *axis_x; QValueAxis *axis_y; - QVector track_pts; QGraphicsPixmapItem *move_icon; QGraphicsProxyWidget *close_btn_proxy; QGraphicsProxyWidget *manage_btn_proxy; @@ -86,9 +95,7 @@ private: QList sigs; double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; - QAbstractSeries::SeriesType series_type = QAbstractSeries::SeriesTypeLine; - QAction *line_series_action; - QAction *scatter_series_action; + SeriesType series_type = SeriesType::Line; friend class ChartsWidget; }; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 6cbd16cabf..23f001efff 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -65,7 +65,7 @@ SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) { form_layout->addRow(tr("Max Cached Minutes"), cached_minutes); chart_series_type = new QComboBox(this); - chart_series_type->addItems({tr("Line"), tr("Scatter")}); + chart_series_type->addItems({tr("Line"), tr("Step Line"), tr("Scatter")}); chart_series_type->setCurrentIndex(settings.chart_series_type); form_layout->addRow(tr("Chart Default Series Type"), chart_series_type); From 7a3b3e8b567ea476088e6f3d7344c7220e35e398 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 23 Feb 2023 15:01:10 -0800 Subject: [PATCH 1015/1179] better main off alert (#27442) --- selfdrive/controls/lib/events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index 4e664d8cf0..e4ddfb5326 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -317,9 +317,9 @@ def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM def wrong_car_mode_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: - text = "Cruise Mode Disabled" + text = "Enable Adaptive Cruise to Engage" if CP.carName == "honda": - text = "Main Switch Off" + text = "Enable Main Switch to Engage" return NoEntryAlert(text) From d5688ae49fd8652bf500ec145f2f3aa711c6bbf3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Feb 2023 16:18:32 -0800 Subject: [PATCH 1016/1179] Angle control: fix limiting bug (#27428) * fix steer up bug * Update ref_commit --- selfdrive/car/__init__.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index c056f7ca3d..a90f023ed1 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -115,7 +115,7 @@ def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torq def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS): # pick angle rate limits based on wind up/down - steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last) + steer_up = apply_angle_last * apply_angle >= 0. and abs(apply_angle) > abs(apply_angle_last) rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 5e7a5c8c0a..9991154b9a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a38b267bd2d44945dcd664b2a84e6cd0a6163f91 +772f30de36fc7f8421dabb779cc02f45eb83d7bb From 79e6910106de6ae25127613728332e8b743d962a Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 23 Feb 2023 19:45:48 -0800 Subject: [PATCH 1017/1179] setup: detailed error messages (#27429) * setup: specific error state for non-executable file * Result -> DownloadResult * complete -> finished * rename widgets to be more consistent * fix typos * fix setCurrentIndex This appears to have different behaviour on device than on PC (off by one) * load fonts * copy Co-authored-by: Adeeb Shihadeh * Revert "load fonts" This reverts commit e8756598ed99aea39ef5721453e97920a494051c. * font family * undo * less widgets more better * font size --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/qt/setup/setup.cc | 41 ++++++++++++++++-------- selfdrive/ui/qt/setup/setup.h | 5 +-- selfdrive/ui/translations/main_de.ts | 8 +++++ selfdrive/ui/translations/main_ja.ts | 8 +++++ selfdrive/ui/translations/main_ko.ts | 8 +++++ selfdrive/ui/translations/main_pt-BR.ts | 8 +++++ selfdrive/ui/translations/main_zh-CHS.ts | 8 +++++ selfdrive/ui/translations/main_zh-CHT.ts | 8 +++++ 8 files changed, 78 insertions(+), 16 deletions(-) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 409d79796c..3de6255521 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -34,7 +34,7 @@ bool is_elf(char *fname) { void Setup::download(QString url) { CURL *curl = curl_easy_init(); if (!curl) { - emit finished(false); + emit finished(url, tr("Something went wrong. Reboot the device.")); return; } @@ -57,16 +57,19 @@ void Setup::download(QString url) { int ret = curl_easy_perform(curl); long res_status = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_status); - if (ret == CURLE_OK && res_status == 200 && is_elf(tmpfile)) { + + if (ret != CURLE_OK || res_status != 200) { + emit finished(url, tr("Ensure the entered URL is valid, and the device’s internet connection is good.")); + } else if (!is_elf(tmpfile)) { + emit finished(url, tr("No custom software found at this URL.")); + } else { rename(tmpfile, "/tmp/installer"); FILE *fp_url = fopen("/tmp/installer_url", "w"); fprintf(fp_url, "%s", url.toStdString().c_str()); fclose(fp_url); - emit finished(true); - } else { - emit finished(false); + emit finished(url); } curl_slist_free_all(list); @@ -239,10 +242,10 @@ QWidget * Setup::downloading() { return widget; } -QWidget * Setup::download_failed() { +QWidget * Setup::download_failed(QLabel *url, QLabel *body) { QWidget *widget = new QWidget(); QVBoxLayout *main_layout = new QVBoxLayout(widget); - main_layout->setContentsMargins(55, 225, 55, 55); + main_layout->setContentsMargins(55, 185, 55, 55); main_layout->setSpacing(0); QLabel *title = new QLabel(tr("Download Failed")); @@ -251,7 +254,13 @@ QWidget * Setup::download_failed() { main_layout->addSpacing(67); - QLabel *body = new QLabel(tr("Ensure the entered URL is valid, and the device’s internet connection is good.")); + url->setWordWrap(true); + url->setAlignment(Qt::AlignTop | Qt::AlignLeft); + url->setStyleSheet("font-family: \"JetBrains Mono\"; font-size: 64px; font-weight: 400; margin-right: 100px;"); + main_layout->addWidget(url); + + main_layout->addSpacing(48); + body->setWordWrap(true); body->setAlignment(Qt::AlignTop | Qt::AlignLeft); body->setStyleSheet("font-size: 80px; font-weight: 300; margin-right: 100px;"); @@ -276,7 +285,7 @@ QWidget * Setup::download_failed() { restart->setProperty("primary", true); blayout->addWidget(restart); QObject::connect(restart, &QPushButton::clicked, this, [=]() { - setCurrentIndex(2); + setCurrentIndex(1); }); widget->setStyleSheet(R"( @@ -309,15 +318,19 @@ Setup::Setup(QWidget *parent) : QStackedWidget(parent) { downloading_widget = downloading(); addWidget(downloading_widget); - failed_widget = download_failed(); + QLabel *url_label = new QLabel(); + QLabel *body_label = new QLabel(); + failed_widget = download_failed(url_label, body_label); addWidget(failed_widget); - QObject::connect(this, &Setup::finished, [=](bool success) { - // hide setup on success - qDebug() << "finished" << success; - if (success) { + QObject::connect(this, &Setup::finished, [=](const QString &url, const QString &error) { + qDebug() << "finished" << url << error; + if (error.isEmpty()) { + // hide setup on success QTimer::singleShot(3000, this, &QWidget::hide); } else { + url_label->setText(url); + body_label->setText(error); setCurrentWidget(failed_widget); } }); diff --git a/selfdrive/ui/qt/setup/setup.h b/selfdrive/ui/qt/setup/setup.h index f990b5a6cb..bf5d97070d 100644 --- a/selfdrive/ui/qt/setup/setup.h +++ b/selfdrive/ui/qt/setup/setup.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -15,13 +16,13 @@ private: QWidget *getting_started(); QWidget *network_setup(); QWidget *downloading(); - QWidget *download_failed(); + QWidget *download_failed(QLabel *url, QLabel *body); QWidget *failed_widget; QWidget *downloading_widget; signals: - void finished(bool success); + void finished(const QString &url, const QString &error = ""); public slots: void nextPage(); diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 77670ede3b..5f3511d3cc 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -703,6 +703,14 @@ This may take up to a minute. Start over Von neuem beginnen + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + +
SetupWidget diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 856beee7bc..1e0223606b 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -701,6 +701,14 @@ This may take up to a minute. Start over 最初からやり直す + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index ee5bb4fd36..5470e57ce5 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -701,6 +701,14 @@ This may take up to a minute. Start over 다시 시작 + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 156b6f16c1..5c4eab3327 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -705,6 +705,14 @@ This may take up to a minute. Start over Inicializar + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index f295a72938..cfc055ac98 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -699,6 +699,14 @@ This may take up to a minute. Start over 重来 + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index b7636c18c5..e4058ee0db 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -701,6 +701,14 @@ This may take up to a minute. Start over 重新開始 + + No custom software found at this URL. + + + + Something went wrong. Reboot the device. + + SetupWidget From f64fa07b0a42bb04d036f1280953dbbd27de41a0 Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 23 Feb 2023 19:46:06 -0800 Subject: [PATCH 1018/1179] setup: set download timeout (#27441) --- selfdrive/ui/qt/setup/setup.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/ui/qt/setup/setup.cc b/selfdrive/ui/qt/setup/setup.cc index 3de6255521..de5021c8bc 100644 --- a/selfdrive/ui/qt/setup/setup.cc +++ b/selfdrive/ui/qt/setup/setup.cc @@ -53,6 +53,7 @@ void Setup::download(QString url) { curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_USERAGENT, (USER_AGENT + version).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); int ret = curl_easy_perform(curl); long res_status = 0; From 608ac253df5295187c6c7289b5b41a983482123e Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 24 Feb 2023 12:02:46 +0800 Subject: [PATCH 1019/1179] cabana: right align signal values & fixed text overflow (#27444) right align the signal values --- tools/cabana/signaledit.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 5fcfc116c1..d5cd4ae825 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -338,6 +338,15 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); + } else if (index.column() == 1 && item && item->type == SignalModel::Item::Sig) { + // draw signal value + if (option.state & QStyle::State_Selected) { + painter->fillRect(option.rect, option.palette.highlight()); + } + painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + QRect rc = option.rect.adjusted(0, 0, -70, 0); + auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); + painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); } else { QStyledItemDelegate::paint(painter, option, index); } From c80bc583817991a47bdcb59cc9d88713b1322b88 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Fri, 24 Feb 2023 17:01:12 +0100 Subject: [PATCH 1020/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 9fe24bd368..1923b14189 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 9fe24bd3683377146b04c68ab94d0935f0bd9d78 +Subproject commit 1923b1418933e464ff7460a3e0a05d63aad0d53b From 78116029d33ab7724daa087201f1743fd34d6a19 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Feb 2023 06:27:18 +0800 Subject: [PATCH 1021/1179] cabana: replace hardcoded margins, colors, spacing with values from style. (#27449) replace hardcoded margins, colors, spacing improve performance of MessageBytesDelegate --- tools/cabana/binaryview.cc | 7 ++----- tools/cabana/chartswidget.cc | 21 +++++++++++--------- tools/cabana/historylog.cc | 4 +++- tools/cabana/mainwin.cc | 5 +++++ tools/cabana/messageswidget.cc | 4 +++- tools/cabana/signaledit.cc | 20 ++++++++++++------- tools/cabana/util.cc | 36 ++++++++++++++++++++++------------ tools/cabana/util.h | 9 +++++++-- 8 files changed, 68 insertions(+), 38 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index d9b00f6882..120a85a330 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -293,7 +293,6 @@ void BinaryViewModel::updateState() { double max_f = 255.0; double factor = 0.25; double scaler = max_f / log2(1.0 + factor); - char hex[3] = {'\0'}; for (int i = 0; i < binary.size(); ++i) { for (int j = 0; j < 8; ++j) { auto &item = items[i * column_count + j]; @@ -305,9 +304,7 @@ void BinaryViewModel::updateState() { double alpha = std::clamp(offset + log2(1.0 + factor * (double)n / (double)last_msg.count) * scaler, min_f, max_f); item.bg_color.setAlpha(alpha); } - hex[0] = toHex(binary[i] >> 4); - hex[1] = toHex(binary[i] & 0xf); - items[i * column_count + 8].val = hex; + items[i * column_count + 8].val = toHex(binary[i]); items[i * column_count + 8].bg_color = last_msg.colors[i]; } for (int i = binary.size() * column_count; i < items.size(); ++i) { @@ -375,7 +372,7 @@ void BinaryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op bg.setAlpha(std::max(50, bg.alpha())); } painter->fillRect(option.rect, bg); - painter->setPen(Qt::black); + painter->setPen(option.palette.color(QPalette::Text)); } } diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index d895191d86..7982a5899c 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -25,11 +25,12 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { // toolbar QToolBar *toolbar = new QToolBar(tr("Charts"), this); - toolbar->setIconSize({16, 16}); + int icon_size = style()->pixelMetric(QStyle::PM_SmallIconSize); + toolbar->setIconSize({icon_size, icon_size}); QAction *new_plot_btn = toolbar->addAction(utils::icon("file-plus"), tr("New Plot")); toolbar->addWidget(title_label = new QLabel()); - title_label->setContentsMargins(0, 0, 12, 0); + title_label->setContentsMargins(0, 0, style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing), 0); QMenu *menu = new QMenu(this); for (int i = 0; i < MAX_COLUMN_COUNT; ++i) { @@ -77,8 +78,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { main_layout->addWidget(charts_scroll); // init settings - use_dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > - QApplication::style()->standardPalette().color(QPalette::Background).value(); + use_dark_theme = QApplication::palette().color(QPalette::WindowText).value() > + QApplication::palette().color(QPalette::Background).value(); column_count = std::clamp(settings.chart_column_count, 1, MAX_COLUMN_COUNT); max_chart_range = std::clamp(settings.chart_range, 1, settings.max_cached_minutes * 60); display_range = {0, max_chart_range}; @@ -322,7 +323,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { chart->setMargins({0, 0, 0, 0}); background = new QGraphicsRectItem(chart); - background->setBrush(Qt::white); + background->setBrush(QApplication::palette().color(QPalette::Base)); background->setPen(Qt::NoPen); background->setZValue(chart->zValue() - 1); @@ -443,10 +444,12 @@ void ChartView::manageSeries() { void ChartView::resizeEvent(QResizeEvent *event) { updatePlotArea(align_to); - int x = event->size().width() - close_btn_proxy->size().width() - 11; - close_btn_proxy->setPos(x, 8); - manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - 5, 8); - move_icon->setPos(11, 8); + int top_margin = style()->pixelMetric(QStyle::PM_LayoutTopMargin); + int spacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + int x = event->size().width() - close_btn_proxy->size().width() - style()->pixelMetric(QStyle::PM_LayoutRightMargin); + close_btn_proxy->setPos(x, top_margin); + manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - spacing, top_margin); + move_icon->setPos(style()->pixelMetric(QStyle::PM_LayoutLeftMargin), top_margin); QChartView::resizeEvent(event); } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index deee2f1724..57f65b97d8 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -15,8 +15,10 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); - } else if (role == Qt::UserRole && index.column() == 1 && !show_signals) { + } else if (role == ColorsRole) { return QVariant::fromValue(m.colors); + } else if (role == BytesRole) { + return m.data; } return {}; } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 25e40e15aa..282a541244 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -58,6 +58,11 @@ MainWindow::MainWindow() : QMainWindow() { fingerprint_to_dbc = QJsonDocument::fromJson(json_file.readAll()); } + setStyleSheet(QString(R"(QMainWindow::separator { + width: %1px; /* when vertical */ + height: %1px; /* when horizontal */ + })").arg(style()->pixelMetric(QStyle::PM_SplitterWidth))); + QObject::connect(this, &MainWindow::showMessage, statusBar(), &QStatusBar::showMessage); QObject::connect(this, &MainWindow::updateProgressBar, this, &MainWindow::updateDownloadProgress); QObject::connect(messages_widget, &MessagesWidget::msgSelectionChanged, center_widget, &CenterWidget::setMessage); diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index cda3069ad9..b4a7ed7b34 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -129,7 +129,7 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { case 4: return can_data.count; case 5: return toHex(can_data.dat); } - } else if (role == Qt::UserRole && index.column() == 5) { + } else if (role == ColorsRole) { QVector colors = can_data.colors; if (!suppressed_bytes.empty()) { for (int i = 0; i < colors.size(); i++) { @@ -139,6 +139,8 @@ QVariant MessageListModel::data(const QModelIndex &index, int role) const { } } return QVariant::fromValue(colors); + } else if (role == BytesRole) { + return can_data.dat; } return {}; } diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d5cd4ae825..e425a13f82 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -322,19 +322,22 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // color label auto bg_color = getColor(item->sig); - QRect rc{option.rect.left(), option.rect.top(), color_label_width, option.rect.height()}; + int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + QRect rc{option.rect.left() + h_margin, option.rect.top(), color_label_width, option.rect.height()}; painter->setPen(Qt::NoPen); painter->setBrush(item->highlight ? bg_color.darker(125) : bg_color); - painter->drawRoundedRect(rc.adjusted(0, 2, 0, -2), 3, 3); + painter->drawRoundedRect(rc.adjusted(0, v_margin, 0, -v_margin), 3, 3); painter->setPen(item->highlight ? Qt::white : Qt::black); painter->setFont(small_font); painter->drawText(rc, Qt::AlignCenter, QString::number(item->row() + 1)); // signal name painter->setFont(option.font); - painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); QString text = index.data(Qt::DisplayRole).toString(); - QRect text_rect = option.rect.adjusted(rc.width() + 6, 0, 0, 0); + QRect text_rect = option.rect; + text_rect.setLeft(rc.right() + h_margin * 2); text = painter->fontMetrics().elidedText(text, Qt::ElideRight, text_rect.width()); painter->drawText(text_rect, option.displayAlignment, text); painter->restore(); @@ -343,7 +346,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } - painter->setPen((option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()).color()); + painter->setPen(option.palette.color(option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text)); QRect rc = option.rect.adjusted(0, 0, -70, 0); auto text = painter->fontMetrics().elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, rc.width()); painter->drawText(rc, Qt::AlignRight | Qt::AlignVCenter, text); @@ -442,8 +445,11 @@ void SignalView::rowsChanged() { if (!tree->indexWidget(index)) { QWidget *w = new QWidget(this); QHBoxLayout *h = new QHBoxLayout(w); - h->setContentsMargins(0, 2, 0, 2); - h->addStretch(1); + int v_margin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + int h_margin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + h->setContentsMargins(0, v_margin, -h_margin, v_margin); + h->setSpacing(style()->pixelMetric(QStyle::PM_ToolBarItemSpacing)); + h->addStretch(0); auto remove_btn = toolButton("x", tr("Remove signal")); auto plot_btn = toolButton("graph-up", ""); diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 4f79f9a3ac..5e4f505d29 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -71,26 +71,26 @@ void ChangeTracker::clear() { MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { fixed_font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + byte_width = QFontMetrics(fixed_font).width("00 "); } void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + auto colors = index.data(ColorsRole).value>(); + auto byte_list = index.data(BytesRole).toByteArray(); + + int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin); + int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); + QRect rc{option.rect.left() + h_margin, option.rect.top() + v_margin, byte_width, option.rect.height() - 2 * v_margin}; + auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText: QPalette::Text; painter->setPen(option.palette.color(color_role)); painter->setFont(fixed_font); - int space = painter->boundingRect(option.rect, option.displayAlignment, " ").width(); - QRect pos = painter->boundingRect(option.rect, option.displayAlignment, "00").adjusted(0, 0, 2, 0); - pos.moveLeft(pos.x() + space); - int m = space / 2; - const QMargins margins(m, m, m, m); - - auto colors = index.data(Qt::UserRole).value>(); - auto byte_list = index.data(Qt::DisplayRole).toString().split(" "); for (int i = 0; i < byte_list.size(); ++i) { if (i < colors.size() && colors[i].alpha() > 0) { - painter->fillRect(pos.marginsAdded(margins), colors[i]); + painter->fillRect(rc, colors[i]); } - painter->drawText(pos, Qt::AlignCenter, byte_list[i]); - pos.moveLeft(pos.right() + space); + painter->drawText(rc, Qt::AlignCenter, toHex(byte_list[i])); + rc.moveLeft(rc.right() + 1); } } @@ -114,8 +114,8 @@ QValidator::State NameValidator::validate(QString &input, int &pos) const { namespace utils { QPixmap icon(const QString &id) { - static bool dark_theme = QApplication::style()->standardPalette().color(QPalette::WindowText).value() > - QApplication::style()->standardPalette().color(QPalette::Background).value(); + static bool dark_theme = QApplication::palette().color(QPalette::WindowText).value() > + QApplication::palette().color(QPalette::Background).value(); QPixmap pm; QString key = "bootstrap_" % id % (dark_theme ? "1" : "0"); if (!QPixmapCache::find(key, &pm)) { @@ -138,3 +138,13 @@ QToolButton *toolButton(const QString &icon, const QString &tooltip) { btn->setAutoRaise(true); return btn; }; + + +QString toHex(uint8_t byte) { + static std::array hex = []() { + std::array ret; + for (int i = 0; i < 256; ++i) ret[i] = QStringLiteral("%1").arg(i, 2, 16, QLatin1Char('0')).toUpper(); + return ret; + }(); + return hex[byte]; +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h index b72ddfcaa0..5eb5c3c5aa 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -14,7 +14,6 @@ #include "tools/cabana/dbcmanager.h" using namespace dbcmanager; - class ChangeTracker { public: void compute(const QByteArray &dat, double ts, uint32_t freq); @@ -31,16 +30,22 @@ private: QByteArray prev_dat; }; +enum { + ColorsRole = Qt::UserRole + 1, + BytesRole = Qt::UserRole + 2 +}; + class MessageBytesDelegate : public QStyledItemDelegate { Q_OBJECT public: MessageBytesDelegate(QObject *parent); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QFont fixed_font; + int byte_width; }; inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } -inline char toHex(uint value) { return "0123456789ABCDEF"[value & 0xF]; } +QString toHex(uint8_t byte); QColor getColor(const dbcmanager::Signal *sig); class NameValidator : public QRegExpValidator { From 581fd62d2642629b23ac111112245a963202143f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sun, 26 Feb 2023 17:32:52 -0800 Subject: [PATCH 1022/1179] steer limits: rename common dist to meas function (#27453) * rename function * make a wrapper function (ford uses dynamic up/down limits * make two functions consistent * make torque function convert to int --- selfdrive/car/__init__.py | 38 ++++++++++++++--------- selfdrive/car/chrysler/carcontroller.py | 4 +-- selfdrive/car/gm/carcontroller.py | 4 +-- selfdrive/car/hyundai/carcontroller.py | 4 +-- selfdrive/car/mazda/carcontroller.py | 6 ++-- selfdrive/car/subaru/carcontroller.py | 4 +-- selfdrive/car/toyota/carcontroller.py | 4 +-- selfdrive/car/volkswagen/carcontroller.py | 4 +-- 8 files changed, 38 insertions(+), 30 deletions(-) diff --git a/selfdrive/car/__init__.py b/selfdrive/car/__init__.py index a90f023ed1..58cde85817 100644 --- a/selfdrive/car/__init__.py +++ b/selfdrive/car/__init__.py @@ -73,7 +73,7 @@ def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> Dict[str, st return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc} -def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS): +def apply_driver_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS): # limits due to driver torque driver_max_torque = LIMITS.STEER_MAX + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER @@ -93,24 +93,32 @@ def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque return int(round(float(apply_torque))) -def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS): - # limits due to comparison of commanded torque VS motor reported torque - max_lim = min(max(motor_torque + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_ERROR_MAX), LIMITS.STEER_MAX) - min_lim = max(min(motor_torque - LIMITS.STEER_ERROR_MAX, -LIMITS.STEER_ERROR_MAX), -LIMITS.STEER_MAX) +def apply_dist_to_meas_limits(val, val_last, val_meas, + STEER_DELTA_UP, STEER_DELTA_DOWN, + STEER_ERROR_MAX, STEER_MAX): + # limits due to comparison of commanded val VS measured val (torque/angle/curvature) + max_lim = min(max(val_meas + STEER_ERROR_MAX, STEER_ERROR_MAX), STEER_MAX) + min_lim = max(min(val_meas - STEER_ERROR_MAX, -STEER_ERROR_MAX), -STEER_MAX) - apply_torque = clip(apply_torque, min_lim, max_lim) + val = clip(val, min_lim, max_lim) - # slow rate if steer torque increases in magnitude - if apply_torque_last > 0: - apply_torque = clip(apply_torque, - max(apply_torque_last - LIMITS.STEER_DELTA_DOWN, -LIMITS.STEER_DELTA_UP), - apply_torque_last + LIMITS.STEER_DELTA_UP) + # slow rate if val increases in magnitude + if val_last > 0: + val = clip(val, + max(val_last - STEER_DELTA_DOWN, -STEER_DELTA_UP), + val_last + STEER_DELTA_UP) else: - apply_torque = clip(apply_torque, - apply_torque_last - LIMITS.STEER_DELTA_UP, - min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP)) + val = clip(val, + val_last - STEER_DELTA_UP, + min(val_last + STEER_DELTA_DOWN, STEER_DELTA_UP)) - return int(round(float(apply_torque))) + return float(val) + + +def apply_meas_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS): + return int(round(apply_dist_to_meas_limits(apply_torque, apply_torque_last, motor_torque, + LIMITS.STEER_DELTA_UP, LIMITS.STEER_DELTA_DOWN, + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_MAX))) def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS): diff --git a/selfdrive/car/chrysler/carcontroller.py b/selfdrive/car/chrysler/carcontroller.py index 20a44bce21..b418179e0e 100644 --- a/selfdrive/car/chrysler/carcontroller.py +++ b/selfdrive/car/chrysler/carcontroller.py @@ -1,6 +1,6 @@ from opendbc.can.packer import CANPacker from common.realtime import DT_CTRL -from selfdrive.car import apply_toyota_steer_torque_limits +from selfdrive.car import apply_meas_steer_torque_limits from selfdrive.car.chrysler.chryslercan import create_lkas_hud, create_lkas_command, create_cruise_buttons from selfdrive.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags @@ -67,7 +67,7 @@ class CarController: # steer torque new_steer = int(round(CC.actuators.steer * self.params.STEER_MAX)) - apply_steer = apply_toyota_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params) + apply_steer = apply_meas_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorqueEps, self.params) if not lkas_active or not lkas_control_bit: apply_steer = 0 self.apply_steer_last = apply_steer diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index 42eaf7e88a..2a996c0ff6 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -3,7 +3,7 @@ from common.conversions import Conversions as CV from common.numpy_fast import interp from common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.gm import gmcan from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons @@ -73,7 +73,7 @@ class CarController: if CC.latActive: new_steer = int(round(actuators.steer * self.params.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) else: apply_steer = 0 diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py index 1e6f78af20..2572038492 100644 --- a/selfdrive/car/hyundai/carcontroller.py +++ b/selfdrive/car/hyundai/carcontroller.py @@ -3,7 +3,7 @@ from common.conversions import Conversions as CV from common.numpy_fast import clip from common.realtime import DT_CTRL from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.hyundai import hyundaicanfd, hyundaican from selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR @@ -60,7 +60,7 @@ class CarController: # steering torque new_steer = int(round(actuators.steer * self.params.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params) if not CC.latActive: apply_steer = 0 diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py index 524a02a370..cb401a8abd 100644 --- a/selfdrive/car/mazda/carcontroller.py +++ b/selfdrive/car/mazda/carcontroller.py @@ -1,6 +1,6 @@ from cereal import car from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.mazda import mazdacan from selfdrive.car.mazda.values import CarControllerParams, Buttons @@ -23,8 +23,8 @@ class CarController: if CC.latActive: # calculate steer and also set limits due to driver torque new_steer = int(round(CC.actuators.steer * CarControllerParams.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, - CS.out.steeringTorque, CarControllerParams) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, + CS.out.steeringTorque, CarControllerParams) if CC.cruiseControl.cancel: # If brake is pressed, let us wait >70ms before trying to disable crz to avoid diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py index 24d85877d7..a6dbf4a39e 100644 --- a/selfdrive/car/subaru/carcontroller.py +++ b/selfdrive/car/subaru/carcontroller.py @@ -1,5 +1,5 @@ from opendbc.can.packer import CANPacker -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.subaru import subarucan from selfdrive.car.subaru.values import DBC, GLOBAL_GEN2, PREGLOBAL_CARS, CarControllerParams @@ -34,7 +34,7 @@ class CarController: # limits due to driver torque new_steer = int(round(apply_steer)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p) if not CC.latActive: apply_steer = 0 diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 2e0d7009c8..8004ea9dca 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -1,6 +1,6 @@ from cereal import car from common.numpy_fast import clip, interp -from selfdrive.car import apply_toyota_steer_torque_limits, create_gas_interceptor_command, make_can_msg +from selfdrive.car import apply_meas_steer_torque_limits, create_gas_interceptor_command, make_can_msg from selfdrive.car.toyota.toyotacan import create_steer_command, create_ui_command, \ create_accel_command, create_acc_cancel_command, \ create_fcw_command, create_lta_steer_command @@ -60,7 +60,7 @@ class CarController: # steer torque new_steer = int(round(actuators.steer * CarControllerParams.STEER_MAX)) - apply_steer = apply_toyota_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.torque_rate_limits) + apply_steer = apply_meas_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.torque_rate_limits) # Count up to MAX_STEER_RATE_FRAMES, at which point we need to cut torque to avoid a steering fault if lat_active and abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE: diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py index 5d00b5a52f..c17b632450 100644 --- a/selfdrive/car/volkswagen/carcontroller.py +++ b/selfdrive/car/volkswagen/carcontroller.py @@ -3,7 +3,7 @@ from opendbc.can.packer import CANPacker from common.numpy_fast import clip from common.conversions import Conversions as CV from common.realtime import DT_CTRL -from selfdrive.car import apply_std_steer_torque_limits +from selfdrive.car import apply_driver_steer_torque_limits from selfdrive.car.volkswagen import mqbcan, pqcan from selfdrive.car.volkswagen.values import CANBUS, PQ_CARS, CarControllerParams @@ -44,7 +44,7 @@ class CarController: if CC.latActive: new_steer = int(round(actuators.steer * self.CCP.STEER_MAX)) - apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.CCP) + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.CCP) if apply_steer == 0: hcaEnabled = False self.hcaEnabledFrameCount = 0 From c995acda7c502bc14fff431ba4832faa9dbaec18 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Tue, 28 Feb 2023 03:01:55 +0800 Subject: [PATCH 1023/1179] driverview: use static icon (#27448) * fix alpha * prerender --- selfdrive/assets/img_driver_face.png | Bin 19875 -> 3769 bytes selfdrive/assets/img_driver_face_static.png | Bin 0 -> 4908 bytes selfdrive/ui/qt/offroad/driverview.cc | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 selfdrive/assets/img_driver_face_static.png diff --git a/selfdrive/assets/img_driver_face.png b/selfdrive/assets/img_driver_face.png index 03765a0376dc33e72f88fb68d0f3879bffff90ff..e2d943e537fb1cc489dbcfbb3dcfeb57258fb4b0 100644 GIT binary patch literal 3769 zcmbtXYgAKL7S7EjiRN(uK?oW(NWhy>G=P=FX9B1M7(whPj#kqsXltwqxX=+Fxrt(E zsUl_s9aPoJNsPzOs9Wlt@*(r=iIZu z{q4QKbMC%H8A}#RgyV!94o9L-PRfM;x6t1xK8)ipz50N|A*}i&-MibdKDyw`um12} z(?13`Toqj{U*i0|v+}R+ZqzL;dC%j^q$F<_8{((M)U}r5h20zf5OpW!kY>u6nAm@E zgO(28<=v2d89aIhd8Dx1G5JgKWW=$D&tCOhso?e14Za<2dwI6u^RJJ;?(KgbnWFr{ zk=aaER%isclH8Eu)N9(~c-gU)y~XyUnHl*B&aX6TgRpsHrTB^AM6gqr)RSu_l;ozO zT$??267TVED(^MvdNMNto>tiBWvVbiK_w##dg`!Dcprz&(N8VMMP^wi#ej2R_ zZy7C^<1)N2>vh=n1&N+A&ftn5B40}<6z$733xzEj!D*L)@;0j5OKr7B?9s}sfEqdB zcDck|hE!pQcAC{5O_Hnfs(Cy?noKQ-P?B@H4GNwhMMk2@VT;OU!xcn{JuukWz)mI; z4m62-Xz=3+5@e%Lq;(8T;-(N*I~DBgu&7FGVL@?E402v}n@n6~IOR>#NRxFMDZ$TB zB^nE5VwX#%5a48aSWFzOWe~@}@aA3!5huw{9vV2jIC)MZ%@HJ1It-2_^`mCP#H4EYo$}e%okAk@{IiMzd1$ETejzk<0GF0kJyK*aY}w z_I~6gyk;FSF4!51fqi~bZwc~}<^}r+0du-si8^Ia?wu0`f%kxVBY;f=NOOu&z}lzF zW|HbiOA3p;7{&^lI#M7Jrf6`OnDiAk1Xd9UOK!yyT4%RqLVgI|s(@91>2k(Bap~v~ z?-76@v-toi)thMWoSD-Idk=X-*awTy16}bW#3im9EJhg>$jQ-gV9XyA!3LS8*_fd! zk+ME=ZUP48)goH4c@Ugf&dBbpIG2h4myA(|TJTS@mX7)iBz@i6;yBzGcIwUB< z#~uj!PWY^mO^;kU-TrnD3Ih~K@FbO25Lv=$=d-`jdigJY6TD3hKI_d4-p+=PV*|oq z%u1Ze=97!^S-g>Tun$H?T2qLUHf=8eH96j44RkQ77oB|w{*@xA2_0yZAgU{+FdhhK zVl&VPc;>z8tB6v_RUjGRjX{O2)xszXKVU(D@=z@og47TaWR(6`-N+g=gTYwKUe+~= zXKL3d#Cs(P9+rCpQ7UUQPz;U;mJ$u=83p_KK(!pK!Vj<^@IaSx*pB=fz-Vul1r>T^ z`C}HH-Mt)TH=6~iVMQi-0_Am#Wqqn(OgPI1WdrR77{6sHqN)Z=Wtsec(6W(4vL64Z zX#O*J#QOv)VBlhwVFC!RdNM>0VeSK!{a1ETAu>a*0rjz#Vm4byIa9k(9*M0%8kw~gc%s`x93AWGq^M1HL)9uQ-scR~0%rJx0{-$~k!Xu#zv5w-

rm_t!z9LIw?96gA^h_s^Hg9tbrV=GS16K`Oh_gw`T!3t6&NVD^WaR-~|JT zm&0z7!=`qv7@ZoWzyleO{NhM1Vgm{T!5BC(HsstAN6`hgXbiep45v&Bbgc`PxpRi@mdPx7+f2H@nXp~tOHQE0=!)c7guuHZM(}(W|IHL8U*BITHVzee)?(jV zifv&KrXjVZeCO$o+*R1RewF8?bp_@RZ;1`)+Ket*hA0?`B~KSC8a``X zKg9E-QqS9Mwt0|RCfG|ro~zdp`ANE-+F>3uJ3om|f{@j`8gy&+TJ57r@;xG|(y$n< zM%F~Ys)?q(!OrQO+pu(_QOI7Ua6PkWA@ZL;pk{D?#&?!Zz3;zsP3tCde8=U9_4syv z&@vSYdX79F36Kz6e7)B5fYZJPjO;C@wSH@w{esUvg!jsv$x)2q8?oa|*c-imOJ(n;eVvpjEeR}ucS$)gS7y~j zGoN_|^IBh03!JZh*Zjz|U{t+$?*7;JN3AY-wNg;vGBkOUWW6Oee&>1K=eP8GgmYK4 zhLVSChqcTi=7P1!(z@9C!0)HDQcWZ67o4U|yGARO?Vf>jYzt?i_iyw0_sE`Mr@mwN z81v}uGJ|$?-*SCuhlf5umRrlq?T3Pk4MX9c-+C6F%V8!mfu%1_rClBPj!N}>k<}lf zzYtSmUzVW?jERAMLVA55k-A-T{~&kEAJ;c4ObbLnwfyG|+SQg%sye0D>11J)V!%V2 zk8G7hbnKS;a+m^jPi57r%~R7lG@bESnYyRWbE|aCjSyL}%V0F7qxM44`8`%<-H_KR zpvv@rIb56PUdvtWckXeOKOU-RD2i^s99mz91@}_z5vVb+^{vHTFjWQAK`cJ`?b_y+ zb|{|T+{3T$iy&jO+zj+B1@eKLG+*dmKQxQUX&cJXA9qz8+q|#)kSCkzIXk$ViPHD4 z6QRyxN|#vOuBAgv3xXgP=b5nWk-pjbNtG4H`ljGz)~4F~3;Dq4lQnK(JT;j!T2^+VmB3+C2&o*-&l>f6}tnVp09bnN!J zh61ao^o2nLZHRf1H!KgDra;pJ?vGsG=89JzFyBWGYhbUxU^;%=&~Tdz2|E-x(q@IB z28%N7ndeLO+*sLvP%#{vt?CpuZR3<#Cv9jr$O%;pN8_52{tWeO_tw)Hcqd#v?;AJp&gKY3#Sr$V{$xWBQXlL}3a9j}%q z)5VUXxzKv@I|l`8By&Sm@^ks|z7%FqvFlLoSRfu@P4&dpAHyu)eiGSGAwkl~@fJg8 zN{@5%c1{JtIc)|0zPi%+Ng8^f+Zu|c}p%%5I9Ch{^t9Q-wEoC-g zmak`U_HceYP<2tcqGtGvCz8Rem}MV^{mcg`9h}LsD#B5B+|+(~l8?(w_G#OO7V6KR zzSrcoHsPVvl)C#Dsa4cP#Sd4;5&TS5UY8YF#kePlFNM9)wH1u_8TDJ9%Idx{&lQ5g zK6S6qzm+t)8_%kxIvNWQT%|_|mzy3;db1fRb&QW-4g%Wnl&9r=r@7}j6H_}E>M!K( zg`Qm&V6n=ItEzWJ`+}K%^>u4~*GtbPMS~-+c|b(1Fz>@Gtt%)|>F(oW1relL)n(O4 z`yYBvcl3S+H}BCr??61Kj5_{)-EAyhzvBxy`7*hMkri*7VUFIlmiv)ljbP{M))gyR zk#NhX)72e&IPt1d8y*$XNY7j&_;I=q(+}3F+zXR)=VIH#e7NVGG%Za9iMkDg)A94p zSIQ8tyKyfNpMhT2NOA>EoU&Y~dajYXkNfS6@O|e=S7AI+R117WWtcg#v}9T% zZwZHqDv^k)Vq}3&%k4$V_BcV%GV_umn?2TH%Uj|+qb8@2$K*St3uu^Ct5Jx z$yDcE*))eOwwyfugt5Z+Q&9F8B1fz1P%a&4hC9^R5OC7DG)bB5{24DB8jO$Z+`b<^ PNjdt3OOnnd7;OIrwou~J literal 19875 zcmV)BK*PU@P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O559(&RdhrTJg0=p~4x__Z90q|9aqv;27;dPG)c zRaRHG*<|Fs@m>#ixkLg7=YRm>+W+tW^IiYzfBmoU+`U{+uC4S^ZvOZ5r^mq$?f(6* zpMQt@IsZQYo9oY?g@1kh`o|wcUP}C)e*am=pZ5=5&;Rj(zuytwe|`OGfBq!4KNtG* z2Y)Y^{N~6H>z{9u*W>T?@cg+@-@hM9Z}p#V^^JcX<t^D~X)pO~8T*Uvr{`rNc zvPvuSt`y@=A>HTS?RN*se^MIfcmG{|-}#w8yZ9}nzjwld{LAD0{r$fGd4c|Ak^la5 z{pZ#H$4~!h@#FaOdiqamS^lgMKm6N22>IVH{#oLG`r`DDJBt7M2dk(2UmoYrKi{|7 z_wC=)ji<1p<&Q<(*WcCgGraL-$ilZ=xF?&l?s>obnxTitu6$Q` z!U`jNVV~b;nB3wMcVtguj5DV5T4RrToa_}_xiw%8J{Kvh7^S%9i z-wcg!UV*p9z{SGZ?EmK1^}qYW|C?Xe_f3~5-0dH0#eGFBm)mgX{5S7nL&EoG-||`D zzrX%$|NT$)gQ>EE`7Cqe0muFRF7f8@AGVdwJ}2In`Tge=;i~J;1y~}!J99H3u>*Gr zDTfm78e!+%oa5pq~L+6Vm~|Yvg>ZU@9|-4U;3Uef90!R`}#Njv1@;J^}qc3zu2|#XV>D{Dc@KB zv1`0~)%y1mK{(0o89NrAz>ZgU0E3S1+18+A_|~vtvImbWQJs_wnbujVm_Z zvH2Ot1kcKz-^_KV`+Zj2-~LAA=1QG!>b1ms_6A1gucnXqb$=;uKr^lDV?jsaE_Qg^ z<{Q>x%~s<%OKJBLS=vcR0-GKd_};m-{e(0(Pkld&Z+N-!aK$z9kiyhPH+0c;Qj-9^v%V)#`iodHo#V5s2dmz^BwmFoo2ri+cpazfHB9u z!2G;+uayUB>wE6+&I{arvcYBwDKDN!`>sW)$aGLO`OD>Hv5*# zlUaicOoVG?q7k30YsdI;VSF{j_YL)X6L(&?Mg|r!|HR90XlwB(8cyD0=Dymsb{Q#s zJ>Vg4T63-z*FN`IG2?;F)D_t^o|WuXZI9t9k zpT(zgdibJu&lEG}GxJ;f1TZkrG6~tEE?{M0ChU5u`@LD-c&~!BtPka=OQIwS{o#Xb3RRz2p5T`ka&D?$&(Ojnp6 z_=XdX);`Z32ztaIdbj0%bs zHrCyFuvW^uu+rVqcP{wV4XPLZeZA;#n6wpXbMQGQky- zeoM!V14s$p%z;MvD(i%+-de8K#}yLZ41j2SA7nBBBbD1WG_Kw;JE9Pn!uo!&AY(oF z11Ro-k>S{26ON4yV$(P_IPv@(d*usAe&^mFpb7r67sRJo_-Nd0UGKybya~V>UnWlB zfcLlOHtKL=X|fw@ueq=OrqnZ56ieD=reM6NY;WQY@4oXp+znJ1fBdkAFL7O;hPC9c zJzRt}+Up|F?^SPbDCHp$p3fjIY1=IW2-wBKRURD`I4?Nb_*!6{f$)J5mM?-$&sBIM zW>L7{l&^oi9yrfHQQwfUy}lg*-BRD0&rm*?3HVk%7CRcEp0x_d z)}95@c)zuWjF|04TWK)138soNmy!kJCI)Q)0~=m=2zJ)q`Vh`5Yt8evcVBCeORQnP^@51tNWeM! z&+Qxapnq>1Z6B!z!GutCmU}|U+R&gzUu!DoB+-d4{KVlq-jET zvgEQTR58Z4v1NH0QwZLnfJY4|%o8z)9j*gy&3k_#iNFN$^JN>6HT7nnLM-qEuJnfr zVNJUcTP5sl7(mm0?({%K6L0%Ky6igC1pvKRkhGyXhK^zas0#ofV2l(LZN!|fM zB<}uB^ZK|52o5gjH98@vzB(&JgorTM)^d$}>kA4ekQO84vB>T zSfH`$2Ju0p$+*SFm5J70#2Ma-Q-S>tD-OFtsK9veZ0<3Gwa|w5+E43`-0H=Mp~~&v zs}XfpZK1Xf96_wX0wH^&UEi;dazl>bJ8(8A1Bi@_fM{u;o8@x1->)_-8T%Imv2LOc z23PWl38}JQ2@=2az`2Q@gjrM#&Yv#!i|v+Cf9w)o4T(vm^`Qt6wuzYoe#34AYF%n;hM<~s{FC30t-tvwDVZe7foJYOx)d&B)ISCAK$S3^W zkh|dQy|^J8{z62$2F6T`S_traH$*xZ(dX^voM>-&VWH862nx0&FD!@~#^N^axC^Rv z&Zl0n!nb$|JV~a-<|7IxP=i%1&>k7`p_ATTpcRz>w}=xERTMrHp+k&$Ok5RTVG3Xj>}?okHwYl_6H5Ou)qz~ck-iG|hrv!aHQgP{Hfultf@TG* z^5&+H!$u|86%h9wlfWC})?oU3W#spZawzM0N5dH(^H*>AO(<36eGc=m~xB{8jbb3 zfsOl8(X)p2+%!IDVu1KapqU5j3R(jw=29yBhj%}iCUCS-oaR1J4pDlH`=BsCF9r4d zMPz`WiGt8*?$xliLD*L)W@d5Ba{EZ21PTJ6MkubdF8BvGA^CtoK%M2hfC<60ePy8kV~#5#0I`8) z5(Afp510i7l|e<^6PLmu2M*7TjPZP$aV=n;d4j<6H=rMFhGY!W$o{w$3%2vZL2q%Q zJ~u>yaCspV6VKLaeWZ^G&QFBFDE33R!2_To@cxbLf)ebw%qA4T-~mUc6{jv zYV0+F=zFFL9rv!HM%_aK4u<<4q7gdZ6A4qSTtl`G6bd~jNAhD2Y!6gktA%G)^Iq6Y z$2=hl1AYU=#R5V`y3GAtnlxNw{)90BG5v-3*E?i~CsZm)BHBpvNr4B%2J`VNa06_@ z@b<-4-``LogI(Yu7|M!2Y8ME}oZu^wkd5fgFbvms0SNcsyV*wJ0z9wnVkrpyr9ivP z`pFXETgd2082XSqSPn|KB5R3WbA#ZRR7^PRV0XZHu0;St)ZkGsdh?EWIwW&6w1;+P zByh>Nxp#XBf~7HGoXjFDB_m^?7-&US^^#R0rn(HDzyN~a#0gt~941tZ1e6G}Dtdwo zgaU}&(4z=r<+q&FEC94b3ptT6*1mpG6xzpkJ|Ou9p^WWr&|tCN!d}8D4u%m0@8;8* z_3dmwK^8zoiQw~zr{YnF6Zi!|MjZ*iGq|xO&d-Kus39goefjma(&xH^c|S zB5J%c(H9@!o{2;()!t_Jqe45t)-E&;(W$a_v;KAq&Q5d;<8|dSi-Qmxh>DY0ReuB5 zL|)eISQ0pBdh#O3gHb#&Ot5T}d&Hll8w3TI9R64FFSty>kLv?h1>w2d=@uag0X?~3 zAoiF2@N)%6Baw1J$7Rqj%oI5UQ3HJ+Q|apbjDGOc3tGl1o0~L;841PLi!6BMGXs=v z01LQ-`aJAupA^jw2va<+)CV-sOIB_;FS=)Rh>xc+DO})*nWLwnxeSyzwn->WrbGGx zXN>iU3kZh_o4#b5J5Io#e{ou)6k$>0$J4K4K{yk^V>z-a0W%AL*DOlUx8k_fi|0)``Ca0UwHrl~eU z?yAp)ikp9M@J14qB%fmU(5Ef;4G-ow6T)VPHO-B3U)uMAv=PszDt|p!5x@)frpV*A z5=;2JMC#gWG=@HAH9V23E~Rl4M#K6geD5hlcIDxymvn95{fkHsyY$PdNxJ}aJRp6x zDj;RBmc449DKE5ZOv9V!bNwZH-eyL*fTUlG#Uv3+DA0$<2X1W-hbnKtX9;3#G*84m z;3uz%laB1%0|4Od7qJF*5bDXYa5*+LAASP(a|>n!u;$q0`Hzf%I7ejqB8K7l2X_SM z?05|n8BnL7-^z3J{5_(f5qg0&-W~uz`)cJIE7296zytomI->W(YI)S}V$XTp4kUVl z6pp=mko5)_Hcmo}t}OXtDF`Gy4$twJ^6ZEI&Vk^nM2(9JRD~xV`w=ET$V;pb?0s;j zAo7;vMU|}#0~Bn~h?@`u7LC{RY|V*XxO|`jeh~|Z*vqV5E4O456GuD>gYEcR?0o$7 zEBR*0GjSA&45>wUV@H4**bQ(Pe+U}cTb`dO2@~3K)B;Mu4%0knKUtiB`8+pw+~m0^ z)#u{#xqX@{JBKDB9d+*wjF1509dg4p!SIF?N|Y&_9m zjNC*J!)6g5A0b-Z{{0eUY<50k4ATKW@Q_0i30zrq#J3V=H{p_CA5F=yOX0&=z$-IU z>zJYcVFJ)YD@$L9SV&(5COVfW(#)6Fj5vBQDNn#G!`K5gkK&J_0+#mPo}5j^zzj%_ z{yQ|oT)b~l>e?ONzEP^s7R2Vgvtf7=$BxJ|DUWZBb5h5bXLIGB`W6!3jyS=8OI=sr zC7rD0(NuY$KyjZ0q@!KD26y5)v96=a(1t|4} zs2@kn>REhst{=;;I0+ACbz8hd2saIpO@y_3%L4M1*)xx24B!u|{VgOU$m$_q>XisL zJQVNzDb$%e2g3s^D3C@M!hSKno0eRl+<$%KxWIW3wtT&uk!JR!&6C0o! zEcVwXMuve5$cP6qFuDX+!myx`t~+rU{VX??m%J`0q;=+ac;E|7gg{l)QJ>=^y>Cy+ zO&c^5!pB>14|GV9YT;3y6$KE5n2($FY)*tPAXww?#o_;f=SdqZr-Dc-*Uvl=kN0Bc5hkh!V97= zS(Cgy2Eys^bGE>wFl33vW$|L?Q#a%rtZk=UBY%^J3D-8}4CLi08eof204!lo0w6jU z=3OVT3aJ8Pipf+5RQV2oCt^wzXn_5?wlxDR*xLsrx@@GYnhqNPWGDCe5e#+1bN1tb znxYQLd{+Ntv(uMwkynp|5_-%E*{cx3VMa_z`RCO87X*pco?9YtYa>*$)6ZvKp_n9@ z$ z!{Pu{Gb{Hw$M*!EHG9v)sNd>>>`2E!k*;&?<+1wh_VW|*qj=o>D?%_U4X(h6zN73| zIac|DlV)PULU$t*K*487BC+~6rYqj(XqZ6o5gAt6?Zr@Eg3sWCPxm0_Bl30ZUU+;# z+MLZcTh2+;9|RX7C*rtE7cjeLb?e|v%@Kc=n}*hVq~tAd$#c}>*cD^PJjwZjEK5(K$Ht{TO<~dCb zdmt=kJk($z#R@lZR^aJKPp_22TJ@aP@ZKiQR00 zc@;bwLJOhl%6)iRBINKyEEJ$IJeZ7Tlo5p|p&W0bd^0hz(IOR1fo(%=*VuR(TGwcK zj^y8#%kv=iLI)gII!A63f63;gkU0dEWmW~oMv%P+YiU-wkBZlsHOv4sg3^dK_kwqI zOHvN8wUnZ88G9(d0R*AzFT;JNU%q!dNP%+4N#MWX|$MuZ02ZFnbkpK-Sp(L(ZI(}$b8zBf32+0%% zWX>egQ{w}5YDqecDImyRkBU)U-+!V>*AHL_Y&UVRwAVwFYOY4o;PIJG0@0gRSfS>D zk6Eo(v@oT9SnA2E;(qec5GVgZC=MT#Z}o#DE&fkPa{Z?l03wiNz8@hXW~)CuC+0QcJhpp| z)bRF@EJOLuiO_NO?D-ld_h}yh;`6+}yzmV-`8W{6U2I7=`VlZCrM!gk<#_d5~}Z!yDT!Rd)0;7sOj)X?EFU?<34lyCCMS7KiQ@!%=n zsgRHdo4~k>>3$;nXb>F23{(kf^u<$uR3$$i9^onfbTs_0=FaN=_aXe267-AhEe$qb zd?c;T`o=OQw}eHrnp#|>tF-AX(Qq-J7E65-s}31H%NzR%`AMZc{X!uie~jV zA$<@fbH)fCZPk*8pxVkEc=U*<+}K#VFJxePzmq$KTmEa5{GWagMDV{}di`5B64e>7JBZBVtF*W6JbbqgxIOM54fYD9zJSKCk8Erfkau`2m9mdH* zycTz_YH_EBZ}Mf2@l5Q1*%<1cn@Er5wwWTflHf|^)Z9Rl65Q#DFp0B&9XS3^TiY#} zj2HI%1^p{LfNnXG^|ejFbo==%2;dfZ6p0rEq&|@rQU_0lZg-#nW0FM7VJnlRfE!h3 z+8djH>a0**bB6dE;6(@+B}EqYw&Xe7fHt8te!K!*nO>-vxW{dmxyV!q5w9T`8^)rL zgAnIZiIPD`I7bwd#XuQI5ItGeyRU|wj)(hgvd4%U1y2=bHlNhb4=P*$bA$)hQsFtvPH zO1W&WdHy`@9RD5T_{OPnD?<695k(sD{R;W6h3?41)0P`^^jsYVY0(gI*TSU;qMhKtUM<6ohvSI?3XDz7J8@`HtJJ8C9cyA15exbiS_lXP#pDl zM^J8*+OgJnZe8~BlQ{YJ6{Z*kc1H|)%yu$WMCF%_-^AEsJ^B4>9M^xg5=-&#M>x;rCxXGobH@;_Nen@vd=*w| z4$Q*XQ|=V=Ws2hzF&QKMSbHtw^qADt|KVhJ`Jc7u^{*TJ5{M(J`ZHgCa@P|U8~C;m za723>mesmb>p}|?{6r2Y`PGDu@W=Qv@#I+bXC2*V*9RWD?NNZX=@;c>&`m#?r}C}| zBS?~XJyYWUL{?;57&AQ}2)encwa@TzRL1+?Bt;=o2FY^$ip~3p66;r&?y&|@A}OKe z4Q;Xb!gVl!g6RD_VjOc~(X)~A804?Ee}J@=xuO)iEG)0&4KmK<*xNAC5) zNN?;GOAWbXo1u83bAoRJK>5`W0r2=A&uI^x>~%i`)_bEmS^V#XrC!x;p!|Hq`_~id zVYc->7zt^BD)9DE*~*T^LmdXj{&G(eG!|;z?kXhjl2Yz;Ds?2s5k-ps!Xc%H9{zl< zA>^bso0TMluBpfz#aPKMyXrywmq~rk|LFnrrY{cEDUZpOsB9t+uZIs1iCW(iO6+o zCsCRqqKG}asCPo^Kh;{nei~bna)12o67XQ$;=TfJc#f}~4wkzUz%1ko8`KCN&{&5B ze+a9Uw1odA)&H-W)*rH{9;e5qf)2rDXBMX8J{UdgzGH?84c6_pNvV7IfRp~p#LTdp zKC8r(9`?Ofu$&LO$hI|@oWYi(g_m>i+%`@q&<}Zfg7g~&zb#yV`Bxi_5)e;Z>95@5 zHOWmtwP16cdWE4?Ta9m36@(x1w(|q>5R3@tvn`<3HZMHG!%d4u&8oJ~ZU8GMA9w&p z{PG3+j@t1!N6@xtoHFw7542wY5|P=Odv-f)>is+j(TpUCSnJ*vNuC51>J~8|?D?-y z*Wf8rxV-R(CcuLft?1HDtT@YoL>yKNU}*8^4VZAT|72irw;>0OYJVdBw=Sr3A%L5d zVFgX0cl(2u{SJU6YRyz%!)5K2c(YZjv6<9|Mz{XhKT&FcM7#mZwTcQnYPb?wbhK)z zK6ltz`$Ie?2pV{_#{-NyCj=wSK3Qc$lWUabSL|`fCtro(LmmpY%u7h5usx=K`_rOA z3`jyVSwS!}7;#GF?*+CD|Z3w^93z}YW+G2lMePi-ii%2;nupf-9cc+1|tVRU#kTwjsBeKrG#^L+dN8AH{9CaYS28 zO2l6i!QmoYZfN8UEpwZLV9zXlvZF(v1?Ru`KqBnA^^W2Hga3a6UTTi>-vVKl%-wcv zlvBE}J^z9=d>4`*g=HMP&CN;KAa63}vpse(d?J2ejb3bbty+mHx-!9u0HPkVgQcH* z65%$bc_aq$aWqIZ-bz?x4~6ZeZb^#}86 zWtxe7tTThLcN>k;{g+_tekYs%&hoA8OZN9S z+kV(MnAgW`{mw~`?03>d=Qab&Q7`q4W# z;3-wyr+dQMPj*hkTBkDN3d*K0?uLui{94dx*(`xDbem($Cn4CTZE~epTnGsogNR$g zsdLTG$%S5^N6WAumkH9J<{Ry}B^nkBF$sq7l%DLP7#5Y<@6tVdt1L?X9ib58En+SU zq&9;Mj=vBWds%VRWqQd<&GFQ6;->}Li#UC3)g&9%_u;*-M;BMN0slUS#g8y==`)yO z4QB8}nQ-HYZ2Nk$72P=*C^vQjfz)5S!L9CuXq`+w%)A3r#DNZzXH9rU>z;~-P4Lbt zrCbEHSZrP98H~kTkq0R-e{;3J#LKsC*zC!V#eY6U!jHGccv|eBu+!?_`mkY*XifOD zOu=GLMNKxjVUeHZll)0xrxas7jefioA$RIxZ5BUuvCv5yi^?PNfM#|OUIHZs*c$@5 zHn?mK){V1MaF{YoDx)5%f$IK>SdPzN(7z5gi`UR)Y}nQI2W5eaJTFFP^P08}0$Fba zv0hHJNxEjVu)BP>wM^V~#ZS6rZ}uilFxyiq5Nh}#@B|BLZdiFt{MwFW^WA3{dQQO< zAPZ~5ax2eEgpMeiSi*Jo+lovOdKSLN446_#|EvZM7IIss;`^}xP8K)VawNKn8&I7UUIoKz~qxEQ!28g{a7~U2&oetbn zik>ZNe!`A7KpM;f!Ds5x+UO1F#b<6GNnz0-Bm=K1GAH)Ql({FzES7b~Mgu$oupp8) zs}&H%T(R3=cth`Fx0&F+RLUd#8vH`B8|ha7JIaQaL2KcWl;xa6xSgNYaz{^W2rKn>mG5ZUzgKa5&RGBG z1F!5kc&$RMr@{=THRK6RemhN^ z_k(rvO+9BsjhR8HHzEdP4tC3@f-5CEqa@#VyiW{42zXQieCTzsgwMX6+f&EHdR<3? zCbL>*4b15jh}^>bdk7vRi}~E`cS3d&|FDr4MD1)#v?Z+*-qy7(o2`=i1ebx~Rx84K zv`tF|iX-LcRf7P=fsZarvMhSR{vnVB0)Ujv7sg2JB9L^MIa?fmg`oicgKeJEq|eh8 z%yB@-?q*RG!QlCo78wRX%6MUah@6U>1AqzJM4*D6_F`eeD9T*B!qNPa^?rnu7v{2& zd`^3SKs*yn0*}zMrwS_Ys0J+T1|Odg40DOB&mhLC0J7Z_!M0j^U_w%GzzZ#y1AZ^N zzzY9qBa^T#_rN~F_>Xj1)a7i7Er2SJT&zzgoTIREN;gW<=^h7Sn&UW3reIX#oEAWQ zABSs*%NC~+qPS^Tl8IBM|sj;+xWOe)rP-lTZIxq5i#4A2=Wm4 zV18yNT2hwUx59NB4xnV-cQS-&45&o3@SYcBb)BsOpkDMpC>0RHaQrVLec5B;v`MC5 zC0uf~_qKV?X*iNdHckP3J)-kmAP_u-csf}79pHKn)p!hkj-6luL06M5tytm!OOSF{ z#m5q&;@V}u6f~k#dlZr-k3B_T`*aze{%o_7k?VvrL8mE>u=adPD(AM7(+0!KKIdB>59tXVX_@I#2SDy654Eqxh;(*00I)WIG6p4EG2j@79K3UO*X2Q zY%wJ?u3_-0{;F*)C74dF0t#NcRqfQ{h8{@(B*EG@WQpSevQ-hc=`?G(cSIdIX#=(S z$mmZ*#L~?3(~g$R_HV z2G?3FUW02r{!~+Z%kW7UMO67~TXH^4(J5?7`~; zH1aOnf=%EN$y|3l(&w?XJap@zhV^z6wLi**i~YtNK?$=}IQ@(VV$1ol5nDnH2up(N zPoo6f!yYtO={x<}xWwpS_UQ$$%Fh`4Ik0LDtGKJJh5)do8Slxz13{J?dm8)Mr27%& z#&0lAD}hcS8;$Cc-eD--?m?_MXk3UWY zu;R!{sTq~3M-)1-Z;V5Ab4kK&2I zbBqvox8u~2XMYYZCn0LRUpnPQ(OPYu32bJ~Ev~TL0Bf{6xY(Hl19v>xT$WQg5-XQsp-y+;&22Se zI0R<-9q;K*YrfRjZylcKGi`XfNl!iIYK??3yZ0Co`nMHC=c zW5gnfG?qW!@HuCSbWFJY#v_=k9|@;D=YL0f;5?31$iuNNtgu}YENJbHIx!7VZEUdp zHT*#3v~e`snSB!Y?lPxW0M2$qj9?W0; zQLtWPTN1nPwuMegS@;eO9nt+a?@iV*$G9q+i|(UK@_c&+JIGqYyOm zR0F~W3xM$kFmhc3hf9zMk4GH0*qzG4wJ@P%;~xaY%2oub!v`+HoBV^je%iIZ+J4&^cCD&`aM zLUy`$?GdvfIBkz5^RKEkIS_#RfsLedy)9pU)tT82XT*Ob0ut2iJF?vZ7q(2*U97ft zd0r2QJD)|L*sPJqseo|zIG{S#r2h((5dc#-m4ZhL>!MvFXs>)23`g)F4ct(k_B1sjg;sJ%_3UO=}iU8we}gG#TjkIq&J@f;>C==V)!e(GP)%kr~U$>r|4NbUwP08d6_2b#RsE1f4$C_~_- z1&GB_Af@d)qkoa?<{^JoYPtjB$P|jr0T51L7cuv|5O(J-C?I14pTms9TYuziS$5J+ zS%l{yR{0W(i#236mE4Dro0)hKF&AXE5jSoJxAY8YiO|c_UuGvfss?doQG<sTY2f}9v$n-|o^FAm*KHMobWSNag0Fys1<>1%dI92pq;@As2|^(@_#);aL~ z-;@So5Y{a%#f!@Cx6<)(Rw|c(^`n*G_cpd(0CPCiB>C4j6DncUsP0iE7H&YvF#oq^ z`<_rZ@g}}?`+xE6=72X(!dUElDuDp*d3d%|aozgf=YUh^Ld_A8Me#k;>?+Vb9ON?J zzjMYMGj;*Fz4kL_Y>eP2m1^e$T89VIP3V+J@@Yt0{d0%t2p9+DG zX6N+4UtSo8Q@2z(iIj;A~w z{@+Ohk6)*ZlZvcE>($943q{Yn?MaQMfuJ=`jkNOob!f?w3ph^jY4Oak>wv_@%AV~| z8qdj3Kag+f&T>v)ZrC`!rg}q5C$lt;*)+Jhw^^4m`#CG5YyTOq=s+bKh=HgP&cF~G zatT=%JanP~h_jDJdQgp1{_2zo8$2z!16!QxI$N>y>M@{$7Y??Bh53G9YFu~~H1H%= zoqKcIqm?%fs=}&xflmXU&R|u&wO(L%_rQ_3F9#o-)1Y*niVc{tQ8+so6kQCTmL5pZ zG4N%2<8%JVY4WN*)wHAfakx%Ka>Mn25rF7{3~WA)%@R%_zA(Pu8Q4691cfIw1G`T@ zIo#Kdwfo)D;fN!s7Op4>2F{CWNJBaGg8_RyYV_BpZzzF{Us2r zem#aS6s`T+)=oIn1%M#fydJ~YIBAa0*?Q?TyS&h{X#@U~F(fmf!7>x@Xhu^Er*d1Y z|9CWl<*$49w8JPP5$>vw;@Q*ZEW2fi4Y=^JIrgkw7CrJL6@$lyNB*YvuO{))z;)nZ!L z%)dj22|Z_u8>^VOSIplwd=$eI9uvVlI~UC6LLs9@*uNuvTXLi??)LsPK5-^+JH=yb z%q1Qnb0UEGEoUDccryKFV=k;7uD`5>pLc@&*oI(~d-Cbalv0Cm+2VHNuL)Rh`wZ&k z+QDWiz`ucw3cd2{{Q^jWV?460aj%i*%rUZ23ZY>>a&{9YgvyAmZ=;!$kFH!!6U=Ru zb0#i00)lYq#2lEn&Hac5=gkJETZJHUy!>^Dk;Tl?wtCrTVowM}uRF^!%zs~nWtDq(8Yjr}aMIbwKC^$EQB(EL(6l21H6#Nxif6)OK=V}q zguu)#AbHabyS9+-!7WP$n{6h3{$_@=;~Fkg_sfF5=2+w03ZJ&yTowp02WKz`v*g2m zvSwuy(KdPY`$R?x}6)+RR8L3Q#f2#LM);K)a(Mn!8Vlharn zEnTs2u(w%DVJDt#w2;+y#-LegS|GisSZHI#X#1Apk(4L<*-6-lV|o43u$(?m<0zvBl65ZdQzavuNiZqj~qQ zjMTViPfcZ&A<#XkH%(~c@z$WA8>aP}r{TDs$)REc7keF@1@kqfZ-Fe7_j;V3I-WUs z`xhm}mh_|noq^2=-pLtkmhqkg#kCIn1A{M&pm9_7dyRGq2LQcw^#!*g_O3uiu3F>!l- z=(i_eka)PsgW-;ApMo{$Z?|GNf5yHChWj`6IcK;a8;%IgPd%}Z$U^|P3B3I6(?PGv zm}l(fDp-Ah`lR(?)J_+5tgu5YkXXNBuw=Xno>&`rcK9f`PGOBePb2`9aI8X!P3hm?~(a{6>HKn>7o(lM3@K%O7 zGWAT)n(1=H&1!zsw!dzDDtheiJelJFP6Dka7%))B0Vrw9p56YU@s(&#-Ddlp>V}A! z5y^N)zuW9|JA+lNxxmW{BLv_r7oO)F^5!X?0n*-G2N1RQ zmt!!wz?KqA7I1!#*Fm4HL*cW-Lv5X^d}=$n;=NCz;}qIBAhq5}hI$dX8pdY+2T9;tn008KD*{0Be0l|tjaW1{XG^S&`2EgF#4lA8J z)ELzcpnMIC%jtCQJcXT3xH9|tJ9=b)ECKvju7W~Xzp>r#gfmcI_ELp z!@psKn|8FOb1^odXCdqijOJV{yFh?hSdYU2FR z?R&Zt9I|aC5eme^pYH<(PqA0?XacqV)-$!x9PMd&4c~84bsolK8vr(vZoZF%)-#gn zSIGy|Jgr{A%9YT@FXwnWruVjAB|N{@s@weCnTlw7<1nIseCvJx{a#zD!k-Z-ztW9j z=GM{8koV8WJRgk?);dZ6&awTgeTL;hzse5BskD4Oq4wWslW;qx&5_{fQM^~MLk{Nm z9l<*J?j)7Z!xSizm6+YhTgg(ll-AYk1+$Lzh)oBki$28}ptt8>w-u2mHHrCd+eI8A zVQjY0fY|$(*f=#2S;CjY8K@GR;N%dx?>-OD#@f}lZR+vwXM!IhOFN7jDK#Q5KnbGb z0xw5N!EUip+h3-$fgN!O(E3+W6ohYo%xJ&PM?*R}Ul#F%6g$BwryAh-U%5QRFcBKt znU+wF?6PLRpXNyC+q3$R0R9{&TFwx6=EUZQ@Znz5lEtwvl_U#`bbV2?xWqZmgLRs5 zdaOTl5Ch!Wm?Fr$COICDrnqW&Z5ao_iEB=J;_Z3;CUCYcS9GxRv_fi$j=_eNGOP*B z{-qYtaj7PCyF*GIw=`dP(BG_4_OE$}kJ^4Y)OJ3>iJQ)>N2Op64v({h(-Bz?we(2C z@+XgoFHiT)7t~WMkR8rwiemZ~L4?my;xq5*K+b-|XLj6=$9T5*nG5tJqD2>%Qhp*mR*ztByqP=pGhR%q41dwn9(V5mp;2L~85jjr%`#GnxR}YV ziosV12qAzOOv=pE=Oif!&+&B+A7AfcJj?sspQ9(2HyPj)iD#K^Si~E|Q=68~d7n7K zN^*|)oOr~b3lcwaU2*x1bJ1aeXGV;4YMwYkEEYRh>0nkeRN@KZXin8AU&y$e z+3|z_!S8O(!uXh*6pjO3FSh+L1O#`1X5F^Gk8Qho0{EYSE3NIXHh}3*((7$4dIa=t z0~gnAP1yr3cYyvUT{dJ#^3xOw1>pURz9|dz-2&ZfZf~u9oIU_)>MD5y92^3}Mao|H zcz39?w|~#H`uhQ=0&=`#dS>JR000JJOGiWi000000Qp0^e*gdg32;bRa{vGf6951U z69E94oEQKA00(qQO+^Ri0tf~a55j#+V*mgR2;>2$M`Y&Wt&j^LBCevBPoiefG!tc-LCb1BV&@=bXLQ$NO9Fv)0~gAAw=1YUg_* z0xDnS+_x@7WAru17!i#6sPduvHbgvn zg{G_DLx7W0+^Fwit{|{N_G`#^l#m6i&1R(lq{a-DdcGtv3R)^SmLaJXq!@81xfPg@ z5TL2?mnAegf>Samr9l*H(3V_jCn$s`mCKP76|e{nLCF`O*wX?jr6Re&5-RXw*25A! zDF$dMX#}tmWY$LHQtO(^(MZaQrD$*80hH;4SxbN?)u1dXD;Kk!eFaLP*ETdacv89; zNi{0Oiaj3zQQ6h>YzCK9gR!vl2}-VQNN5anG(pL;U6)0R)qT=dfLvo|YR3{54oYJf zkgjxB!|nHkh3!6N?k%bPVTz6;EbN1!bEHmaa=bg4u;dR^Lfv^ysP{6zh8mr)x49wIO+>$r*rMf6Ow0$MSK?#dL zI7))aLVx;*Z3%hsT7j{&pDpK=Pv8COE2d@6NkVl~K5L?`3~ zOwK!`EdUhTP56psnRBuL&)qc-Oo@*Y$mLQ(C~(FeR;He?HehOa?nVyV&*%2Pk9}Px zOzw~dBP`{^lZ!PM0uvXOfQu(Zz>@ju04sL1z5IBEiWSnv#IY z@iwWrr3!YH$q_Qh9####0oer z#&rk+laEAXaGkAP!wUTn_~kD}ON=MbSW2x!JDdC1Yz{0b2H+RnMG*RNu>__LcuEDQ z?Nlyg$|W%6STB0A#p@|tZ)^=MG7=kmj&MrjI zNBQ3>F< zSimsLFx!+OXJHgzr!(8+lx>`+2I7#;Y?H@-gxl>PTMvE5Prn%JA zQdDjOw#%{56ti|po90rSl=B%X=WOG0DlA1=$TlwK$tbFXY~yk$B$f4OUR<_uF-}5J zC1o3Dxp09RkWoamL8ZH7*6c++0%IjhPp`mD#=VY2%76G`{LCu+ZFw;;J=QL$o z1B%d4w7KO%!{uhG@&Q7t&oo>NpgpENqbNed(T*|>4R6$>Xm6QmD2mWfw8eym7K0)* z6h&w#iXt==MQA9B&``Ej`vMA~p(sK_QG|w~2n|IQ0Sz~qQA1UGs4&w|6rrIgLPJq` zLc>jJRORzHVWy#isr2!c&`=bip$u4=dZ6L88meMTsgt0gD2mWf6rrKNHeqFIo1@8O zXn3uL;vm%mO>K(-90w@cGg>ri{J^P%hGJ$8G@qFSO|J8rzHCE_<_DNsGCDI2!J&LW zQ|e;CrfLzK`m)Rv=fq4yaA?b7K$G+JnjsxbaM%`oj?0bxLJc;J;0$kr8kh5{wPyr} zz)W>aF7^p&Pwdy18K&Q9xv5{QCEL^l&d_@Dxo4G&;M57s9H-<`o!A;UHP3OFVa7Qu zH}?Qs93U{XXH+%d)Cx?WLmHAKT*v|t9G1V@Ov9(tlofcDUw_gl&@kJS6M)Px^OJ+~ zeZU$4U?A3$Ww;Pf*$7U!{UilvjpCdG%5oFTDH~y%0Sy-fm<4OMX5Q^tuGz+Cv8^?M zukw@(-q>WYHRS{)t(HyMmAL6Us>&l<3d0sX}SUWCjf2)aMlbTY!;lko5%*#?Erw^uC!-0 zS;kuscF7VbEjp^IKUUStmb(>)?pjS1tRZm#$@1gM-eNHo!=2UZ= z5sh*Rz)=8~1Nhezznz>BzV1!C?mf5QUI?7uz%_V zx8zl_was~-1n~Kxz^wO+v3kwwG_g)~3?O}!FNcgXr<$sI0>H~GwRx&|%nF)NBbLYV z6$wme*WeSN7_sPLRC-Q>Tb^j)sgl+OjQMYRhMV`YNreI;PM88t~5mP6GH3 zfXAD^{RzNv-vMfgZ;v2f17Ht;Zv*&1Xlpekz+(-p5~9K>GE#?*0r)w9`vLq4z&~PT zh}7Wtu2V~WZUS%xfGeBDl%&}q=Db>#4dUyVQwkpdmgfLG0^p+}a%58whqP5G;E6p5 zte#I*KMUY9F##G9KXaj3Wn^o4K40Jrv1uVjNudxzMjkT+N^j~f~uL-VO~ zLRz;e!S4f@)qkBOOEIPqmTKzoKt~qcr>a{<$~^d?gei|XGq`qPaqX*1KLBvvoFE>1 zb>9~-t8$@&Ixr}!e^&qxcYN(~0J{uA@8xAls=5=vwEzxveB?0z_W*dZuRpEFVK8WX z7I!u-Y+Z){yarT^`OI4Y+zQ~5#xAexha&Q$W{?{+AX=3R>5Hc}!h}XV4B(3` zf4>mG{i?d#nC~x9XE!gPeO30f$3ZgYpxq9Q#dJTiV#fh|qhnsP6Tqdax@ozaVLwlM z0KB|qfhMHGh+@mu`Ea3OnNWeL4ZRKEj~(y5ty$D#stKoaRx-`%p!IJ6H;KsYkp|F^ zb0mmJoK0vWD>Ajx&j5I^x zc&~^&R0=T3QeR+jjsW;u$H;gyfNwJ1=UcO;3tx$qTa{XLs(DSO(i$)({h|kO9szI} znmzw5I!KG=O}hb{+w=Z$5qYj8U`#+UL=%tw&yK^LR@Ez2b!X})$K;S{I$m3<`mLTW zJFTi83mF&HECfs)DJC}3cK|%v^7m~3cLR72v6yDf0GtQl{GRtuHm^yrSkExY?O8x@ zz6;>{9q(NL;A&d5@!i$@yQi^cU3#*4dAH({*)ws2S{R>JZF%KiRrjgtUt11yruq97 zsw%W-qpaC=s`^+@7u}<(7hAFEA>!B#JyGbuVkAuEr)p%7X$|N`A${6RaKwq>5{Jw zy}wUK$XYDB86%E~dCrE%;wlywHGk7{n0olPmB?PD}*vdu-RdV9~;A5hf;%r>3DY7 z+4!n@wyOT2=WD-f?iQ#Hnig1~su!y2Pd7C6mshQ@@4+rLJiYeJiY4=D*IGK_SpdK9 z`P!QS+y>wVtX%P~aBj1#@Ie3t3n|ew&Bq%IBLtt#IY+e6XW!R`tRLvnlq<$}KTtA6oDFz_5Os&%{PQ3gGzx zpF0TPb67mwd#eJQwrtDu(SI}Ms-6IF=alSX?H;np3`7)&`xl^-PGj-B=)2Htm(F?9;9B!+1Nbn2TLA1cVxi5(R&Z#BtjYyGe~4k{J^&8^ z__c`KUBJZuX8^7=Vh33%vTQ|T#h=s;3;`-` z-WEI#w+KvkaMTWv@TcR_WSUaiy%vB<044NA&!EthI#87cP>C5OWIP622=Lhtp^jTC zL{=bKZ?+J{TAst~>RE0hMhzh4w%V0L-)0F-&epH?yAn$1S7F0aB~I2uia*>+rLv9L ami>RG56lgMCO}*O0000vK&AGLy2(^ zgsEan1(Bg_Wtp~;9;jqusM4V@bEf^|RF;q~o_<9L_^D6=eD}UAozwaAJLmg@@V@VJ z@9+NZ^4{k@?}eBsp_RpNEGQI;Rb+%94*q|Me@s*ObsGGi*C~`;k0S-4;sWZUznyDa zUkkmz`0&ho);|9VZx4U&DB^t14_q29NztsTre-*-4+iuFgY*^-PG z+;6rw37$k(oU*d;46_@4*UhVz$$R-n!O5Wh)T5s+(BEHJNnIF!@@e-UQX0n}Hasrm zYqI-~L{2=)^>$S+g|oIjOKf&vUSsG1#mN1saW=MCM62#lcUss6fi| z^VXNOt9lh&4xeB<+AiJ`Cr4=A9bG_cWs7R@@KFI@#(rkI$gB{y>P5uB zdES`)qCzfg(OVJ&NqEDQ3!CufBT0jsp31UG9=^Zs<|-#rUL7{)xHK6k zk_K04f4$O9z;~Ucwg-i3v)OE}qQF%{kM)n&X4~}SPTj8>XNo9 zs+dl3{x4}?=DFNZydwrtYPvh`v?4Kd*v_`E97P=tHR%}Au$>eYDOBaTo@_e~fB>p51QYPXv=tRTZS}T5-yG5_7Hyhx zwD;RIbxASt{$Buz0V}Ge+;ldbBq+^4fPoJWpY|gKF>nb@! zRii9ZQ~=aOig;K~Ua3CFr2;93IDa>3ek@*z{cUB@v)9r8HmR#LpN%%bgvLjf%>K?1;dHD)^|CNJs4K)Bda;M*m2 z)mzSr5WN$$_cwz|ItWJDkHvr>x(b32kVJsJpxFb!Cu00<`%VgwI@%5miiJzI*cl#* zLC69`qHLqU0jRt(#Z>dAikq}Gw;V|Nw4s>}Fyjf>0Tp(@qN@dN``bYJ9WYhzHi{f^ zc_17tBt`e%vbMiWI6$zWqDv%9^>_g0r5@>qK-I44G^e-Hp0&^m!5E(+8r2X%bMnsC;Ogl8Z z^Xwgvvy_{IIVUnUuY&b20LfG%2MsIq_`_BJI0b>VX42vJP}4RZt_HbUf{jc8l73+e zMHaFf^%MXw^#)*pMwoVQI_e?Gyw3Km)gu}#okN&7l3*36sob5Bh#Q9R>uu=0v!%!e z^+-1E;KSrDYqWwDxoHJ5p}&$V1m}MddCj#)DX0Jd3oKWv11`J^)nf+*`euoag=#Q)Z0cTS!*XVY6EY!-5bL7~{JoKT6BwIfv66A|2MPOZ^z2vUsxSh-A{Ps_ z|0{BVVEX@`-2WkRS0E6-jvV&3-~C(A%eE^(EF;U_Y}3W6+*h{4zQ21bPucR5I}yN_ z8bh{KQ)DiNA<~(U3qZWIZJAWYoJ}(GH*+gjOi2;u7r`n_?tV-z27If;$rMSkh9Rf$ zE`&f)kg0Uo&P=ws*$(2@XgUT=pM=+tWCk7lt!<9NAbe{{?e31Pt4YFor-(X{0QS8j znjJGBh`#*C(+>CJibA9V8IJoFli7t z`r>K8QEa9#Xh++>|D z6!2qV6xfum2*6m@D-+f%4Tp4}i4+CRywdn*)TZj%U>IM~6_uT< z`|fT~GelB|WcOwbnJllV_fd{j`CNcnfbmKWL#M4wIDBgDdBb_NBX{L&lvpOvy2rqe zC@alm-88{ghU1;%uI?sj5<~Nmh4G&rGh?{H^K&7z4NZ^kQxD{N61WY)48~w5*voEa zl`c@v+KjJ0uiNLba*&I3sc5MD);{{6WwCi>3Cj>x+xTH(2u^tIswPF*tr=#q|M==5 z-79rQS_Y1pRGd*;Z}pf>TN>Zey~pZ@{qV&OWF`WI(UM6@DY+4*(@aO+@ zw=|Gj7@R@cg3#zqvVxro%nR&dT=_qxM5cbHP_iz7)+rczgF+uv)2A&4?|o!Z%v^5q z*ryYLD|`w}o#2ln^u9;WtRO3xx@@h>UmA3*8|=&yk70OCVI-He z-pXO5>I;KegGWaK-+UX+B*{sM5ilro-&pM|y;^$Uhr(c!Vo7bz_t$ZzE``&=*jG>A zS6@`0DV(mR9Pn7l8~evocl8;VqN(Yj$oK-G|ef9J$5KsG|*M@q)qtFHmOX>+{EHcwaN`vV}hwIP&rA~`nivF}$ zX{A)v+-hV(KHVzUe4#{hW=%k}%R3WKKmnhueWGrp-+uSbdU|c}I9t-?tuO!P_}7p} z+WNuDHE&QjH!MO0Ul{D*fd|0@7;SV3^x32#im^nOtgUrF}ch)m&bKn4ci+YS+KrB03ucqo! z)T_0{3Oet!azbS&6_473d^Lo2xy1QtiaNn-rJA3fb@RXDORtuVXUyerS329W#M$Bo zS3Q+!BZAX^_Qz}9x*S^0!(MoSt&HxvlE`&#bmD_?`fbzYKYpGnTJp=r4+8XEE=@|i z@T@dev7e!*FcseFMzh;)BMAny3f?r+?9jXi4WR-&Qkwf z{qW7nb7s@`E^u6W4H4qxyG3O~bmMEa)rNZ?TfH1t;$@Ji7Z|B`*wAukFSn}(ua@<^ zx)jgnWZi7O)o51CHXJEk>d18?ss#mdp5ISbOE+l6XKH&M60fiRQ{70LHZSHmIxOCk z3%m47>j4Hj#M1Z&7uBr|T0uYpep%r*>0dln^PLsn6`JPq6ZJl`btWt*D!46r3yw=E zZf`V=omj?z84o@}L`M{8;426mLlYbp1r>YQ14*z2_ZA%=o>?hV2~silSgr zSTqsLc~wk}@LVn{rZUs>bJ#W!+IhHOvz=`F2HJYzaLR_mBat^S6^UP;MmFe&++QrO Us`>2_d Date: Mon, 27 Feb 2023 13:49:06 -0800 Subject: [PATCH 1024/1179] Update check-submodules.sh --- release/check-submodules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/check-submodules.sh b/release/check-submodules.sh index 2585db6bd7..5f4e307e49 100755 --- a/release/check-submodules.sh +++ b/release/check-submodules.sh @@ -1,7 +1,7 @@ #!/bin/bash while read hash submodule ref; do - git -C $submodule fetch --depth 300 origin master + git -C $submodule fetch --depth 1000 origin master git -C $submodule branch -r --contains $hash | grep "origin/master" if [ "$?" -eq 0 ]; then echo "$submodule ok" From dc39a87543d61eb5d24ee5f27b661474f7f16598 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Tue, 28 Feb 2023 08:50:32 +0900 Subject: [PATCH 1025/1179] Multilang: kor translation update (#27445) --- selfdrive/ui/translations/main_ko.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 5470e57ce5..be11f2efde 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -403,7 +403,7 @@ location set Waiting for GPS - GPS를 기다리는 중 + GPS 수신중 입니다 @@ -592,16 +592,17 @@ location set Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - + 데이터 파티션을 마운트할 수 없습니다. 파티션이 손상되었을 수 있습니다. 장치를 초기화하려면 확인을 누르세요. Press confirm to erase all content and settings. Press cancel to resume boot. - + 모든 콘텐츠와 설정을 지우려면 확인을 누르세요. 부팅을 재개하려면 취소를 누르세요. Resetting device... This may take up to a minute. - + 장치 초기화 중... +최대 1분이 소요될 수 있습니다. @@ -702,12 +703,12 @@ This may take up to a minute. 다시 시작 - No custom software found at this URL. - + Something went wrong. Reboot the device. + 문제가 발생했습니다. 장치를 재부팅하세요. - Something went wrong. Reboot the device. - + No custom software found at this URL. + 이 URL에서 커스텀 소프트웨어를 찾을 수 없습니다. From ce3e9d5649d930ea0daae2d2a1587cc6e69c158b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 28 Feb 2023 07:51:23 +0800 Subject: [PATCH 1026/1179] cabana: fix gaps in step line between chunks (#27447) --- tools/cabana/chartswidget.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 7982a5899c..42f8e4e06a 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -552,7 +552,12 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even }); for (auto &c : chunks) { s.vals.append(c.vals); - s.step_vals.append(c.step_vals); + if (!c.step_vals.empty()) { + if (!s.step_vals.empty()) { + s.step_vals.append({c.step_vals.first().x(), s.step_vals.back().y()}); + } + s.step_vals.append(c.step_vals); + } } if (events->size()) { s.last_value_mono_time = events->back()->mono_time; From 8d317ef51ce3518e6bd3bb1a97567f8686ca8c8d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 1 Mar 2023 07:50:30 +0800 Subject: [PATCH 1027/1179] cabana: press F11 to toggle fullscreen (#27455) --- tools/cabana/mainwin.cc | 15 +++++++++++++++ tools/cabana/mainwin.h | 1 + 2 files changed, 16 insertions(+) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 282a541244..abcb4948a9 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -194,6 +194,8 @@ void MainWindow::createStatusBar() { void MainWindow::createShortcuts() { auto shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this, nullptr, nullptr, Qt::ApplicationShortcut); QObject::connect(shortcut, &QShortcut::activated, []() { can->pause(!can->isPaused()); }); + shortcut = new QShortcut(QKeySequence(QKeySequence::FullScreen), this, nullptr, nullptr, Qt::ApplicationShortcut); + QObject::connect(shortcut, &QShortcut::activated, this, &MainWindow::toggleFullScreen); // TODO: add more shortcuts here. } @@ -482,6 +484,19 @@ void MainWindow::onlineHelp() { } } +void MainWindow::toggleFullScreen() { + if (isFullScreen()) { + menuBar()->show(); + statusBar()->show(); + showNormal(); + showMaximized(); + } else { + menuBar()->hide(); + statusBar()->hide(); + showFullScreen(); + } +} + // HelpOverlay HelpOverlay::HelpOverlay(MainWindow *parent) : QWidget(parent) { setAttribute(Qt::WA_NoSystemBackground, true); diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 2aeb20aea8..1c21d69370 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -56,6 +56,7 @@ protected: void undoStackCleanChanged(bool clean); void undoStackIndexChanged(int index); void onlineHelp(); + void toggleFullScreen(); void updateStatus(); VideoWidget *video_widget = nullptr; From b6881220426ac231215bbf4476f6fedd11e3e540 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Tue, 28 Feb 2023 21:40:54 -0800 Subject: [PATCH 1028/1179] laikad: reduce min satellite number (#27440) * bump laika * update laikad tests * update refs * bump laika * update refs --------- Co-authored-by: Kurt Nistelberger --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 20 +++++++++++++------- selfdrive/locationd/test/test_laikad.py | 10 +++++----- selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/laika_repo b/laika_repo index 278b44ba8c..b740b71c82 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 278b44ba8c2dec28adc5b30cce13dabc195f15fc +Subproject commit b740b71c82a748e3520b1599487d9a7aaf728670 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2eb1e94526..10c5e1b7e5 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -97,19 +97,25 @@ class Laikad: def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: - min_measurements = 7 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 6 - position_solution, pr_residuals = calc_pos_fix(measurements, self.posfix_functions, min_measurements=min_measurements) + min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 + position_solution, pr_residuals, pos_std = calc_pos_fix(measurements, self.posfix_functions, min_measurements=min_measurements) if len(position_solution) < 3: return None position_estimate = position_solution[:3] - #TODO median abs residual is decent estimate of std, can be improved with measurements stds and/or DOP - position_std = np.median(np.abs(pr_residuals)) * np.ones(3) - velocity_solution, prr_residuals = calc_vel_fix(measurements, position_estimate, self.velfix_function, min_measurements=min_measurements) + + position_std_residual = np.median(np.abs(pr_residuals)) + position_std = np.median(np.abs(pos_std))/10 + position_std = max(position_std_residual, position_std) * np.ones(3) + + velocity_solution, prr_residuals, vel_std = calc_vel_fix(measurements, position_estimate, self.velfix_function, min_measurements=min_measurements) if len(velocity_solution) < 3: return None - velocity_estimate = velocity_solution[:3] - velocity_std = np.median(np.abs(prr_residuals)) * np.ones(3) + + velocity_std_residual = np.median(np.abs(prr_residuals)) + velocity_std = np.median(np.abs(vel_std))/10 + velocity_std = max(velocity_std, velocity_std_residual) * np.ones(3) + return position_estimate, position_std, velocity_estimate, velocity_std def is_good_report(self, gnss_msg): diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index d89f521228..10ac7790b6 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -160,7 +160,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 554 + correct_msgs_expected = 559 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -180,7 +180,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV) # Disable fetch_orbits to test NAV only correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 554 + correct_msgs_expected = 559 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -195,8 +195,8 @@ class TestLaikad(unittest.TestCase): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(0, len(correct_msgs)) - self.assertEqual(0, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(255, len(correct_msgs)) + self.assertEqual(255, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) @@ -282,7 +282,7 @@ class TestLaikad(unittest.TestCase): gm = msg.gnssMeasurements if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: cnt += 1 - self.assertEqual(cnt, 554) + self.assertEqual(cnt, 559) def dict_has_values(self, dct): self.assertGreater(len(dct), 0) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 9991154b9a..b44c9c2f46 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -772f30de36fc7f8421dabb779cc02f45eb83d7bb +dfa8e947c4ef76a9d89974a434e94a078e1ccc6a \ No newline at end of file From 85a37d276c105494b97eee03aa6bb31a212f2f92 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 1 Mar 2023 15:41:28 +0800 Subject: [PATCH 1029/1179] cabana: recalc y-axis label width after unit change (#27466) recalc width --- tools/cabana/chartswidget.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 42f8e4e06a..2c27fbd8b9 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -591,11 +591,14 @@ void ChartView::updateAxisY() { if (it->y() > max) max = it->y(); } } - axis_y->setTitleText(unit); - if (min == std::numeric_limits::max()) min = 0; if (max == std::numeric_limits::lowest()) max = 0; + if (axis_y->titleText() != unit) { + axis_y->setTitleText(unit); + y_label_width = 0;// recalc width + } + double delta = std::abs(max - min) < 1e-3 ? 1 : (max - min) * 0.05; auto [min_y, max_y, tick_count] = getNiceAxisNumbers(min - delta, max + delta, axis_y->tickCount()); if (min_y != axis_y->min() || max_y != axis_y->max() || y_label_width == 0) { From d6abf1d5725e1de58d6f3dc23a238aa4bf65b642 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 1 Mar 2023 13:38:49 -0800 Subject: [PATCH 1030/1179] No disengage on gas by default (#27472) --- selfdrive/manager/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 865966d6c5..963d94066b 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -36,7 +36,7 @@ def manager_init() -> None: default_params: List[Tuple[str, Union[str, bytes]]] = [ ("CompletedTrainingVersion", "0"), - ("DisengageOnAccelerator", "1"), + ("DisengageOnAccelerator", "0"), ("GsmMetered", "1"), ("HasAcceptedTerms", "0"), ("LanguageSetting", "main_en"), From 9ce26b201104afd24fb20baeba22320473afc09d Mon Sep 17 00:00:00 2001 From: Iamz Date: Thu, 2 Mar 2023 06:35:28 +0700 Subject: [PATCH 1031/1179] Add missing Thai translations and remove obsolete messages. (#27469) Update Thai translations --- selfdrive/ui/translations/main_th.ts | 54 +++++++++++----------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index ce394ecb97..45f91f1cdb 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -311,18 +311,6 @@ Installing... กำลังติดตั้ง... - - Receiving objects: - กำลังรับข้อมูล: - - - Resolving deltas: - การแก้ไขเดลต้า: - - - Updating files: - กำลังอัปเดตไฟล์: - MapETA @@ -586,18 +574,10 @@ location set Are you sure you want to reset your device? คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตอุปกรณ์? - - Resetting device... - กำลังรีเซ็ตอุปกรณ์... - System Reset รีเซ็ตระบบ - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - มีการสั่งรีเซ็ตระบบ กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตเข้าระบบตามปกติ - Cancel ยกเลิก @@ -611,8 +591,18 @@ location set ยืนยัน - Unable to mount data partition. Press confirm to reset your device. - ไม่สามารถเมานต์พาร์ติชั่นข้อมูล กดยืนยันเพื่อรีเซ็ตอุปกรณ์ของคุณ + Resetting device... +This may take up to a minute. + กำลังรีเซ็ตอุปกรณ์... +อาจใช้เวลาถึงหนึ่งนาที + + + Press confirm to erase all content and settings. Press cancel to resume boot. + กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตต่อ + + + Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. + ไม่สามารถเมานต์พาร์ติชั่นข้อมูลได้ พาร์ติชั่นอาจเสียหาย กดยืนยันเพื่อลบและรีเซ็ตอุปกรณ์ของคุณ @@ -684,18 +674,6 @@ location set Waiting for internet กำลังรอสัญญาณอินเตอร์เน็ต - - Choose Software to Install - เลือกซอฟต์แวร์ที่จะติดตั้ง - - - Dashcam - กล้องติดรถยนต์ - - - Custom Software - ซอฟต์แวร์ที่กำหนดเอง - Enter URL ป้อน URL @@ -724,6 +702,14 @@ location set Start over เริ่มต้นใหม่ + + Something went wrong. Reboot the device. + มีบางอย่างผิดพลาด รีบูตอุปกรณ์ + + + No custom software found at this URL. + ไม่พบซอฟต์แวร์ที่กำหนดเองที่ URL นี้ + SetupWidget From be42193a618c9133d9a3a3bd4ac33dd19f0209f5 Mon Sep 17 00:00:00 2001 From: koffee-bean <125648286+koffee-bean@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:39:38 -0700 Subject: [PATCH 1032/1179] Hyundai: add missing 2022 Ioniq 5 fwdCamera version (#27471) Co-authored-by: srivastavasid91@gmail.com --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 4b7a295246..d81c98fbcd 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1566,6 +1566,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206', + b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401', ], }, CAR.TUCSON_4TH_GEN: { From 7f10c736ab0e1f027738b5f64ca75308435a3ade Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 1 Mar 2023 15:57:11 -0800 Subject: [PATCH 1033/1179] test_fw_query_on_routes.py: don't print FW for logging --- selfdrive/debug/test_fw_query_on_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/debug/test_fw_query_on_routes.py b/selfdrive/debug/test_fw_query_on_routes.py index ba7d96dba0..dc6688324f 100755 --- a/selfdrive/debug/test_fw_query_on_routes.py +++ b/selfdrive/debug/test_fw_query_on_routes.py @@ -74,7 +74,7 @@ if __name__ == "__main__": elif msg.which() == "carParams": CP = msg.carParams - car_fw = CP.carFw + car_fw = [fw for fw in CP.carFw if not fw.logging] if len(car_fw) == 0: print("no fw") break From d50d8de63787a09b57c294c54b6f88a1236ec2bc Mon Sep 17 00:00:00 2001 From: javenzy <85425378+javenzy@users.noreply.github.com> Date: Thu, 2 Mar 2023 08:00:08 +0800 Subject: [PATCH 1034/1179] Add China HONDA ACCORD HYBRID 2018 finger (#27462) * Add China HONDA ACCORD HYBRID 2018 finger Add finger to support China HONDA ACCORD HYBRID 2018,use ACCORDH model. * remove FW for logging --------- Co-authored-by: Shane Smiskol --- selfdrive/car/honda/values.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index c085c3fe80..0737bea147 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -368,10 +368,12 @@ FW_VERSIONS = { b'57114-TWA-A050\x00\x00', b'57114-TWA-A530\x00\x00', b'57114-TWA-B520\x00\x00', + b'57114-TWB-H030\x00\x00', ], (Ecu.srs, 0x18da53f1, None): [ b'77959-TWA-A440\x00\x00', b'77959-TWA-L420\x00\x00', + b'77959-TWB-H220\x00\x00', ], (Ecu.combinationMeter, 0x18da60f1, None): [ b'78109-TWA-A010\x00\x00', @@ -385,6 +387,7 @@ FW_VERSIONS = { b'78109-TWA-A230\x00\x00', b'78109-TWA-L010\x00\x00', b'78109-TWA-L210\x00\x00', + b'78109-TWA-H210\x00\x00', ], (Ecu.shiftByWire, 0x18da0bf1, None): [ b'54008-TWA-A910\x00\x00', @@ -396,16 +399,19 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x18dab5f1, None): [ b'36161-TWA-A070\x00\x00', b'36161-TWA-A330\x00\x00', + b'36161-TWB-H040\x00\x00', ], (Ecu.fwdRadar, 0x18dab0f1, None): [ b'36802-TWA-A070\x00\x00', b'36802-TWA-A080\x00\x00', b'36802-TWA-A330\x00\x00', + b'36802-TWB-H060\x00\x00', ], (Ecu.eps, 0x18da30f1, None): [ b'39990-TVA-A160\x00\x00', b'39990-TVA-A150\x00\x00', b'39990-TVA-A340\x00\x00', + b'39990-TWB-H120\x00\x00', ], }, CAR.CIVIC: { From e6240d6ba20c187183ac5a26e3135cb5cedaa4c3 Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Thu, 2 Mar 2023 02:01:39 +0200 Subject: [PATCH 1035/1179] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202018=20?= =?UTF-8?q?=C5=A0koda=20Kodiaq=20(#27460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 158a178b03..b23742b50d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1049,6 +1049,7 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027DD\xf1\x893123', b'\xf1\x8704L906026DE\xf1\x895418', + b'\xf1\x8704L906026HT\xf1\x893617', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', ], @@ -1060,17 +1061,20 @@ FW_VERSIONS = { ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655BJ\xf1\x890703\xf1\x82\x0e1213001211001205212111052100', + b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1213001211001244212111442100', b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6050405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6060405', + b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6070405', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G600', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572Q \xf1\x890342', b'\xf1\x872Q0907572R \xf1\x890372', + b'\xf1\x872Q0907572AA\xf1\x890396', ], }, CAR.SKODA_OCTAVIA_MK3: { From 3fbdddb2fb7c79f0c03e5e76edb11f778608e7a5 Mon Sep 17 00:00:00 2001 From: humza2000 <111622889+humza2000@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:10:00 -0800 Subject: [PATCH 1036/1179] Added new transmission firmware for Hyundai Sonata 2022 (#27456) * Added new transmission firmware for Hyundai Sonata 2020-2023 b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02900A1 \xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y', Dongle ID: ba75a2db7d699895 Route: ba75a2db7d699895|2023-02-27--18-07-15 * Update selfdrive/car/hyundai/values.py * we can clean these up --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index d81c98fbcd..cf0143543a 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -512,7 +512,6 @@ FW_VERSIONS = { b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ', b'\xf1\x00DN89110-L0000 \xaa\xaa\xaa\xaa\xaa\xaa\xaa ', b'\xf1\x8799110L0000\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ', - b'\xf1\x8799110L0000\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ', ], (Ecu.abs, 0x7d1, None): [ b'\xf1\x00DN ESC \x07 106 \x07\x01 58910-L0100', @@ -525,7 +524,6 @@ FW_VERSIONS = { b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 104\x19\x08\x01 58910-L0100', b'\xf1\x8758910-L0100\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100', b'\xf1\x8758910-L0100\xf1\x00DN ESC \x07 104\x19\x08\x01 58910-L0100', - b'\xf1\x8758910-L0300\xf1\x00DN ESC \x03 100 \x08\x01 58910-L0300', b'\xf1\x00DN ESC \x06 106 \x07\x01 58910-L0100', ], (Ecu.engine, 0x7e0, None): [ @@ -587,6 +585,7 @@ FW_VERSIONS = { b'\xf1\x00HT6WA280BLHT6WAD10A1SDN8G25NB4\x00\x00\x00\x00\x00\x00g!l[', b'\xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x00T02601BL T02832A1 VDN8T25XXX832NS8G\x0e\xfeE', + b'\xf1\x00T02601BL T02900A1 VDN8T25XXX900NSCF\xe4!Y', b'\xf1\x87954A02N060\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VDN8T25XXX730NS5\xf7_\x92\xf5', b'\xf1\x87SAKFBA2926554GJ2VefVww\x87xwwwww\x88\x87xww\x87wTo\xfb\xffvUo\xff\x8d\x16\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', b'\xf1\x87SAKFBA3030524GJ2UVugww\x97yx\x88\x87\x88vw\x87gww\x87wto\xf9\xfffUo\xff\xa2\x0c\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00SDN8T16NB0z{\xd4v', From 1483fc32dcb0e44d07909562a3d1c10a37b648b8 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 1 Mar 2023 19:49:11 -0500 Subject: [PATCH 1037/1179] VW MQB: Add FW for 2023 Volkswagen Tiguan (#27475) --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index b23742b50d..b53820a32e 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -739,12 +739,14 @@ FW_VERSIONS = { b'\xf1\x8783A907115B \xf1\x890005', b'\xf1\x8783A907115F \xf1\x890002', b'\xf1\x8783A907115G \xf1\x890001', + b'\xf1\x8783A907115K \xf1\x890001', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158DT\xf1\x893698', b'\xf1\x8709G927158FM\xf1\x893757', b'\xf1\x8709G927158GC\xf1\x893821', b'\xf1\x8709G927158GD\xf1\x893820', + b'\xf1\x8709G927158GM\xf1\x893936', b'\xf1\x870D9300043 \xf1\x895202', b'\xf1\x870DL300011N \xf1\x892001', b'\xf1\x870DL300011N \xf1\x892012', @@ -775,6 +777,7 @@ FW_VERSIONS = { b'\xf1\x875QM909144B \xf1\x891081\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\x0521A60604A1', b'\xf1\x875QM909144C \xf1\x891082\xf1\x82\00521A60804A1', + b'\xf1\x875QM907144D \xf1\x891063\xf1\x82\x002SA6092SOM', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572AA\xf1\x890396', From 437ca99fcd5bddfd2f73701d48919ef4afea3ca3 Mon Sep 17 00:00:00 2001 From: Miniz199922 <124948595+Miniz199922@users.noreply.github.com> Date: Wed, 1 Mar 2023 19:56:01 -0500 Subject: [PATCH 1038/1179] Chrysler: Add missing FP for 2020 Jeep Grand Cherokee (#27464) Need to add fingerprint 1538: 8 for my 2020 jeep grand cherokee. Tested and working --- selfdrive/car/chrysler/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 2a5daf440c..2af5246b88 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -135,7 +135,7 @@ FINGERPRINTS = { }], CAR.JEEP_CHEROKEE_2019: [{ # Jeep Grand Cherokee 2019, including most 2020 models - 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 + 55: 8, 168: 8, 179: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 341: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 530: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 640: 1, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 960: 4, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1250: 8, 1251: 8, 1252: 8, 1254: 8, 1264: 8, 1284: 8, 1536: 8, 1537: 8, 1538: 8, 1543: 8, 1545: 8, 1562: 8, 1568: 8, 1570: 8, 1572: 8, 1593: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1890: 8, 1891: 8, 1892: 8, 1894: 8, 1896: 8, 1904: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 }], } From cb2a53ae80ab3917986266290f37ef0228a6ca21 Mon Sep 17 00:00:00 2001 From: Kurt Nistelberger Date: Wed, 1 Mar 2023 19:01:08 -0800 Subject: [PATCH 1039/1179] laikad: fix qcom without internet (#27468) move week Co-authored-by: Kurt Nistelberger --- selfdrive/locationd/laikad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 10c5e1b7e5..2b18dcf152 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -193,10 +193,10 @@ class Laikad: elif self.is_good_report(gnss_msg): week, tow, new_meas = self.read_report(gnss_msg) + self.gps_week = week if len(new_meas) == 0: return None - self.gps_week = week t = gnss_mono_time * 1e-9 if week > 0: self.got_first_gnss_msg = True From afc24f08d66c34ccebf3143e5062390e8529f26f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 2 Mar 2023 13:54:07 +0800 Subject: [PATCH 1040/1179] cabana: fix wrong tooltip (#27480) --- tools/cabana/chartswidget.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 2c27fbd8b9..bd4bf4aba9 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -708,14 +708,16 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (!s.series->isVisible()) continue; // use reverse iterator to find last item <= sec. + double value = 0; auto it = std::lower_bound(s.vals.rbegin(), s.vals.rend(), sec, [](auto &p, double x) { return p.x() > x; }); if (it != s.vals.rend() && it->x() >= axis_x->min()) { + value = it->y(); s.track_pt = chart()->mapToPosition(*it); x = std::max(x, s.track_pt.x()); } text_list.push_back(QString("%2: %3") .arg(s.series->color().name(), s.sig->name, - s.track_pt.isNull() ? "--" : QString::number(s.track_pt.y()))); + s.track_pt.isNull() ? "--" : QString::number(value))); } if (x < 0) { x = ev->pos().x(); @@ -779,7 +781,7 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); qreal track_line_x = -1; for (auto &s : sigs) { - if (!s.track_pt.isNull() && s.series->isVisible()) { + if (!s.track_pt.isNull() && s.series->isVisible()) { painter->setBrush(s.series->color().darker(125)); painter->drawEllipse(s.track_pt, 5.5, 5.5); track_line_x = std::max(track_line_x, s.track_pt.x()); From 9245335e8c0cf4c5371a1afa5a9ff5d4469f8d30 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 2 Mar 2023 16:44:58 -0800 Subject: [PATCH 1041/1179] Car docs: add Toyota Camry 2023 (#27483) * We support 2023 Camry * update docs --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 3bc918f784..20155f306b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -181,7 +181,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry 2018-20|All|Stock|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| -|Toyota|Camry 2021-22|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Toyota|Camry 2021-23|All|openpilot|0 mph[6](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 0639d46ec0..35e2db8b1e 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -115,7 +115,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.AVALONH_TSS2: ToyotaCarInfo("Toyota Avalon Hybrid 2022"), CAR.CAMRY: ToyotaCarInfo("Toyota Camry 2018-20", video_link="https://www.youtube.com/watch?v=fkcjviZY9CM", footnotes=[Footnote.CAMRY]), CAR.CAMRYH: ToyotaCarInfo("Toyota Camry Hybrid 2018-20", video_link="https://www.youtube.com/watch?v=Q2DYY0AWKgk"), - CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-22", footnotes=[Footnote.CAMRY]), + CAR.CAMRY_TSS2: ToyotaCarInfo("Toyota Camry 2021-23", footnotes=[Footnote.CAMRY]), CAR.CAMRYH_TSS2: ToyotaCarInfo("Toyota Camry Hybrid 2021-23"), CAR.CHR: ToyotaCarInfo("Toyota C-HR 2017-20"), CAR.CHR_TSS2: ToyotaCarInfo("Toyota C-HR 2021"), From 3ab8645d3af948a35ac410ad7f841ab670091e32 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 2 Mar 2023 20:11:24 -0800 Subject: [PATCH 1042/1179] uiPlan: add planned acceleration field (#27484) * add accel * bump cereal * Update ref_commit --------- Co-authored-by: Bruce Wayne --- cereal | 2 +- selfdrive/controls/lib/longitudinal_planner.py | 3 ++- selfdrive/controls/plannerd.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index b88523f05a..42f84fd85d 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit b88523f05ac958f87a8f6d57c3f4bb20da55f216 +Subproject commit 42f84fd85d06c0fc85371daa2b4820fca49d763e diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 2ef9051122..e959b14ee3 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -122,8 +122,9 @@ class LongitudinalPlanner: self.mpc.update(sm['radarState'], v_cruise, x, v, a, j) self.v_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.v_solution) + self.a_desired_trajectory_full = np.interp(T_IDXS, T_IDXS_MPC, self.mpc.a_solution) self.v_desired_trajectory = self.v_desired_trajectory_full[:CONTROL_N] - self.a_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC, self.mpc.a_solution) + self.a_desired_trajectory = self.a_desired_trajectory_full[:CONTROL_N] self.j_desired_trajectory = np.interp(T_IDXS[:CONTROL_N], T_IDXS_MPC[:-1], self.mpc.j_solution) # TODO counter is only needed because radar is glitchy, remove once radar is gone diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index 543274d841..d8cf9386d1 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -22,6 +22,7 @@ def publish_ui_plan(sm, pm, lateral_planner, longitudinal_planner): uiPlan.position.x = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,0]).tolist() uiPlan.position.y = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,1]).tolist() uiPlan.position.z = np.interp(plan_odo, model_odo, lateral_planner.path_xyz[:,2]).tolist() + uiPlan.accel = longitudinal_planner.a_desired_trajectory_full.tolist() pm.send('uiPlan', ui_send) def plannerd_thread(sm=None, pm=None): diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index b44c9c2f46..79769e14b6 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -dfa8e947c4ef76a9d89974a434e94a078e1ccc6a \ No newline at end of file +f9c7e05b836c4bff364978752e82d64b90f9d6e6 From 6c4320559a05d6af1ee7b0f4bbebda171b94e20a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 3 Mar 2023 14:30:12 +0800 Subject: [PATCH 1043/1179] replay: fixed the status is always "loading" if there is no carState in events (#27481) --- tools/replay/consoleui.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/replay/consoleui.cc b/tools/replay/consoleui.cc index 5ad702590c..077861ff96 100644 --- a/tools/replay/consoleui.cc +++ b/tools/replay/consoleui.cc @@ -165,7 +165,10 @@ void ConsoleUI::updateStatus() { sm.update(0); if (status != Status::Paused) { - status = (sm.updated("carState") || sm.updated("liveParameters")) ? Status::Playing : Status::Waiting; + auto events = replay->events(); + uint64_t current_mono_time = replay->routeStartTime() + replay->currentSeconds() * 1e9; + bool playing = !events->empty() && events->back()->mono_time > current_mono_time; + status = playing ? Status::Playing : Status::Waiting; } auto [status_str, status_color] = status_text[status]; write_item(0, 0, "STATUS: ", status_str, " ", false, status_color); From a7d9085bca46e83c6b2ea6a64c4bc9d214a0e733 Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Sat, 4 Mar 2023 08:19:36 +0800 Subject: [PATCH 1044/1179] VW MQB: Add FW for 2019 Skoda Superb (#27490) * VW MQB: Add FW for 2019 Skoda Superb 'carVin': 'TMBJD9NP0K7067520', * sort alphabetically --------- Co-authored-by: Cameron Clough --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index b53820a32e..4eef1307be 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1147,6 +1147,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026FP\xf1\x891196', b'\xf1\x8704L906026KB\xf1\x894071', b'\xf1\x8704L906026KD\xf1\x894798', + b'\xf1\x873G0906259 \xf1\x890004', b'\xf1\x873G0906259B \xf1\x890002', b'\xf1\x873G0906264A \xf1\x890002', ], @@ -1156,12 +1157,14 @@ FW_VERSIONS = { b'\xf1\x870D9300012 \xf1\x894940', b'\xf1\x870D9300041H \xf1\x894905', b'\xf1\x870GC300043 \xf1\x892301', + b'\xf1\x870D9300043F \xf1\x895202', ], (Ecu.srs, 0x715, None): [ b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\x12111200111121001121110012211292221111', b'\xf1\x875Q0959655AE\xf1\x890130\xf1\x82\022111200111121001121118112231292221111', b'\xf1\x875Q0959655AK\xf1\x890130\xf1\x82\022111200111121001121110012211292221111', b'\xf1\x875Q0959655BH\xf1\x890336\xf1\x82\02331310031313100313131013141319331413100', + b'\xf1\x875Q0959655CA\xf1\x890403\xf1\x82\x1331310031313100313151013141319331423100', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143K \xf1\x892033\xf1\x820514UZ070203', From f17ac166a325ae1f73778ac45af57fc1b23a1298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 3 Mar 2023 17:48:51 -0800 Subject: [PATCH 1045/1179] Enable dmoji crosshairs in gray when not enabled (#27491) * try * add fade back --------- Co-authored-by: ZwX1616 --- selfdrive/ui/qt/onroad.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 98c636b0a4..dc2f1368ac 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -573,7 +573,10 @@ void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) const int arc_l = 133; const float arc_t_default = 6.7; const float arc_t_extend = 12.0; - QColor arc_color = QColor::fromRgbF(0.09, 0.945, 0.26, 0.4*(1.0-dm_fade_state)*(s->engaged())); + QColor arc_color = QColor::fromRgbF(0.545 - 0.445 * s->engaged(), + 0.545 + 0.4 * s->engaged(), + 0.545 - 0.285 * s->engaged(), + 0.4 * (1.0 - dm_fade_state)); float delta_x = -scene.driver_pose_sins[1] * arc_l / 2; float delta_y = -scene.driver_pose_sins[0] * arc_l / 2; painter.setPen(QPen(arc_color, arc_t_default+arc_t_extend*fmin(1.0, scene.driver_pose_diff[1] * 5.0), Qt::SolidLine, Qt::RoundCap)); From 703f5e34ba783dba5369bf44caa95ed66a07855a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 4 Mar 2023 02:18:03 -0800 Subject: [PATCH 1046/1179] bump panda (#27497) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 1923b14189..e0e754de2c 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 1923b1418933e464ff7460a3e0a05d63aad0d53b +Subproject commit e0e754de2c7fdbf943dd02db203b7bb40bf3e9b5 From 2de085d39d0b9f149526828cd02cc4ccb9122d05 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Mar 2023 07:55:22 +0800 Subject: [PATCH 1047/1179] cabana: faster copy events (#27499) --- tools/cabana/streams/livestream.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index b2fc7ea4a6..8f63d3baec 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -89,10 +89,11 @@ void LiveStream::removeExpiredEvents() { } const std::vector *LiveStream::events() const { - events_vector.clear(); std::lock_guard lk(lock); - events_vector.reserve(can_events.size()); - std::copy(can_events.begin(), can_events.end(), std::back_inserter(events_vector)); + if (events_vector.capacity() <= can_events.size()) { + events_vector.reserve(can_events.size() * 2); + } + events_vector.assign(can_events.begin(), can_events.end()); return &events_vector; } From c2018d6bf291e68102859eb31bb1dd68790172b1 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Mon, 6 Mar 2023 08:03:44 +0800 Subject: [PATCH 1048/1179] cabana: use a segment tree to solve range queries in O(log n) time complexity (#27498) --- tools/cabana/chartswidget.cc | 17 +++++++++++++---- tools/cabana/chartswidget.h | 1 + tools/cabana/util.cc | 34 ++++++++++++++++++++++++++++++++++ tools/cabana/util.h | 13 +++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index bd4bf4aba9..54966be578 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -562,6 +562,9 @@ void ChartView::updateSeries(const Signal *sig, const std::vector *even if (events->size()) { s.last_value_mono_time = events->back()->mono_time; } + if (!can->liveStreaming()) { + s.segment_tree.build(s.vals); + } s.series->replace(series_type == SeriesType::StepLine ? s.step_vals : s.vals); } } @@ -586,9 +589,15 @@ void ChartView::updateAxisY() { auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); - for (auto it = first; it != last; ++it) { - if (it->y() < min) min = it->y(); - if (it->y() > max) max = it->y(); + if (can->liveStreaming()) { + for (auto it = first; it != last; ++it) { + if (it->y() < min) min = it->y(); + if (it->y() > max) max = it->y(); + } + } else { + auto [min_y, max_y] = s.segment_tree.minmax(std::distance(s.vals.begin(), first), std::distance(s.vals.begin(), last)); + min = std::min(min, min_y); + max = std::max(max, max_y); } } if (min == std::numeric_limits::max()) min = 0; @@ -781,7 +790,7 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); qreal track_line_x = -1; for (auto &s : sigs) { - if (!s.track_pt.isNull() && s.series->isVisible()) { + if (!s.track_pt.isNull() && s.series->isVisible()) { painter->setBrush(s.series->color().darker(125)); painter->drawEllipse(s.track_pt, 5.5, 5.5); track_line_x = std::max(track_line_x, s.track_pt.x()); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 76943c1fe9..c86c19a04e 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -46,6 +46,7 @@ public: QVector step_vals; uint64_t last_value_mono_time = 0; QPointF track_pt{}; + SegmentTree segment_tree; }; signals: diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 5e4f505d29..1a0b9d93ef 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -67,6 +67,40 @@ void ChangeTracker::clear() { colors.clear(); } + +// SegmentTree + +void SegmentTree::build(const QVector &arr) { + size = arr.size(); + tree.resize(4 * size); // size of the tree is 4 times the size of the array + if (size > 0) { + build_tree(arr, 1, 0, size - 1); + } +} + +void SegmentTree::build_tree(const QVector &arr, int n, int left, int right) { + if (left == right) { + const double y = arr[left].y(); + tree[n] = {y, y}; + } else { + const int mid = (left + right) >> 1; + build_tree(arr, 2 * n, left, mid); + build_tree(arr, 2 * n + 1, mid + 1, right); + tree[n] = {std::min(tree[2 * n].first, tree[2 * n + 1].first), std::max(tree[2 * n].second, tree[2 * n + 1].second)}; + } +} + +std::pair SegmentTree::get_minmax(int n, int left, int right, int range_left, int range_right) const { + if (range_left > right || range_right < left) + return {std::numeric_limits::max(), std::numeric_limits::lowest()}; + if (range_left <= left && range_right >= right) + return tree[n]; + int mid = (left + right) >> 1; + auto l = get_minmax(2 * n, left, mid, range_left, range_right); + auto r = get_minmax(2 * n + 1, mid + 1, right, range_left, range_right); + return {std::min(l.first, r.first), std::max(l.second, r.second)}; +} + // MessageBytesDelegate MessageBytesDelegate::MessageBytesDelegate(QObject *parent) : QStyledItemDelegate(parent) { diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 5eb5c3c5aa..cf1b5d4b20 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -35,6 +35,19 @@ enum { BytesRole = Qt::UserRole + 2 }; +class SegmentTree { +public: + SegmentTree() = default; + void build(const QVector &arr); + inline std::pair minmax(int left, int right) const { return get_minmax(1, 0, size - 1, left, right); } + +private: + std::pair get_minmax(int n, int left, int right, int range_left, int range_right) const; + void build_tree(const QVector &arr, int n, int left, int right); + std::vector> tree; + int size = 0; +}; + class MessageBytesDelegate : public QStyledItemDelegate { Q_OBJECT public: From fd2e03decf0a89e1c04e0a8d6aee0bf033d2ec0b Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Mon, 6 Mar 2023 02:44:56 +0000 Subject: [PATCH 1049/1179] Ford: add missing Explorer FW (#27502) `1493c38de09a381a|2023-03-05--21-10-07--0` VIN: `1FMSK8FH6LGB17698` --- selfdrive/car/ford/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 3bc56eb9dd..50c7d93987 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -165,6 +165,7 @@ FW_VERSIONS = { b'M1MC-14D003-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x760, None): [ + b'L1MC-2D053-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-BF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'L1MC-2D053-KB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', @@ -178,6 +179,7 @@ FW_VERSIONS = { b'LC5T-14F397-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x7E0, None): [ + b'LB5A-14C204-BUJ\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'LB5A-14C204-EAC\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-MD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'MB5A-14C204-RC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', From e729f5b763a98f4156c1761f1511135cc32121d3 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 6 Mar 2023 15:36:39 -0800 Subject: [PATCH 1050/1179] Remove dashcam override param (#27509) * remove dashcam override * sort * remove ford from segments --- common/params.cc | 1 - selfdrive/controls/controlsd.py | 3 --- selfdrive/test/process_replay/process_replay.py | 3 --- selfdrive/test/process_replay/test_processes.py | 3 +-- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/common/params.cc b/common/params.cc index 2ba4f7e8ab..e74c63bf6a 100644 --- a/common/params.cc +++ b/common/params.cc @@ -99,7 +99,6 @@ std::unordered_map keys = { {"CompletedTrainingVersion", PERSISTENT}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, - {"DashcamOverride", PERSISTENT}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisablePowerDown", PERSISTENT}, {"ExperimentalMode", PERSISTENT}, diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index f49b58212a..1391d6570c 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -112,9 +112,6 @@ class Controls: if not self.disengage_on_accelerator: self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS - if self.CP.dashcamOnly and self.params.get_bool("DashcamOverride"): - self.CP.dashcamOnly = False - # read params self.is_metric = self.params.get_bool("IsMetric") self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled") diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 7dc0b139a3..971ddb3fe2 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -449,9 +449,6 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): if CP.openpilotLongitudinalControl: params.put_bool("ExperimentalLongitudinalEnabled", True) - # controlsd process configuration assume all routes are out of dashcam - params.put_bool("DashcamOverride", True) - def python_replay_process(cfg, lr, fingerprint=None): sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 569090f606..07117c2e7f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -29,12 +29,12 @@ source_segments = [ ("SUBARU", "341dccd5359e3c97|2022-09-12--10-35-33--3"), # SUBARU.OUTBACK ("GM", "0c58b6a25109da2b|2021-02-23--16-35-50--11"), # GM.VOLT ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), # GM.BOLT_EUV - ("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), # FORD.BRONCO_SPORT_MK1 ("NISSAN", "35336926920f3571|2021-02-12--18-38-48--46"), # NISSAN.XTRAIL ("VOLKSWAGEN", "de9592456ad7d144|2021-06-29--11-00-15--6"), # VOLKSWAGEN.GOLF ("MAZDA", "bd6a637565e91581|2021-10-30--15-14-53--4"), # MAZDA.CX9_2021 # Enable when port is tested and dashcamOnly is no longer set + #("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), # FORD.BRONCO_SPORT_MK1 #("TESLA", "bb50caf5f0945ab1|2021-06-19--17-20-18--3"), # TESLA.AP2_MODELS #("VOLKSWAGEN2", "3cfdec54aa035f3f|2022-07-19--23-45-10--2"), # VOLKSWAGEN.PASSAT_NMS ] @@ -53,7 +53,6 @@ segments = [ ("SUBARU", "regen1E72BBDCED5|2022-09-27--15-55-31--0"), ("GM", "regen45B05A80EF6|2022-09-27--15-57-22--0"), ("GM2", "376bf99325883932|2022-10-27--13-41-22--1"), - ("FORD", "54827bf84c38b14f|2023-01-26--21-59-07--4"), ("NISSAN", "regenC19D899B46D|2022-09-27--15-59-13--0"), ("VOLKSWAGEN", "regenD8F7AC4BD0D|2022-09-27--16-41-45--0"), ("MAZDA", "regenFC3F9ECBB64|2022-09-27--16-03-09--0"), From 3892c6098085ad05878f78aef0afefac55e38306 Mon Sep 17 00:00:00 2001 From: George Hotz <72895+geohot@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:50:28 -0800 Subject: [PATCH 1051/1179] tinygrad: bump to 0.5 (#27505) * bump tinygrad to 0.5 * update release files * ref commit + bump tinygrad * save 220 mW --------- Co-authored-by: Comma Device --- release/files_common | 9 +++++---- selfdrive/modeld/SConscript | 2 +- selfdrive/test/process_replay/model_replay_ref_commit | 2 +- system/hardware/tici/test_power_draw.py | 2 +- tinygrad_repo | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/release/files_common b/release/files_common index 5b310d5c80..e0f989e9be 100644 --- a/release/files_common +++ b/release/files_common @@ -577,13 +577,14 @@ opendbc/tesla_can.dbc opendbc/tesla_radar.dbc opendbc/tesla_powertrain.dbc -tinygrad_repo/accel/opencl/* -tinygrad_repo/tinygrad/llops/ops_opencl.py tinygrad_repo/openpilot/compile.py tinygrad_repo/extra/onnx.py +tinygrad_repo/extra/onnx_ops.py tinygrad_repo/extra/thneed.py tinygrad_repo/extra/utils.py -tinygrad_repo/tinygrad/llops/ops_gpu.py -tinygrad_repo/tinygrad/shape/* +tinygrad_repo/tinygrad/codegen/ast.py +tinygrad_repo/tinygrad/codegen/gpu.py tinygrad_repo/tinygrad/nn/* +tinygrad_repo/tinygrad/runtime/ops_gpu.py +tinygrad_repo/tinygrad/shape/* tinygrad_repo/tinygrad/*.py diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 7bbc1b3477..c7e0dc5d86 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -70,7 +70,7 @@ lenv.Program('_dmonitoringmodeld', [ if use_thneed and arch == "larch64" or GetOption('pc_thneed'): fn = File("models/supercombo").abspath - tinygrad_opts = ["NATIVE_EXPLOG=1", "VALIDHACKS=1", "OPTWG=1", "IMAGE=2", "GPU=1", "CLCACHE=0"] + tinygrad_opts = ["NATIVE_EXPLOG=1", "VALIDHACKS=1", "OPTLOCAL=1", "IMAGE=2", "GPU=1", "ENABLE_METHOD_CACHE=1"] if not GetOption('pc_thneed'): # use FLOAT16 on device for speed + don't cache the CL kernels for space tinygrad_opts += ["FLOAT16=1", "PYOPENCL_NO_CACHE=1"] diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index c64f522352..ad09668a46 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -ba947edbb131a2a36ced7c490dfcf3280ad5b167 +ab64afd1abd1059c14f50c67b51e5ef89029f216 diff --git a/system/hardware/tici/test_power_draw.py b/system/hardware/tici/test_power_draw.py index 2460152998..6c3f5747e3 100755 --- a/system/hardware/tici/test_power_draw.py +++ b/system/hardware/tici/test_power_draw.py @@ -20,7 +20,7 @@ class Proc: PROCS = [ Proc('camerad', 2.15), - Proc('modeld', 1.15, atol=0.2), + Proc('modeld', 0.93, atol=0.2), Proc('dmonitoringmodeld', 0.4), Proc('encoderd', 0.23), ] diff --git a/tinygrad_repo b/tinygrad_repo index 2e1d47b166..d8dda2af3a 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit 2e1d47b16625ff343516287cdd9e4bcb26f5c4ef +Subproject commit d8dda2af3afcef0bb772fff580cfa8b3eabf7f69 From ebd25b8a7de29542be7c6a213c578bc363999857 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 6 Mar 2023 16:13:29 -0800 Subject: [PATCH 1052/1179] test_power_draw: add header to output table (#27511) * test_power_draw: add header to output table * units --- poetry.lock | 30 +++++++++++-------------- pyproject.toml | 1 + system/hardware/tici/test_power_draw.py | 10 +++++---- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/poetry.lock b/poetry.lock index 91e1b5c826..ec4022c81f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4355,6 +4355,14 @@ python-versions = "*" [package.dependencies] types-urllib3 = "<1.27" +[[package]] +name = "types-tabulate" +version = "0.9.0.1" +description = "Typing stubs for tabulate" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "types-urllib3" version = "1.26.25.1" @@ -4567,7 +4575,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "9e9495c896e6fd0855803aeaf46513c6c22424b86be820759a8baf27d44e73ee" +content-hash = "669485055bf8d77336509cb7a3878e06aa32431c520825948914d76b57347fde" [metadata.files] adal = [ @@ -6616,7 +6624,6 @@ onnx = [ ] onnx2torch = [ {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, - {file = "onnx2torch-1.5.4.tar.gz", hash = "sha256:df837b557a63540223d85fde4a1d679fde0ca8d8bb89d5379c030b01eddc9c24"}, ] onnxoptimizer = [ {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, @@ -7002,7 +7009,6 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, - {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -7010,14 +7016,12 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, - {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, - {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, @@ -7659,18 +7663,6 @@ setproctitle = [ {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, - {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, - {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, - {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, - {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, - {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, - {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, @@ -8066,6 +8058,10 @@ types-requests = [ {file = "types-requests-2.28.11.2.tar.gz", hash = "sha256:fdcd7bd148139fb8eef72cf4a41ac7273872cad9e6ada14b11ff5dfdeee60ed3"}, {file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"}, ] +types-tabulate = [ + {file = "types-tabulate-0.9.0.1.tar.gz", hash = "sha256:e486292c279f19247865bdabe802419740a0e74b53444e7f7a8009e08129da5d"}, + {file = "types_tabulate-0.9.0.1-py3-none-any.whl", hash = "sha256:be2ea0de05f615ccfcbadf6206aa720e265955eb1de23e343aec9d8bf3fa9aaa"}, +] types-urllib3 = [ {file = "types-urllib3-1.26.25.1.tar.gz", hash = "sha256:a948584944b2412c9a74b9cf64f6c48caf8652cb88b38361316f6d15d8a184cd"}, {file = "types_urllib3-1.26.25.1-py3-none-any.whl", hash = "sha256:f6422596cc9ee5fdf68f9d547f541096a20c2dcfd587e37c804c9ea720bf5cb2"}, diff --git a/pyproject.toml b/pyproject.toml index 6b4b0bb5fa..b1ad273cd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" polyline = "^1.4.0" +types-tabulate = "^0.9.0.1" [tool.poetry.group.dev.dependencies] diff --git a/system/hardware/tici/test_power_draw.py b/system/hardware/tici/test_power_draw.py index 6c3f5747e3..f563933285 100755 --- a/system/hardware/tici/test_power_draw.py +++ b/system/hardware/tici/test_power_draw.py @@ -3,6 +3,7 @@ import unittest import time import math from dataclasses import dataclass +from tabulate import tabulate from system.hardware import HARDWARE, TICI from system.hardware.tici.power_monitor import get_power @@ -58,15 +59,16 @@ class TestPowerDraw(unittest.TestCase): manager_cleanup() - print("-"*35) - print(f"Baseline {baseline:.2f}W\n") + tab = [] + tab.append(['process', 'expected (W)', 'current (W)']) for proc in PROCS: cur = used[proc.name] expected = proc.power - print(f"{proc.name.ljust(20)} {expected:.2f}W {cur:.2f}W") + tab.append([proc.name, round(expected, 2), round(cur, 2)]) with self.subTest(proc=proc.name): self.assertTrue(math.isclose(cur, expected, rel_tol=proc.rtol, abs_tol=proc.atol)) - print("-"*35) + print(tabulate(tab)) + print(f"Baseline {baseline:.2f}W\n") if __name__ == "__main__": From ddcafeb7dcac709dbd517e619fe3807cfc898198 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 8 Mar 2023 02:08:33 +0800 Subject: [PATCH 1053/1179] cabana: improve the performance of updating TreeView in real-time. (#27517) --- tools/cabana/signaledit.cc | 18 ++++++++++++------ tools/cabana/signaledit.h | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index e425a13f82..5684edf95a 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,7 +1,7 @@ #include "tools/cabana/signaledit.h" +#include #include -#include #include #include #include @@ -304,11 +304,17 @@ SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(pa } QSize SignalItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - QSize size = QStyledItemDelegate::sizeHint(option, index); - if (index.column() == 0 && !index.parent().isValid()) { - size.rwidth() = std::min(option.widget->size().width() / 2, size.width() + color_label_width + 8); + int width = option.widget->size().width() / 2; + if (index.column() == 0) { + auto text = index.data(Qt::DisplayRole).toString(); + auto it = width_cache.find(text); + if (it == width_cache.end()) { + int spacing = option.widget->style()->pixelMetric(QStyle::PM_TreeViewIndentation) + color_label_width + 8; + it = width_cache.insert(text, option.fontMetrics.width(text) + spacing); + } + width = std::min(width, it.value()); } - return size; + return {width, QApplication::fontMetrics().height()}; } void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -508,7 +514,7 @@ void SignalView::signalHovered(const Signal *sig) { for (int i = 0; i < children.size(); ++i) { bool highlight = children[i]->sig == sig; if (std::exchange(children[i]->highlight, highlight) != highlight) { - emit model->dataChanged(model->index(i, 0), model->index(i, 0)); + emit model->dataChanged(model->index(i, 0), model->index(i, 0), {Qt::DecorationRole}); } } } diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 73a107f5c9..da3bc36c62 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -85,6 +85,7 @@ public: QValidator *name_validator, *double_validator; QFont small_font; const int color_label_width = 18; + mutable QHash width_cache; }; class SignalView : public QFrame { From 186c48137a8cf94ec28136ca9a6f50d8512c3987 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Tue, 7 Mar 2023 13:39:36 -0500 Subject: [PATCH 1054/1179] =?UTF-8?q?VW=20MQB:=20=C5=A0koda=20Fabia=20Mk4?= =?UTF-8?q?=20(#27520)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VW MQB: Škoda Fabia Mk4 * typo --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + selfdrive/car/volkswagen/interface.py | 4 ++++ selfdrive/car/volkswagen/values.py | 19 +++++++++++++++++++ 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index f71810784a..9cfcbafea1 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,7 @@ Version 0.9.2 (2023-03-XX) ======================== * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. +* Škoda Fabia 2022-23 support thanks to jyoung8607! Version 0.9.1 (2023-02-28) ======================== diff --git a/docs/CARS.md b/docs/CARS.md index 20155f306b..426db94f89 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 237 Supported Cars +# 238 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -161,6 +161,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|| |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| +|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| |Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| |Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 02e37492d3..4ca7c0a16c 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -206,6 +206,7 @@ routes = [ CarTestRoute("0cd0b7f7e31a3853|2021-12-03--03-12-05", VOLKSWAGEN.AUDI_Q3_MK2), CarTestRoute("8f205bdd11bcbb65|2021-03-26--01-00-17", VOLKSWAGEN.SEAT_ATECA_MK1), CarTestRoute("fc6b6c9a3471c846|2021-05-27--13-39-56", VOLKSWAGEN.SEAT_LEON_MK3), + CarTestRoute("0bbe367c98fa1538|2023-03-04--17-46-11", VOLKSWAGEN.SKODA_FABIA_MK4), CarTestRoute("12d6ae3057c04b0d|2021-09-15--00-04-07", VOLKSWAGEN.SKODA_KAMIQ_MK1), CarTestRoute("12d6ae3057c04b0d|2021-09-04--21-21-21", VOLKSWAGEN.SKODA_KAROQ_MK1), CarTestRoute("90434ff5d7c8d603|2021-03-15--12-07-31", VOLKSWAGEN.SKODA_KODIAQ_MK1), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 61243424f0..696d9829d1 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -56,6 +56,7 @@ CADILLAC ATS Premium Performance 2018: CHEVROLET VOLT PREMIER 2017 CHEVROLET MALIBU PREMIER 2017: CHEVROLET VOLT PREMIER 2017 HOLDEN ASTRA RS-V BK 2017: CHEVROLET VOLT PREMIER 2017 +SKODA FABIA 4TH GEN: VOLKSWAGEN GOLF 7TH GEN SKODA OCTAVIA 3RD GEN: SKODA SUPERB 3RD GEN SKODA SCALA 1ST GEN: SKODA SUPERB 3RD GEN SKODA KODIAQ 1ST GEN: SKODA SUPERB 3RD GEN diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 521c68184d..2f8bd8661b 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -187,6 +187,10 @@ class CarInterface(CarInterfaceBase): ret.mass = 1227 + STD_CARGO_KG ret.wheelbase = 2.64 + elif candidate == CAR.SKODA_FABIA_MK4: + ret.mass = 1266 + STD_CARGO_KG + ret.wheelbase = 2.56 + elif candidate == CAR.SKODA_KAMIQ_MK1: ret.mass = 1265 + STD_CARGO_KG ret.wheelbase = 2.66 diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 4eef1307be..c5868e16f3 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -129,6 +129,7 @@ class CAR: AUDI_Q3_MK2 = "AUDI Q3 2ND GEN" # Chassis 8U/F3/FS, Mk2 Audi Q3 and variants SEAT_ATECA_MK1 = "SEAT ATECA 1ST GEN" # Chassis 5F, Mk1 SEAT Ateca and CUPRA Ateca SEAT_LEON_MK3 = "SEAT LEON 3RD GEN" # Chassis 5F, Mk3 SEAT Leon and variants + SKODA_FABIA_MK4 = "SKODA FABIA 4TH GEN" # Chassis PJ, Mk4 Skoda Fabia SKODA_KAMIQ_MK1 = "SKODA KAMIQ 1ST GEN" # Chassis NW, Mk1 Skoda Kamiq SKODA_KAROQ_MK1 = "SKODA KAROQ 1ST GEN" # Chassis NU, Mk1 Skoda Karoq SKODA_KODIAQ_MK1 = "SKODA KODIAQ 1ST GEN" # Chassis NS, Mk1 Skoda Kodiaq @@ -239,6 +240,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.AUDI_Q3_MK2: VWCarInfo("Audi Q3 2019-23"), CAR.SEAT_ATECA_MK1: VWCarInfo("SEAT Ateca 2018"), CAR.SEAT_LEON_MK3: VWCarInfo("SEAT Leon 2014-20"), + CAR.SKODA_FABIA_MK4: VWCarInfo("Škoda Fabia 2022-23", footnotes=[Footnote.VW_MQB_A0]), CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_MQB_A0, Footnote.KAMIQ]), CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21"), CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"), @@ -1009,6 +1011,23 @@ FW_VERSIONS = { b'\xf1\x875Q0907572P \xf1\x890682', ], }, + CAR.SKODA_FABIA_MK4: { + (Ecu.engine, 0x7e0, None): [ + b'\xf1\x8705E906018CF\xf1\x891905', + ], + (Ecu.transmission, 0x7e1, None): [ + b'\xf1\x870CW300051M \xf1\x891936', + ], + (Ecu.srs, 0x715, None): [ + b'\xf1\x875QF959655AT\xf1\x890755\xf1\x82\x1311110011110011111100110200--1111120749', + ], + (Ecu.eps, 0x712, None): [ + b'\xf1\x872Q1909144S \xf1\x896042', + ], + (Ecu.fwdRadar, 0x757, None): [ + b'\xf1\x872Q0907572AA\xf1\x890396', + ], + }, CAR.SKODA_KAMIQ_MK1: { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8705C906032M \xf1\x891333', From f7c15c1708ab0ab42f916162ea26ca52226ce81f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Mar 2023 11:05:20 -0800 Subject: [PATCH 1055/1179] pandad unit tests (#27516) * pandad unit tests * only one * in bootstub * run in jenkins * phone only --- Jenkinsfile | 1 + selfdrive/boardd/tests/test_pandad.py | 48 +++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100755 selfdrive/boardd/tests/test_pandad.py diff --git a/Jenkinsfile b/Jenkinsfile index 30c045e419..0450f33175 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -161,6 +161,7 @@ pipeline { ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], ["test pigeond", "python selfdrive/sensord/tests/test_pigeond.py"], ["test manager", "python selfdrive/manager/test/test_manager.py"], + ["test pandad", "python selfdrive/boardd/tests/test_pandad.py"], ]) } } diff --git a/selfdrive/boardd/tests/test_pandad.py b/selfdrive/boardd/tests/test_pandad.py new file mode 100755 index 0000000000..3b2369b39b --- /dev/null +++ b/selfdrive/boardd/tests/test_pandad.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +import time +import unittest + +import cereal.messaging as messaging +from panda import Panda +from selfdrive.test.helpers import phone_only +from selfdrive.manager.process_config import managed_processes +from system.hardware import HARDWARE + + +class TestPandad(unittest.TestCase): + + def tearDown(self): + managed_processes['pandad'].stop() + + def _wait_for_boardd(self): + sm = messaging.SubMaster(['peripheralState']) + for _ in range(30): + sm.update(1000) + if sm.updated['peripheralState']: + break + + if not sm.updated['peripheralState']: + raise Exception("boardd failed to start") + + @phone_only + def test_in_dfu(self): + HARDWARE.recover_internal_panda() + time.sleep(1) + + managed_processes['pandad'].start() + self._wait_for_boardd() + + @phone_only + def test_in_bootstub(self): + with Panda() as p: + p.reset(enter_bootstub=True) + assert p.bootstub + managed_processes['pandad'].start() + self._wait_for_boardd() + + #def test_out_of_date_fw(self): + # pass + + +if __name__ == "__main__": + unittest.main() From 5326c14b433371861a0014675d833a4d3e6602bc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Mar 2023 16:17:23 -0800 Subject: [PATCH 1056/1179] bump panda (#27510) * bump panda * fix mypy * bump panda --- panda | 2 +- selfdrive/boardd/pandad.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/panda b/panda index e0e754de2c..79210e8c2b 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e0e754de2c7fdbf943dd02db203b7bb40bf3e9b5 +Subproject commit 79210e8c2b8dbddda474cafd68d7ee0c8d0e4a40 diff --git a/selfdrive/boardd/pandad.py b/selfdrive/boardd/pandad.py index f61d9ee1a6..f292b921cf 100755 --- a/selfdrive/boardd/pandad.py +++ b/selfdrive/boardd/pandad.py @@ -84,9 +84,9 @@ def main() -> NoReturn: params.remove("PandaSignatures") # Flash all Pandas in DFU mode - for p in PandaDFU.list(): - cloudlog.info(f"Panda in DFU mode found, flashing recovery {p}") - PandaDFU(p).recover() + for serial in PandaDFU.list(): + cloudlog.info(f"Panda in DFU mode found, flashing recovery {serial}") + PandaDFU(serial).recover() time.sleep(1) panda_serials = Panda.list() From 38eea8948469bcfdb5ea376e6507bc8f0074313c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 7 Mar 2023 20:37:40 -0800 Subject: [PATCH 1057/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index 79210e8c2b..b231281c8b 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 79210e8c2b8dbddda474cafd68d7ee0c8d0e4a40 +Subproject commit b231281c8b2c79c46892576dee4c8a56d5e0b2d2 From ce900f34d08b423e9f3ebed0d028692bb9198dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 7 Mar 2023 20:56:39 -0800 Subject: [PATCH 1058/1179] Ubloxd: subframe 0 is not valid (#27528) No 0 strings --- selfdrive/locationd/ublox_msg.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index b746989466..77ca9099ed 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -183,7 +183,7 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m gps_t subframe(&stream); int subframe_id = subframe.how()->subframe_id(); - if (subframe_id > 3) { + if (subframe_id > 3 || subframe_id < 1) { // dont parse almanac subframes return kj::Array(); } @@ -283,7 +283,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ glonass_t gl_string(&stream); int string_number = gl_string.string_number(); - if (string_number > 5 || gl_string.idle_chip()) { + if (string_number < 1 || string_number > 5 || gl_string.idle_chip()) { // dont parse non immediate data, idle_chip == 0 return kj::Array(); } From 6f40f0d4427f4238c3939a64d1d6baa7d77f1ecc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 8 Mar 2023 10:56:54 -0800 Subject: [PATCH 1059/1179] sensord: move to system/ (#27531) * sensord: move to system/ * add gitignore to releaes files --- .gitignore | 3 --- Jenkinsfile | 6 ++--- SConstruct | 2 +- docs/c_docs.rst | 2 +- release/files_common | 13 ++++++----- release/files_tici | 2 +- selfdrive/locationd/locationd.h | 2 +- selfdrive/manager/process_config.py | 6 ++--- system/sensord/.gitignore | 1 + {selfdrive => system}/sensord/SConscript | 0 {selfdrive => system}/sensord/__init__.py | 0 {selfdrive => system}/sensord/pigeond.py | 0 .../sensord/rawgps/compare.py | 0 .../sensord/rawgps/modemdiag.py | 0 .../sensord/rawgps/rawgpsd.py | 4 ++-- .../sensord/rawgps/structs.py | 0 .../sensord/rawgps/test_rawgps.py | 0 {selfdrive => system}/sensord/sensord | 0 .../sensord/sensors/bmx055_accel.cc | 0 .../sensord/sensors/bmx055_accel.h | 2 +- .../sensord/sensors/bmx055_gyro.cc | 0 .../sensord/sensors/bmx055_gyro.h | 2 +- .../sensord/sensors/bmx055_magn.cc | 0 .../sensord/sensors/bmx055_magn.h | 2 +- .../sensord/sensors/bmx055_temp.cc | 2 +- .../sensord/sensors/bmx055_temp.h | 4 ++-- .../sensord/sensors/constants.h | 0 .../sensord/sensors/file_sensor.cc | 0 .../sensord/sensors/file_sensor.h | 2 +- .../sensord/sensors/i2c_sensor.cc | 0 .../sensord/sensors/i2c_sensor.h | 4 ++-- .../sensord/sensors/light_sensor.cc | 2 +- .../sensord/sensors/light_sensor.h | 0 .../sensord/sensors/lsm6ds3_accel.cc | 0 .../sensord/sensors/lsm6ds3_accel.h | 2 +- .../sensord/sensors/lsm6ds3_gyro.cc | 0 .../sensord/sensors/lsm6ds3_gyro.h | 2 +- .../sensord/sensors/lsm6ds3_temp.cc | 0 .../sensord/sensors/lsm6ds3_temp.h | 2 +- .../sensord/sensors/mmc5603nj_magn.cc | 0 .../sensord/sensors/mmc5603nj_magn.h | 2 +- .../sensord/sensors/sensor.h | 0 .../sensord/sensors_qcom2.cc | 22 +++++++++---------- .../sensord/tests/__init__.py | 0 .../sensord/tests/test_pigeond.py | 0 .../sensord/tests/test_sensord.py | 0 .../sensord/tests/ttff_test.py | 0 tools/gpstest/test_gps.py | 2 +- tools/gpstest/test_laikad.py | 2 +- 49 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 system/sensord/.gitignore rename {selfdrive => system}/sensord/SConscript (100%) rename {selfdrive => system}/sensord/__init__.py (100%) rename {selfdrive => system}/sensord/pigeond.py (100%) rename {selfdrive => system}/sensord/rawgps/compare.py (100%) rename {selfdrive => system}/sensord/rawgps/modemdiag.py (100%) rename {selfdrive => system}/sensord/rawgps/rawgpsd.py (98%) rename {selfdrive => system}/sensord/rawgps/structs.py (100%) rename {selfdrive => system}/sensord/rawgps/test_rawgps.py (100%) rename {selfdrive => system}/sensord/sensord (100%) rename {selfdrive => system}/sensord/sensors/bmx055_accel.cc (100%) rename {selfdrive => system}/sensord/sensors/bmx055_accel.h (96%) rename {selfdrive => system}/sensord/sensors/bmx055_gyro.cc (100%) rename {selfdrive => system}/sensord/sensors/bmx055_gyro.h (95%) rename {selfdrive => system}/sensord/sensors/bmx055_magn.cc (100%) rename {selfdrive => system}/sensord/sensors/bmx055_magn.h (97%) rename {selfdrive => system}/sensord/sensors/bmx055_temp.cc (94%) rename {selfdrive => system}/sensord/sensors/bmx055_temp.h (71%) rename {selfdrive => system}/sensord/sensors/constants.h (100%) rename {selfdrive => system}/sensord/sensors/file_sensor.cc (100%) rename {selfdrive => system}/sensord/sensors/file_sensor.h (88%) rename {selfdrive => system}/sensord/sensors/i2c_sensor.cc (100%) rename {selfdrive => system}/sensord/sensors/i2c_sensor.h (93%) rename {selfdrive => system}/sensord/sensors/light_sensor.cc (92%) rename {selfdrive => system}/sensord/sensors/light_sensor.h (100%) rename {selfdrive => system}/sensord/sensors/lsm6ds3_accel.cc (100%) rename {selfdrive => system}/sensord/sensors/lsm6ds3_accel.h (97%) rename {selfdrive => system}/sensord/sensors/lsm6ds3_gyro.cc (100%) rename {selfdrive => system}/sensord/sensors/lsm6ds3_gyro.h (96%) rename {selfdrive => system}/sensord/sensors/lsm6ds3_temp.cc (100%) rename {selfdrive => system}/sensord/sensors/lsm6ds3_temp.h (92%) rename {selfdrive => system}/sensord/sensors/mmc5603nj_magn.cc (100%) rename {selfdrive => system}/sensord/sensors/mmc5603nj_magn.h (94%) rename {selfdrive => system}/sensord/sensors/sensor.h (100%) rename {selfdrive => system}/sensord/sensors_qcom2.cc (90%) rename {selfdrive => system}/sensord/tests/__init__.py (100%) rename {selfdrive => system}/sensord/tests/test_pigeond.py (100%) rename {selfdrive => system}/sensord/tests/test_sensord.py (100%) rename {selfdrive => system}/sensord/tests/ttff_test.py (100%) diff --git a/.gitignore b/.gitignore index 2b283d3b11..be6629f212 100644 --- a/.gitignore +++ b/.gitignore @@ -46,9 +46,6 @@ selfdrive/mapd/default_speeds_by_region.json system/proclogd/proclogd selfdrive/ui/_ui selfdrive/test/longitudinal_maneuvers/out -selfdrive/visiond/visiond -selfdrive/sensord/_gpsd -selfdrive/sensord/_sensord system/camerad/camerad system/camerad/test/ae_gray_test selfdrive/modeld/_modeld diff --git a/Jenkinsfile b/Jenkinsfile index 0450f33175..2067b9dac1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -159,7 +159,7 @@ pipeline { ["test power draw", "python system/hardware/tici/test_power_draw.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], - ["test pigeond", "python selfdrive/sensord/tests/test_pigeond.py"], + ["test pigeond", "python system/sensord/tests/test_pigeond.py"], ["test manager", "python selfdrive/manager/test/test_manager.py"], ["test pandad", "python selfdrive/boardd/tests/test_pandad.py"], ]) @@ -193,11 +193,11 @@ pipeline { steps { phone_steps("tici-lsmc", [ ["build", "cd selfdrive/manager && ./build.py"], - ["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"], + ["test sensord", "cd system/sensord/tests && python -m unittest test_sensord.py"], ]) phone_steps("tici-bmx-lsm", [ ["build", "cd selfdrive/manager && ./build.py"], - ["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"], + ["test sensord", "cd system/sensord/tests && python -m unittest test_sensord.py"], ]) } } diff --git a/SConstruct b/SConstruct index 007931b7f5..27c811686c 100644 --- a/SConstruct +++ b/SConstruct @@ -427,7 +427,7 @@ SConscript(['selfdrive/boardd/SConscript']) SConscript(['selfdrive/loggerd/SConscript']) SConscript(['selfdrive/locationd/SConscript']) -SConscript(['selfdrive/sensord/SConscript']) +SConscript(['system/sensord/SConscript']) SConscript(['selfdrive/ui/SConscript']) SConscript(['selfdrive/navd/SConscript']) diff --git a/docs/c_docs.rst b/docs/c_docs.rst index 77be7e51d8..5619cc8a51 100644 --- a/docs/c_docs.rst +++ b/docs/c_docs.rst @@ -83,7 +83,7 @@ common sensorsd ^^^^^^^^ .. autodoxygenindex:: - :project: selfdrive_sensord_sensors + :project: system_sensord_sensors boardd ^^^^^^ diff --git a/release/files_common b/release/files_common index e0f989e9be..334e08a322 100644 --- a/release/files_common +++ b/release/files_common @@ -276,12 +276,13 @@ selfdrive/loggerd/uploader.py selfdrive/loggerd/deleter.py selfdrive/loggerd/xattr_cache.py -selfdrive/sensord/SConscript -selfdrive/sensord/sensors_qcom2.cc -selfdrive/sensord/sensors/*.cc -selfdrive/sensord/sensors/*.h -selfdrive/sensord/sensord -selfdrive/sensord/pigeond.py +system/sensord/.gitignore +system/sensord/SConscript +system/sensord/sensors_qcom2.cc +system/sensord/sensors/*.cc +system/sensord/sensors/*.h +system/sensord/sensord +system/sensord/pigeond.py selfdrive/thermald/thermald.py selfdrive/thermald/power_monitoring.py diff --git a/release/files_tici b/release/files_tici index c8abd720d5..b4e0c50516 100644 --- a/release/files_tici +++ b/release/files_tici @@ -13,7 +13,7 @@ system/camerad/cameras/camera_util.cc system/camerad/cameras/camera_util.h system/camerad/cameras/real_debayer.cl -selfdrive/sensord/rawgps/* +system/sensord/rawgps/* selfdrive/ui/qt/spinner_larch64 selfdrive/ui/qt/text_larch64 diff --git a/selfdrive/locationd/locationd.h b/selfdrive/locationd/locationd.h index a292a3c936..b7e42a9df8 100755 --- a/selfdrive/locationd/locationd.h +++ b/selfdrive/locationd/locationd.h @@ -14,7 +14,7 @@ #include "common/timing.h" #include "common/util.h" -#include "selfdrive/sensord/sensors/constants.h" +#include "system/sensord/sensors/constants.h" #define VISION_DECIMATION 2 #define SENSOR_DECIMATION 10 #include "selfdrive/locationd/models/live_kf.h" diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 8fc4d94e55..324063a68b 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -39,7 +39,7 @@ procs = [ NativeProcess("modeld", "selfdrive/modeld", ["./modeld"]), NativeProcess("mapsd", "selfdrive/navd", ["./map_renderer"], enabled=False), NativeProcess("navmodeld", "selfdrive/modeld", ["./navmodeld"], enabled=False), - NativeProcess("sensord", "selfdrive/sensord", ["./sensord"], enabled=not PC), + NativeProcess("sensord", "system/sensord", ["./sensord"], enabled=not PC), NativeProcess("ui", "selfdrive/ui", ["./ui"], offroad=True, watchdog_max_dt=(5 if not PC else None)), NativeProcess("soundd", "selfdrive/ui/soundd", ["./soundd"], offroad=True), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"]), @@ -50,12 +50,12 @@ procs = [ PythonProcess("deleter", "selfdrive.loggerd.deleter", offroad=True), PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=(not PC or WEBCAM), callback=driverview), PythonProcess("laikad", "selfdrive.locationd.laikad"), - PythonProcess("rawgpsd", "selfdrive.sensord.rawgps.rawgpsd", enabled=TICI), + PythonProcess("rawgpsd", "system.sensord.rawgps.rawgpsd", enabled=TICI), PythonProcess("navd", "selfdrive.navd.navd"), PythonProcess("pandad", "selfdrive.boardd.pandad", offroad=True), PythonProcess("paramsd", "selfdrive.locationd.paramsd"), NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=TICI, onroad=False, callback=ublox), - PythonProcess("pigeond", "selfdrive.sensord.pigeond", enabled=TICI, onroad=False, callback=ublox), + PythonProcess("pigeond", "system.sensord.pigeond", enabled=TICI, onroad=False, callback=ublox), PythonProcess("plannerd", "selfdrive.controls.plannerd"), PythonProcess("radard", "selfdrive.controls.radard"), PythonProcess("thermald", "selfdrive.thermald.thermald", offroad=True), diff --git a/system/sensord/.gitignore b/system/sensord/.gitignore new file mode 100644 index 0000000000..e9b8071b4b --- /dev/null +++ b/system/sensord/.gitignore @@ -0,0 +1 @@ +_sensord diff --git a/selfdrive/sensord/SConscript b/system/sensord/SConscript similarity index 100% rename from selfdrive/sensord/SConscript rename to system/sensord/SConscript diff --git a/selfdrive/sensord/__init__.py b/system/sensord/__init__.py similarity index 100% rename from selfdrive/sensord/__init__.py rename to system/sensord/__init__.py diff --git a/selfdrive/sensord/pigeond.py b/system/sensord/pigeond.py similarity index 100% rename from selfdrive/sensord/pigeond.py rename to system/sensord/pigeond.py diff --git a/selfdrive/sensord/rawgps/compare.py b/system/sensord/rawgps/compare.py similarity index 100% rename from selfdrive/sensord/rawgps/compare.py rename to system/sensord/rawgps/compare.py diff --git a/selfdrive/sensord/rawgps/modemdiag.py b/system/sensord/rawgps/modemdiag.py similarity index 100% rename from selfdrive/sensord/rawgps/modemdiag.py rename to system/sensord/rawgps/modemdiag.py diff --git a/selfdrive/sensord/rawgps/rawgpsd.py b/system/sensord/rawgps/rawgpsd.py similarity index 98% rename from selfdrive/sensord/rawgps/rawgpsd.py rename to system/sensord/rawgps/rawgpsd.py index 3fa5e927a2..f75ceee7ed 100755 --- a/selfdrive/sensord/rawgps/rawgpsd.py +++ b/system/sensord/rawgps/rawgpsd.py @@ -15,8 +15,8 @@ from common.gpio import gpio_init, gpio_set from laika.gps_time import GPSTime from system.hardware.tici.pins import GPIO from system.swaglog import cloudlog -from selfdrive.sensord.rawgps.modemdiag import ModemDiag, DIAG_LOG_F, setup_logs, send_recv -from selfdrive.sensord.rawgps.structs import (dict_unpacker, position_report, relist, +from system.sensord.rawgps.modemdiag import ModemDiag, DIAG_LOG_F, setup_logs, send_recv +from system.sensord.rawgps.structs import (dict_unpacker, position_report, relist, gps_measurement_report, gps_measurement_report_sv, glonass_measurement_report, glonass_measurement_report_sv, oemdre_measurement_report, oemdre_measurement_report_sv, oemdre_svpoly_report, diff --git a/selfdrive/sensord/rawgps/structs.py b/system/sensord/rawgps/structs.py similarity index 100% rename from selfdrive/sensord/rawgps/structs.py rename to system/sensord/rawgps/structs.py diff --git a/selfdrive/sensord/rawgps/test_rawgps.py b/system/sensord/rawgps/test_rawgps.py similarity index 100% rename from selfdrive/sensord/rawgps/test_rawgps.py rename to system/sensord/rawgps/test_rawgps.py diff --git a/selfdrive/sensord/sensord b/system/sensord/sensord similarity index 100% rename from selfdrive/sensord/sensord rename to system/sensord/sensord diff --git a/selfdrive/sensord/sensors/bmx055_accel.cc b/system/sensord/sensors/bmx055_accel.cc similarity index 100% rename from selfdrive/sensord/sensors/bmx055_accel.cc rename to system/sensord/sensors/bmx055_accel.cc diff --git a/selfdrive/sensord/sensors/bmx055_accel.h b/system/sensord/sensors/bmx055_accel.h similarity index 96% rename from selfdrive/sensord/sensors/bmx055_accel.h rename to system/sensord/sensors/bmx055_accel.h index 8ef660a99f..2cc316e992 100644 --- a/selfdrive/sensord/sensors/bmx055_accel.h +++ b/system/sensord/sensors/bmx055_accel.h @@ -1,6 +1,6 @@ #pragma once -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define BMX055_ACCEL_I2C_ADDR 0x18 diff --git a/selfdrive/sensord/sensors/bmx055_gyro.cc b/system/sensord/sensors/bmx055_gyro.cc similarity index 100% rename from selfdrive/sensord/sensors/bmx055_gyro.cc rename to system/sensord/sensors/bmx055_gyro.cc diff --git a/selfdrive/sensord/sensors/bmx055_gyro.h b/system/sensord/sensors/bmx055_gyro.h similarity index 95% rename from selfdrive/sensord/sensors/bmx055_gyro.h rename to system/sensord/sensors/bmx055_gyro.h index 80b93f128c..7be3e56563 100644 --- a/selfdrive/sensord/sensors/bmx055_gyro.h +++ b/system/sensord/sensors/bmx055_gyro.h @@ -1,6 +1,6 @@ #pragma once -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define BMX055_GYRO_I2C_ADDR 0x68 diff --git a/selfdrive/sensord/sensors/bmx055_magn.cc b/system/sensord/sensors/bmx055_magn.cc similarity index 100% rename from selfdrive/sensord/sensors/bmx055_magn.cc rename to system/sensord/sensors/bmx055_magn.cc diff --git a/selfdrive/sensord/sensors/bmx055_magn.h b/system/sensord/sensors/bmx055_magn.h similarity index 97% rename from selfdrive/sensord/sensors/bmx055_magn.h rename to system/sensord/sensors/bmx055_magn.h index e4a79bc7e0..15c4e734b9 100644 --- a/selfdrive/sensord/sensors/bmx055_magn.h +++ b/system/sensord/sensors/bmx055_magn.h @@ -1,7 +1,7 @@ #pragma once #include -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define BMX055_MAGN_I2C_ADDR 0x10 diff --git a/selfdrive/sensord/sensors/bmx055_temp.cc b/system/sensord/sensors/bmx055_temp.cc similarity index 94% rename from selfdrive/sensord/sensors/bmx055_temp.cc rename to system/sensord/sensors/bmx055_temp.cc index 95b8068ac1..68ee0da1d6 100644 --- a/selfdrive/sensord/sensors/bmx055_temp.cc +++ b/system/sensord/sensors/bmx055_temp.cc @@ -2,7 +2,7 @@ #include -#include "selfdrive/sensord/sensors/bmx055_accel.h" +#include "system/sensord/sensors/bmx055_accel.h" #include "common/swaglog.h" #include "common/timing.h" diff --git a/selfdrive/sensord/sensors/bmx055_temp.h b/system/sensord/sensors/bmx055_temp.h similarity index 71% rename from selfdrive/sensord/sensors/bmx055_temp.h rename to system/sensord/sensors/bmx055_temp.h index 0b6802deaa..a2eabae395 100644 --- a/selfdrive/sensord/sensors/bmx055_temp.h +++ b/system/sensord/sensors/bmx055_temp.h @@ -1,7 +1,7 @@ #pragma once -#include "selfdrive/sensord/sensors/bmx055_accel.h" -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/bmx055_accel.h" +#include "system/sensord/sensors/i2c_sensor.h" class BMX055_Temp : public I2CSensor { uint8_t get_device_address() {return BMX055_ACCEL_I2C_ADDR;} diff --git a/selfdrive/sensord/sensors/constants.h b/system/sensord/sensors/constants.h similarity index 100% rename from selfdrive/sensord/sensors/constants.h rename to system/sensord/sensors/constants.h diff --git a/selfdrive/sensord/sensors/file_sensor.cc b/system/sensord/sensors/file_sensor.cc similarity index 100% rename from selfdrive/sensord/sensors/file_sensor.cc rename to system/sensord/sensors/file_sensor.cc diff --git a/selfdrive/sensord/sensors/file_sensor.h b/system/sensord/sensors/file_sensor.h similarity index 88% rename from selfdrive/sensord/sensors/file_sensor.h rename to system/sensord/sensors/file_sensor.h index 39d695167d..07d7e8f946 100644 --- a/selfdrive/sensord/sensors/file_sensor.h +++ b/system/sensord/sensors/file_sensor.h @@ -4,7 +4,7 @@ #include #include "cereal/gen/cpp/log.capnp.h" -#include "selfdrive/sensord/sensors/sensor.h" +#include "system/sensord/sensors/sensor.h" class FileSensor : public Sensor { protected: diff --git a/selfdrive/sensord/sensors/i2c_sensor.cc b/system/sensord/sensors/i2c_sensor.cc similarity index 100% rename from selfdrive/sensord/sensors/i2c_sensor.cc rename to system/sensord/sensors/i2c_sensor.cc diff --git a/selfdrive/sensord/sensors/i2c_sensor.h b/system/sensord/sensors/i2c_sensor.h similarity index 93% rename from selfdrive/sensord/sensors/i2c_sensor.h rename to system/sensord/sensors/i2c_sensor.h index 08ca6f09cd..ccac526c12 100644 --- a/selfdrive/sensord/sensors/i2c_sensor.h +++ b/system/sensord/sensors/i2c_sensor.h @@ -8,8 +8,8 @@ #include "common/gpio.h" #include "common/swaglog.h" -#include "selfdrive/sensord/sensors/constants.h" -#include "selfdrive/sensord/sensors/sensor.h" +#include "system/sensord/sensors/constants.h" +#include "system/sensord/sensors/sensor.h" int16_t read_12_bit(uint8_t lsb, uint8_t msb); int16_t read_16_bit(uint8_t lsb, uint8_t msb); diff --git a/selfdrive/sensord/sensors/light_sensor.cc b/system/sensord/sensors/light_sensor.cc similarity index 92% rename from selfdrive/sensord/sensors/light_sensor.cc rename to system/sensord/sensors/light_sensor.cc index 58c602ea39..99e321b47d 100644 --- a/selfdrive/sensord/sensors/light_sensor.cc +++ b/system/sensord/sensors/light_sensor.cc @@ -3,7 +3,7 @@ #include #include "common/timing.h" -#include "selfdrive/sensord/sensors/constants.h" +#include "system/sensord/sensors/constants.h" LightSensor::LightSensor(std::string filename) : FileSensor(filename) {} diff --git a/selfdrive/sensord/sensors/light_sensor.h b/system/sensord/sensors/light_sensor.h similarity index 100% rename from selfdrive/sensord/sensors/light_sensor.h rename to system/sensord/sensors/light_sensor.h diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.cc b/system/sensord/sensors/lsm6ds3_accel.cc similarity index 100% rename from selfdrive/sensord/sensors/lsm6ds3_accel.cc rename to system/sensord/sensors/lsm6ds3_accel.cc diff --git a/selfdrive/sensord/sensors/lsm6ds3_accel.h b/system/sensord/sensors/lsm6ds3_accel.h similarity index 97% rename from selfdrive/sensord/sensors/lsm6ds3_accel.h rename to system/sensord/sensors/lsm6ds3_accel.h index c3f66f5803..69667cb759 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_accel.h +++ b/system/sensord/sensors/lsm6ds3_accel.h @@ -1,6 +1,6 @@ #pragma once -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define LSM6DS3_ACCEL_I2C_ADDR 0x6A diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.cc b/system/sensord/sensors/lsm6ds3_gyro.cc similarity index 100% rename from selfdrive/sensord/sensors/lsm6ds3_gyro.cc rename to system/sensord/sensors/lsm6ds3_gyro.cc diff --git a/selfdrive/sensord/sensors/lsm6ds3_gyro.h b/system/sensord/sensors/lsm6ds3_gyro.h similarity index 96% rename from selfdrive/sensord/sensors/lsm6ds3_gyro.h rename to system/sensord/sensors/lsm6ds3_gyro.h index 220e6b0cec..adaae62dd2 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_gyro.h +++ b/system/sensord/sensors/lsm6ds3_gyro.h @@ -1,6 +1,6 @@ #pragma once -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define LSM6DS3_GYRO_I2C_ADDR 0x6A diff --git a/selfdrive/sensord/sensors/lsm6ds3_temp.cc b/system/sensord/sensors/lsm6ds3_temp.cc similarity index 100% rename from selfdrive/sensord/sensors/lsm6ds3_temp.cc rename to system/sensord/sensors/lsm6ds3_temp.cc diff --git a/selfdrive/sensord/sensors/lsm6ds3_temp.h b/system/sensord/sensors/lsm6ds3_temp.h similarity index 92% rename from selfdrive/sensord/sensors/lsm6ds3_temp.h rename to system/sensord/sensors/lsm6ds3_temp.h index 1d6bcc228a..1b5b621814 100644 --- a/selfdrive/sensord/sensors/lsm6ds3_temp.h +++ b/system/sensord/sensors/lsm6ds3_temp.h @@ -1,6 +1,6 @@ #pragma once -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define LSM6DS3_TEMP_I2C_ADDR 0x6A diff --git a/selfdrive/sensord/sensors/mmc5603nj_magn.cc b/system/sensord/sensors/mmc5603nj_magn.cc similarity index 100% rename from selfdrive/sensord/sensors/mmc5603nj_magn.cc rename to system/sensord/sensors/mmc5603nj_magn.cc diff --git a/selfdrive/sensord/sensors/mmc5603nj_magn.h b/system/sensord/sensors/mmc5603nj_magn.h similarity index 94% rename from selfdrive/sensord/sensors/mmc5603nj_magn.h rename to system/sensord/sensors/mmc5603nj_magn.h index a364c7c37a..fce3f3fecb 100644 --- a/selfdrive/sensord/sensors/mmc5603nj_magn.h +++ b/system/sensord/sensors/mmc5603nj_magn.h @@ -1,6 +1,6 @@ #pragma once -#include "selfdrive/sensord/sensors/i2c_sensor.h" +#include "system/sensord/sensors/i2c_sensor.h" // Address of the chip on the bus #define MMC5603NJ_I2C_ADDR 0x30 diff --git a/selfdrive/sensord/sensors/sensor.h b/system/sensord/sensors/sensor.h similarity index 100% rename from selfdrive/sensord/sensors/sensor.h rename to system/sensord/sensors/sensor.h diff --git a/selfdrive/sensord/sensors_qcom2.cc b/system/sensord/sensors_qcom2.cc similarity index 90% rename from selfdrive/sensord/sensors_qcom2.cc rename to system/sensord/sensors_qcom2.cc index fc8dc8620b..349c67f498 100644 --- a/selfdrive/sensord/sensors_qcom2.cc +++ b/system/sensord/sensors_qcom2.cc @@ -12,17 +12,17 @@ #include "common/swaglog.h" #include "common/timing.h" #include "common/util.h" -#include "selfdrive/sensord/sensors/bmx055_accel.h" -#include "selfdrive/sensord/sensors/bmx055_gyro.h" -#include "selfdrive/sensord/sensors/bmx055_magn.h" -#include "selfdrive/sensord/sensors/bmx055_temp.h" -#include "selfdrive/sensord/sensors/constants.h" -#include "selfdrive/sensord/sensors/light_sensor.h" -#include "selfdrive/sensord/sensors/lsm6ds3_accel.h" -#include "selfdrive/sensord/sensors/lsm6ds3_gyro.h" -#include "selfdrive/sensord/sensors/lsm6ds3_temp.h" -#include "selfdrive/sensord/sensors/mmc5603nj_magn.h" -#include "selfdrive/sensord/sensors/sensor.h" +#include "system/sensord/sensors/bmx055_accel.h" +#include "system/sensord/sensors/bmx055_gyro.h" +#include "system/sensord/sensors/bmx055_magn.h" +#include "system/sensord/sensors/bmx055_temp.h" +#include "system/sensord/sensors/constants.h" +#include "system/sensord/sensors/light_sensor.h" +#include "system/sensord/sensors/lsm6ds3_accel.h" +#include "system/sensord/sensors/lsm6ds3_gyro.h" +#include "system/sensord/sensors/lsm6ds3_temp.h" +#include "system/sensord/sensors/mmc5603nj_magn.h" +#include "system/sensord/sensors/sensor.h" #define I2C_BUS_IMU 1 diff --git a/selfdrive/sensord/tests/__init__.py b/system/sensord/tests/__init__.py similarity index 100% rename from selfdrive/sensord/tests/__init__.py rename to system/sensord/tests/__init__.py diff --git a/selfdrive/sensord/tests/test_pigeond.py b/system/sensord/tests/test_pigeond.py similarity index 100% rename from selfdrive/sensord/tests/test_pigeond.py rename to system/sensord/tests/test_pigeond.py diff --git a/selfdrive/sensord/tests/test_sensord.py b/system/sensord/tests/test_sensord.py similarity index 100% rename from selfdrive/sensord/tests/test_sensord.py rename to system/sensord/tests/test_sensord.py diff --git a/selfdrive/sensord/tests/ttff_test.py b/system/sensord/tests/ttff_test.py similarity index 100% rename from selfdrive/sensord/tests/ttff_test.py rename to system/sensord/tests/ttff_test.py diff --git a/tools/gpstest/test_gps.py b/tools/gpstest/test_gps.py index 8bc5dc89a8..2c08c105a1 100644 --- a/tools/gpstest/test_gps.py +++ b/tools/gpstest/test_gps.py @@ -5,7 +5,7 @@ import struct from common.params import Params import cereal.messaging as messaging -import selfdrive.sensord.pigeond as pd +import system.sensord.pigeond as pd from system.hardware import TICI from selfdrive.test.helpers import with_processes diff --git a/tools/gpstest/test_laikad.py b/tools/gpstest/test_laikad.py index 410a9c70d3..24ffa6c424 100644 --- a/tools/gpstest/test_laikad.py +++ b/tools/gpstest/test_laikad.py @@ -4,7 +4,7 @@ import time import unittest import cereal.messaging as messaging -import selfdrive.sensord.pigeond as pd +import system.sensord.pigeond as pd from common.params import Params from system.hardware import TICI From 94eb2159802d3dba99620db0b08731c68a7e4733 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 8 Mar 2023 11:20:49 -0800 Subject: [PATCH 1060/1179] loggerd: move to system/ (#27534) --- .github/workflows/selfdrive_tests.yaml | 4 +- Jenkinsfile | 4 +- SConstruct | 2 +- docs/overview.rst | 2 +- release/files_common | 42 +++++++++---------- selfdrive/athena/athenad.py | 4 +- selfdrive/manager/manager.py | 2 +- selfdrive/manager/process_config.py | 8 ++-- selfdrive/statsd.py | 2 +- selfdrive/test/test_onroad.py | 2 +- selfdrive/thermald/thermald.py | 2 +- selfdrive/tombstoned.py | 2 +- {selfdrive => system}/loggerd/.gitignore | 0 {selfdrive => system}/loggerd/README.md | 0 {selfdrive => system}/loggerd/SConscript | 0 {selfdrive => system}/loggerd/__init__.py | 0 {selfdrive => system}/loggerd/bootlog.cc | 2 +- {selfdrive => system}/loggerd/config.py | 0 {selfdrive => system}/loggerd/deleter.py | 4 +- .../loggerd/encoder/encoder.cc | 2 +- .../loggerd/encoder/encoder.h | 2 +- .../loggerd/encoder/ffmpeg_encoder.cc | 2 +- .../loggerd/encoder/ffmpeg_encoder.h | 4 +- .../loggerd/encoder/v4l_encoder.cc | 2 +- .../loggerd/encoder/v4l_encoder.h | 2 +- {selfdrive => system}/loggerd/encoderd.cc | 2 +- {selfdrive => system}/loggerd/logger.cc | 2 +- {selfdrive => system}/loggerd/logger.h | 0 {selfdrive => system}/loggerd/loggerd.cc | 4 +- {selfdrive => system}/loggerd/loggerd.h | 8 ++-- .../loggerd/tests/__init__.py | 0 .../loggerd/tests/fill_eon.py | 4 +- .../loggerd/tests/loggerd_tests_common.py | 2 +- .../loggerd/tests/test_deleter.py | 4 +- .../loggerd/tests/test_encoder.py | 2 +- .../loggerd/tests/test_logger.cc | 2 +- .../loggerd/tests/test_loggerd.py | 4 +- .../loggerd/tests/test_runner.cc | 0 .../loggerd/tests/test_uploader.py | 4 +- .../loggerd/tools/mark_all_uploaded.py | 4 +- .../loggerd/tools/mark_unuploaded.py | 2 +- {selfdrive => system}/loggerd/uploader.py | 4 +- {selfdrive => system}/loggerd/video_writer.cc | 2 +- {selfdrive => system}/loggerd/video_writer.h | 0 {selfdrive => system}/loggerd/xattr_cache.py | 0 tools/lib/README.md | 2 +- 46 files changed, 74 insertions(+), 74 deletions(-) rename {selfdrive => system}/loggerd/.gitignore (100%) rename {selfdrive => system}/loggerd/README.md (100%) rename {selfdrive => system}/loggerd/SConscript (100%) rename {selfdrive => system}/loggerd/__init__.py (100%) rename {selfdrive => system}/loggerd/bootlog.cc (97%) rename {selfdrive => system}/loggerd/config.py (100%) rename {selfdrive => system}/loggerd/deleter.py (89%) rename {selfdrive => system}/loggerd/encoder/encoder.cc (98%) rename {selfdrive => system}/loggerd/encoder/encoder.h (97%) rename {selfdrive => system}/loggerd/encoder/ffmpeg_encoder.cc (98%) rename {selfdrive => system}/loggerd/encoder/ffmpeg_encoder.h (92%) rename {selfdrive => system}/loggerd/encoder/v4l_encoder.cc (99%) rename {selfdrive => system}/loggerd/encoder/v4l_encoder.h (95%) rename {selfdrive => system}/loggerd/encoderd.cc (99%) rename {selfdrive => system}/loggerd/logger.cc (99%) rename {selfdrive => system}/loggerd/logger.h (100%) rename {selfdrive => system}/loggerd/loggerd.cc (99%) rename {selfdrive => system}/loggerd/loggerd.h (92%) rename {selfdrive => system}/loggerd/tests/__init__.py (100%) rename {selfdrive => system}/loggerd/tests/fill_eon.py (79%) rename {selfdrive => system}/loggerd/tests/loggerd_tests_common.py (98%) rename {selfdrive => system}/loggerd/tests/test_deleter.py (96%) rename {selfdrive => system}/loggerd/tests/test_encoder.py (99%) rename {selfdrive => system}/loggerd/tests/test_logger.cc (99%) rename {selfdrive => system}/loggerd/tests/test_loggerd.py (99%) rename {selfdrive => system}/loggerd/tests/test_runner.cc (100%) rename {selfdrive => system}/loggerd/tests/test_uploader.py (97%) rename {selfdrive => system}/loggerd/tools/mark_all_uploaded.py (60%) rename {selfdrive => system}/loggerd/tools/mark_unuploaded.py (70%) rename {selfdrive => system}/loggerd/uploader.py (98%) rename {selfdrive => system}/loggerd/video_writer.cc (98%) rename {selfdrive => system}/loggerd/video_writer.h (100%) rename {selfdrive => system}/loggerd/xattr_cache.py (100%) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index efddde720d..fb85a0fbb6 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -204,7 +204,7 @@ jobs: $UNIT_TEST selfdrive/boardd && \ $UNIT_TEST selfdrive/controls && \ $UNIT_TEST selfdrive/monitoring && \ - $UNIT_TEST selfdrive/loggerd && \ + $UNIT_TEST system/loggerd && \ $UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/locationd && \ selfdrive/locationd/test/_test_locationd_lib.py && \ @@ -219,7 +219,7 @@ jobs: ./common/tests/test_util && \ ./common/tests/test_swaglog && \ ./selfdrive/boardd/tests/test_boardd_usbprotocol && \ - ./selfdrive/loggerd/tests/test_logger &&\ + ./system/loggerd/tests/test_logger &&\ ./system/proclogd/tests/test_proclog && \ ./tools/replay/tests/test_replay && \ ./tools/cabana/tests/test_cabana && \ diff --git a/Jenkinsfile b/Jenkinsfile index 2067b9dac1..4e80b5fa3c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -157,8 +157,8 @@ pipeline { phone_steps("tici-common", [ ["build", "cd selfdrive/manager && ./build.py"], ["test power draw", "python system/hardware/tici/test_power_draw.py"], - ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], - ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], + ["test loggerd", "python system/loggerd/tests/test_loggerd.py"], + ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python system/loggerd/tests/test_encoder.py"], ["test pigeond", "python system/sensord/tests/test_pigeond.py"], ["test manager", "python selfdrive/manager/test/test_manager.py"], ["test pandad", "python selfdrive/boardd/tests/test_pandad.py"], diff --git a/SConstruct b/SConstruct index 27c811686c..ba2b377e68 100644 --- a/SConstruct +++ b/SConstruct @@ -424,7 +424,7 @@ SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript']) SConscript(['selfdrive/boardd/SConscript']) -SConscript(['selfdrive/loggerd/SConscript']) +SConscript(['system/loggerd/SConscript']) SConscript(['selfdrive/locationd/SConscript']) SConscript(['system/sensord/SConscript']) diff --git a/docs/overview.rst b/docs/overview.rst index cc4c582155..b9a5700528 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -5,7 +5,7 @@ openpilot :maxdepth: 4 Debugging - selfdrive/loggerd/README.md + system/loggerd/README.md Driver Monitoring Process Replay diff --git a/release/files_common b/release/files_common index 334e08a322..42edaa9b12 100644 --- a/release/files_common +++ b/release/files_common @@ -253,28 +253,28 @@ system/proclogd/main.cc system/proclogd/proclog.cc system/proclogd/proclog.h -selfdrive/loggerd/.gitignore -selfdrive/loggerd/SConscript -selfdrive/loggerd/encoder/encoder.cc -selfdrive/loggerd/encoder/encoder.h -selfdrive/loggerd/encoder/v4l_encoder.cc -selfdrive/loggerd/encoder/v4l_encoder.h -selfdrive/loggerd/video_writer.cc -selfdrive/loggerd/video_writer.h -selfdrive/loggerd/logger.cc -selfdrive/loggerd/logger.h -selfdrive/loggerd/loggerd.cc -selfdrive/loggerd/loggerd.h -selfdrive/loggerd/encoderd.cc -selfdrive/loggerd/bootlog.cc -selfdrive/loggerd/encoder/ffmpeg_encoder.cc -selfdrive/loggerd/encoder/ffmpeg_encoder.h +system/loggerd/.gitignore +system/loggerd/SConscript +system/loggerd/encoder/encoder.cc +system/loggerd/encoder/encoder.h +system/loggerd/encoder/v4l_encoder.cc +system/loggerd/encoder/v4l_encoder.h +system/loggerd/video_writer.cc +system/loggerd/video_writer.h +system/loggerd/logger.cc +system/loggerd/logger.h +system/loggerd/loggerd.cc +system/loggerd/loggerd.h +system/loggerd/encoderd.cc +system/loggerd/bootlog.cc +system/loggerd/encoder/ffmpeg_encoder.cc +system/loggerd/encoder/ffmpeg_encoder.h -selfdrive/loggerd/__init__.py -selfdrive/loggerd/config.py -selfdrive/loggerd/uploader.py -selfdrive/loggerd/deleter.py -selfdrive/loggerd/xattr_cache.py +system/loggerd/__init__.py +system/loggerd/config.py +system/loggerd/uploader.py +system/loggerd/deleter.py +system/loggerd/xattr_cache.py system/sensord/.gitignore system/sensord/SConscript diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index d1cc4cea83..7cb6d5b845 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -36,8 +36,8 @@ from common.file_helpers import CallbackReader from common.params import Params from common.realtime import sec_since_boot, set_core_affinity from system.hardware import HARDWARE, PC, AGNOS -from selfdrive.loggerd.config import ROOT -from selfdrive.loggerd.xattr_cache import getxattr, setxattr +from system.loggerd.config import ROOT +from system.loggerd.xattr_cache import getxattr, setxattr from selfdrive.statsd import STATS_DIR from system.swaglog import SWAGLOG_DIR, cloudlog from system.version import get_commit, get_origin, get_short_branch, get_version diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 963d94066b..1128097251 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -29,7 +29,7 @@ def manager_init() -> None: set_time(cloudlog) # save boot log - subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "selfdrive/loggerd")) + subprocess.call("./bootlog", cwd=os.path.join(BASEDIR, "system/loggerd")) params = Params() params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 324063a68b..7b2b38af3a 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -34,8 +34,8 @@ procs = [ DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"), NativeProcess("dmonitoringmodeld", "selfdrive/modeld", ["./dmonitoringmodeld"], enabled=(not PC or WEBCAM), callback=driverview), - NativeProcess("encoderd", "selfdrive/loggerd", ["./encoderd"]), - NativeProcess("loggerd", "selfdrive/loggerd", ["./loggerd"], onroad=False, callback=logging), + NativeProcess("encoderd", "system/loggerd", ["./encoderd"]), + NativeProcess("loggerd", "system/loggerd", ["./loggerd"], onroad=False, callback=logging), NativeProcess("modeld", "selfdrive/modeld", ["./modeld"]), NativeProcess("mapsd", "selfdrive/navd", ["./map_renderer"], enabled=False), NativeProcess("navmodeld", "selfdrive/modeld", ["./navmodeld"], enabled=False), @@ -47,7 +47,7 @@ procs = [ PythonProcess("calibrationd", "selfdrive.locationd.calibrationd"), PythonProcess("torqued", "selfdrive.locationd.torqued"), PythonProcess("controlsd", "selfdrive.controls.controlsd"), - PythonProcess("deleter", "selfdrive.loggerd.deleter", offroad=True), + PythonProcess("deleter", "system.loggerd.deleter", offroad=True), PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=(not PC or WEBCAM), callback=driverview), PythonProcess("laikad", "selfdrive.locationd.laikad"), PythonProcess("rawgpsd", "system.sensord.rawgps.rawgpsd", enabled=TICI), @@ -61,7 +61,7 @@ procs = [ PythonProcess("thermald", "selfdrive.thermald.thermald", offroad=True), PythonProcess("tombstoned", "selfdrive.tombstoned", enabled=not PC, offroad=True), PythonProcess("updated", "selfdrive.updated", enabled=not PC, onroad=False, offroad=True), - PythonProcess("uploader", "selfdrive.loggerd.uploader", offroad=True), + PythonProcess("uploader", "system.loggerd.uploader", offroad=True), PythonProcess("statsd", "selfdrive.statsd", offroad=True), # debug procs diff --git a/selfdrive/statsd.py b/selfdrive/statsd.py index 7dc002727e..e64907149c 100755 --- a/selfdrive/statsd.py +++ b/selfdrive/statsd.py @@ -13,7 +13,7 @@ from system.swaglog import cloudlog from system.hardware import HARDWARE from common.file_helpers import atomic_write_in_dir from system.version import get_normalized_origin, get_short_branch, get_short_version, is_dirty -from selfdrive.loggerd.config import STATS_DIR, STATS_DIR_FILE_LIMIT, STATS_SOCKET, STATS_FLUSH_TIME_S +from system.loggerd.config import STATS_DIR, STATS_DIR_FILE_LIMIT, STATS_SOCKET, STATS_FLUSH_TIME_S class METRIC_TYPE: diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index 84511771f7..07a3c61bc5 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -15,7 +15,7 @@ from common.basedir import BASEDIR from common.timeout import Timeout from common.params import Params from selfdrive.controls.lib.events import EVENTS, ET -from selfdrive.loggerd.config import ROOT +from system.loggerd.config import ROOT from selfdrive.test.helpers import set_params_enabled, release_only from tools.lib.logreader import LogReader diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index eedeff31f1..531e0b04d1 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -18,7 +18,7 @@ from common.params import Params from common.realtime import DT_TRML, sec_since_boot from selfdrive.controls.lib.alertmanager import set_offroad_alert from system.hardware import HARDWARE, TICI, AGNOS -from selfdrive.loggerd.config import get_available_percent +from system.loggerd.config import get_available_percent from selfdrive.statsd import statlog from system.swaglog import cloudlog from selfdrive.thermald.power_monitoring import PowerMonitoring diff --git a/selfdrive/tombstoned.py b/selfdrive/tombstoned.py index 61a575f141..65fb45b678 100755 --- a/selfdrive/tombstoned.py +++ b/selfdrive/tombstoned.py @@ -10,7 +10,7 @@ import glob from typing import NoReturn from common.file_helpers import mkdirs_exists_ok -from selfdrive.loggerd.config import ROOT +from system.loggerd.config import ROOT import selfdrive.sentry as sentry from system.swaglog import cloudlog from system.version import get_commit diff --git a/selfdrive/loggerd/.gitignore b/system/loggerd/.gitignore similarity index 100% rename from selfdrive/loggerd/.gitignore rename to system/loggerd/.gitignore diff --git a/selfdrive/loggerd/README.md b/system/loggerd/README.md similarity index 100% rename from selfdrive/loggerd/README.md rename to system/loggerd/README.md diff --git a/selfdrive/loggerd/SConscript b/system/loggerd/SConscript similarity index 100% rename from selfdrive/loggerd/SConscript rename to system/loggerd/SConscript diff --git a/selfdrive/loggerd/__init__.py b/system/loggerd/__init__.py similarity index 100% rename from selfdrive/loggerd/__init__.py rename to system/loggerd/__init__.py diff --git a/selfdrive/loggerd/bootlog.cc b/system/loggerd/bootlog.cc similarity index 97% rename from selfdrive/loggerd/bootlog.cc rename to system/loggerd/bootlog.cc index e882e4cf8d..4deb5b41f3 100644 --- a/selfdrive/loggerd/bootlog.cc +++ b/system/loggerd/bootlog.cc @@ -3,7 +3,7 @@ #include "cereal/messaging/messaging.h" #include "common/swaglog.h" -#include "selfdrive/loggerd/logger.h" +#include "system/loggerd/logger.h" static kj::Array build_boot_log() { diff --git a/selfdrive/loggerd/config.py b/system/loggerd/config.py similarity index 100% rename from selfdrive/loggerd/config.py rename to system/loggerd/config.py diff --git a/selfdrive/loggerd/deleter.py b/system/loggerd/deleter.py similarity index 89% rename from selfdrive/loggerd/deleter.py rename to system/loggerd/deleter.py index 5606288024..5fb2b9eb41 100644 --- a/selfdrive/loggerd/deleter.py +++ b/system/loggerd/deleter.py @@ -3,8 +3,8 @@ import os import shutil import threading from system.swaglog import cloudlog -from selfdrive.loggerd.config import ROOT, get_available_bytes, get_available_percent -from selfdrive.loggerd.uploader import listdir_by_creation +from system.loggerd.config import ROOT, get_available_bytes, get_available_percent +from system.loggerd.uploader import listdir_by_creation MIN_BYTES = 5 * 1024 * 1024 * 1024 MIN_PERCENT = 10 diff --git a/selfdrive/loggerd/encoder/encoder.cc b/system/loggerd/encoder/encoder.cc similarity index 98% rename from selfdrive/loggerd/encoder/encoder.cc rename to system/loggerd/encoder/encoder.cc index 943f37803d..08eaf0ff01 100644 --- a/selfdrive/loggerd/encoder/encoder.cc +++ b/system/loggerd/encoder/encoder.cc @@ -1,5 +1,5 @@ #include -#include "selfdrive/loggerd/encoder/encoder.h" +#include "system/loggerd/encoder/encoder.h" VideoEncoder::~VideoEncoder() {} diff --git a/selfdrive/loggerd/encoder/encoder.h b/system/loggerd/encoder/encoder.h similarity index 97% rename from selfdrive/loggerd/encoder/encoder.h rename to system/loggerd/encoder/encoder.h index 21ef65cf12..88dd5cee23 100644 --- a/selfdrive/loggerd/encoder/encoder.h +++ b/system/loggerd/encoder/encoder.h @@ -7,7 +7,7 @@ #include "cereal/messaging/messaging.h" #include "cereal/visionipc/visionipc.h" #include "common/queue.h" -#include "selfdrive/loggerd/video_writer.h" +#include "system/loggerd/video_writer.h" #include "system/camerad/cameras/camera_common.h" #define V4L2_BUF_FLAG_KEYFRAME 8 diff --git a/selfdrive/loggerd/encoder/ffmpeg_encoder.cc b/system/loggerd/encoder/ffmpeg_encoder.cc similarity index 98% rename from selfdrive/loggerd/encoder/ffmpeg_encoder.cc rename to system/loggerd/encoder/ffmpeg_encoder.cc index 5f8d140e8b..275da34f18 100644 --- a/selfdrive/loggerd/encoder/ffmpeg_encoder.cc +++ b/system/loggerd/encoder/ffmpeg_encoder.cc @@ -1,6 +1,6 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" -#include "selfdrive/loggerd/encoder/ffmpeg_encoder.h" +#include "system/loggerd/encoder/ffmpeg_encoder.h" #include #include diff --git a/selfdrive/loggerd/encoder/ffmpeg_encoder.h b/system/loggerd/encoder/ffmpeg_encoder.h similarity index 92% rename from selfdrive/loggerd/encoder/ffmpeg_encoder.h rename to system/loggerd/encoder/ffmpeg_encoder.h index 497a28b651..9095a6e815 100644 --- a/selfdrive/loggerd/encoder/ffmpeg_encoder.h +++ b/system/loggerd/encoder/ffmpeg_encoder.h @@ -11,8 +11,8 @@ extern "C" { #include } -#include "selfdrive/loggerd/encoder/encoder.h" -#include "selfdrive/loggerd/loggerd.h" +#include "system/loggerd/encoder/encoder.h" +#include "system/loggerd/loggerd.h" class FfmpegEncoder : public VideoEncoder { public: diff --git a/selfdrive/loggerd/encoder/v4l_encoder.cc b/system/loggerd/encoder/v4l_encoder.cc similarity index 99% rename from selfdrive/loggerd/encoder/v4l_encoder.cc rename to system/loggerd/encoder/v4l_encoder.cc index 88aeb21256..16e7246ff4 100644 --- a/selfdrive/loggerd/encoder/v4l_encoder.cc +++ b/system/loggerd/encoder/v4l_encoder.cc @@ -2,7 +2,7 @@ #include #include -#include "selfdrive/loggerd/encoder/v4l_encoder.h" +#include "system/loggerd/encoder/v4l_encoder.h" #include "common/util.h" #include "common/timing.h" diff --git a/selfdrive/loggerd/encoder/v4l_encoder.h b/system/loggerd/encoder/v4l_encoder.h similarity index 95% rename from selfdrive/loggerd/encoder/v4l_encoder.h rename to system/loggerd/encoder/v4l_encoder.h index c2a53dd6ef..d4b0a1211d 100644 --- a/selfdrive/loggerd/encoder/v4l_encoder.h +++ b/system/loggerd/encoder/v4l_encoder.h @@ -1,7 +1,7 @@ #pragma once #include "common/queue.h" -#include "selfdrive/loggerd/encoder/encoder.h" +#include "system/loggerd/encoder/encoder.h" #define BUF_IN_COUNT 7 #define BUF_OUT_COUNT 6 diff --git a/selfdrive/loggerd/encoderd.cc b/system/loggerd/encoderd.cc similarity index 99% rename from selfdrive/loggerd/encoderd.cc rename to system/loggerd/encoderd.cc index db5f4b61ab..12b58b6591 100644 --- a/selfdrive/loggerd/encoderd.cc +++ b/system/loggerd/encoderd.cc @@ -1,4 +1,4 @@ -#include "selfdrive/loggerd/loggerd.h" +#include "system/loggerd/loggerd.h" ExitHandler do_exit; diff --git a/selfdrive/loggerd/logger.cc b/system/loggerd/logger.cc similarity index 99% rename from selfdrive/loggerd/logger.cc rename to system/loggerd/logger.cc index aaf267e523..0599aa1e54 100644 --- a/selfdrive/loggerd/logger.cc +++ b/system/loggerd/logger.cc @@ -1,4 +1,4 @@ -#include "selfdrive/loggerd/logger.h" +#include "system/loggerd/logger.h" #include #include diff --git a/selfdrive/loggerd/logger.h b/system/loggerd/logger.h similarity index 100% rename from selfdrive/loggerd/logger.h rename to system/loggerd/logger.h diff --git a/selfdrive/loggerd/loggerd.cc b/system/loggerd/loggerd.cc similarity index 99% rename from selfdrive/loggerd/loggerd.cc rename to system/loggerd/loggerd.cc index e09cdfaa9e..a7f7db4801 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/system/loggerd/loggerd.cc @@ -1,5 +1,5 @@ -#include "selfdrive/loggerd/loggerd.h" -#include "selfdrive/loggerd/video_writer.h" +#include "system/loggerd/loggerd.h" +#include "system/loggerd/video_writer.h" ExitHandler do_exit; diff --git a/selfdrive/loggerd/loggerd.h b/system/loggerd/loggerd.h similarity index 92% rename from selfdrive/loggerd/loggerd.h rename to system/loggerd/loggerd.h index 1fa6349828..1b8f9e0d2a 100644 --- a/selfdrive/loggerd/loggerd.h +++ b/system/loggerd/loggerd.h @@ -23,13 +23,13 @@ #include "common/util.h" #include "system/hardware/hw.h" -#include "selfdrive/loggerd/encoder/encoder.h" -#include "selfdrive/loggerd/logger.h" +#include "system/loggerd/encoder/encoder.h" +#include "system/loggerd/logger.h" #ifdef QCOM2 -#include "selfdrive/loggerd/encoder/v4l_encoder.h" +#include "system/loggerd/encoder/v4l_encoder.h" #define Encoder V4LEncoder #else -#include "selfdrive/loggerd/encoder/ffmpeg_encoder.h" +#include "system/loggerd/encoder/ffmpeg_encoder.h" #define Encoder FfmpegEncoder #endif diff --git a/selfdrive/loggerd/tests/__init__.py b/system/loggerd/tests/__init__.py similarity index 100% rename from selfdrive/loggerd/tests/__init__.py rename to system/loggerd/tests/__init__.py diff --git a/selfdrive/loggerd/tests/fill_eon.py b/system/loggerd/tests/fill_eon.py similarity index 79% rename from selfdrive/loggerd/tests/fill_eon.py rename to system/loggerd/tests/fill_eon.py index b40982fa9f..e0c52ea0d7 100755 --- a/selfdrive/loggerd/tests/fill_eon.py +++ b/system/loggerd/tests/fill_eon.py @@ -3,8 +3,8 @@ import os -from selfdrive.loggerd.config import ROOT, get_available_percent -from selfdrive.loggerd.tests.loggerd_tests_common import create_random_file +from system.loggerd.config import ROOT, get_available_percent +from system.loggerd.tests.loggerd_tests_common import create_random_file if __name__ == "__main__": diff --git a/selfdrive/loggerd/tests/loggerd_tests_common.py b/system/loggerd/tests/loggerd_tests_common.py similarity index 98% rename from selfdrive/loggerd/tests/loggerd_tests_common.py rename to system/loggerd/tests/loggerd_tests_common.py index 80cfb162f1..6aca83858b 100644 --- a/selfdrive/loggerd/tests/loggerd_tests_common.py +++ b/system/loggerd/tests/loggerd_tests_common.py @@ -5,7 +5,7 @@ import random import tempfile import unittest -import selfdrive.loggerd.uploader as uploader +import system.loggerd.uploader as uploader def create_random_file(file_path, size_mb, lock=False): try: diff --git a/selfdrive/loggerd/tests/test_deleter.py b/system/loggerd/tests/test_deleter.py similarity index 96% rename from selfdrive/loggerd/tests/test_deleter.py rename to system/loggerd/tests/test_deleter.py index 80fb5c997f..5b54a43f3b 100755 --- a/selfdrive/loggerd/tests/test_deleter.py +++ b/system/loggerd/tests/test_deleter.py @@ -6,8 +6,8 @@ import unittest from collections import namedtuple from common.timeout import Timeout, TimeoutException -import selfdrive.loggerd.deleter as deleter -from selfdrive.loggerd.tests.loggerd_tests_common import UploaderTestCase +import system.loggerd.deleter as deleter +from system.loggerd.tests.loggerd_tests_common import UploaderTestCase Stats = namedtuple("Stats", ['f_bavail', 'f_blocks', 'f_frsize']) diff --git a/selfdrive/loggerd/tests/test_encoder.py b/system/loggerd/tests/test_encoder.py similarity index 99% rename from selfdrive/loggerd/tests/test_encoder.py rename to system/loggerd/tests/test_encoder.py index 1b9bcef2d7..81f4e9fb9d 100755 --- a/selfdrive/loggerd/tests/test_encoder.py +++ b/system/loggerd/tests/test_encoder.py @@ -14,7 +14,7 @@ from tqdm import trange from common.params import Params from common.timeout import Timeout from system.hardware import TICI -from selfdrive.loggerd.config import ROOT +from system.loggerd.config import ROOT from selfdrive.manager.process_config import managed_processes from tools.lib.logreader import LogReader diff --git a/selfdrive/loggerd/tests/test_logger.cc b/system/loggerd/tests/test_logger.cc similarity index 99% rename from selfdrive/loggerd/tests/test_logger.cc rename to system/loggerd/tests/test_logger.cc index ba7835d632..9c82299091 100644 --- a/selfdrive/loggerd/tests/test_logger.cc +++ b/system/loggerd/tests/test_logger.cc @@ -9,7 +9,7 @@ #include "catch2/catch.hpp" #include "cereal/messaging/messaging.h" #include "common/util.h" -#include "selfdrive/loggerd/logger.h" +#include "system/loggerd/logger.h" #include "tools/replay/util.h" typedef cereal::Sentinel::SentinelType SentinelType; diff --git a/selfdrive/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py similarity index 99% rename from selfdrive/loggerd/tests/test_loggerd.py rename to system/loggerd/tests/test_loggerd.py index 857dc5c4e9..54098d13d0 100755 --- a/selfdrive/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -15,7 +15,7 @@ from cereal.services import service_list from common.basedir import BASEDIR from common.params import Params from common.timeout import Timeout -from selfdrive.loggerd.config import ROOT +from system.loggerd.config import ROOT from selfdrive.manager.process_config import managed_processes from system.version import get_version from tools.lib.logreader import LogReader @@ -51,7 +51,7 @@ class TestLoggerd(unittest.TestCase): def _gen_bootlog(self): with Timeout(5): - out = subprocess.check_output("./bootlog", cwd=os.path.join(BASEDIR, "selfdrive/loggerd"), encoding='utf-8') + out = subprocess.check_output("./bootlog", cwd=os.path.join(BASEDIR, "system/loggerd"), encoding='utf-8') log_fn = self._get_log_fn(out) diff --git a/selfdrive/loggerd/tests/test_runner.cc b/system/loggerd/tests/test_runner.cc similarity index 100% rename from selfdrive/loggerd/tests/test_runner.cc rename to system/loggerd/tests/test_runner.cc diff --git a/selfdrive/loggerd/tests/test_uploader.py b/system/loggerd/tests/test_uploader.py similarity index 97% rename from selfdrive/loggerd/tests/test_uploader.py rename to system/loggerd/tests/test_uploader.py index 6090bbe2aa..11b273cec8 100755 --- a/selfdrive/loggerd/tests/test_uploader.py +++ b/system/loggerd/tests/test_uploader.py @@ -7,9 +7,9 @@ import logging import json from system.swaglog import cloudlog -import selfdrive.loggerd.uploader as uploader +import system.loggerd.uploader as uploader -from selfdrive.loggerd.tests.loggerd_tests_common import UploaderTestCase +from system.loggerd.tests.loggerd_tests_common import UploaderTestCase class TestLogHandler(logging.Handler): diff --git a/selfdrive/loggerd/tools/mark_all_uploaded.py b/system/loggerd/tools/mark_all_uploaded.py similarity index 60% rename from selfdrive/loggerd/tools/mark_all_uploaded.py rename to system/loggerd/tools/mark_all_uploaded.py index e60e6cfa2c..c963014748 100644 --- a/selfdrive/loggerd/tools/mark_all_uploaded.py +++ b/system/loggerd/tools/mark_all_uploaded.py @@ -1,7 +1,7 @@ import os -from selfdrive.loggerd.uploader import UPLOAD_ATTR_NAME, UPLOAD_ATTR_VALUE +from system.loggerd.uploader import UPLOAD_ATTR_NAME, UPLOAD_ATTR_VALUE -from selfdrive.loggerd.config import ROOT +from system.loggerd.config import ROOT for folder in os.walk(ROOT): for file1 in folder[2]: full_path = os.path.join(folder[0], file1) diff --git a/selfdrive/loggerd/tools/mark_unuploaded.py b/system/loggerd/tools/mark_unuploaded.py similarity index 70% rename from selfdrive/loggerd/tools/mark_unuploaded.py rename to system/loggerd/tools/mark_unuploaded.py index 343805d5fc..3d1d4472b0 100755 --- a/selfdrive/loggerd/tools/mark_unuploaded.py +++ b/system/loggerd/tools/mark_unuploaded.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import os import sys -from selfdrive.loggerd.uploader import UPLOAD_ATTR_NAME +from system.loggerd.uploader import UPLOAD_ATTR_NAME for fn in sys.argv[1:]: print(f"unmarking {fn}") diff --git a/selfdrive/loggerd/uploader.py b/system/loggerd/uploader.py similarity index 98% rename from selfdrive/loggerd/uploader.py rename to system/loggerd/uploader.py index f97bafecb9..d4ed6dca28 100644 --- a/selfdrive/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -16,8 +16,8 @@ from common.api import Api from common.params import Params from common.realtime import set_core_affinity from system.hardware import TICI -from selfdrive.loggerd.xattr_cache import getxattr, setxattr -from selfdrive.loggerd.config import ROOT +from system.loggerd.xattr_cache import getxattr, setxattr +from system.loggerd.config import ROOT from system.swaglog import cloudlog NetworkType = log.DeviceState.NetworkType diff --git a/selfdrive/loggerd/video_writer.cc b/system/loggerd/video_writer.cc similarity index 98% rename from selfdrive/loggerd/video_writer.cc rename to system/loggerd/video_writer.cc index 4f79ccafc8..91bf09355f 100644 --- a/selfdrive/loggerd/video_writer.cc +++ b/system/loggerd/video_writer.cc @@ -2,7 +2,7 @@ #include #include -#include "selfdrive/loggerd/video_writer.h" +#include "system/loggerd/video_writer.h" #include "common/swaglog.h" #include "common/util.h" diff --git a/selfdrive/loggerd/video_writer.h b/system/loggerd/video_writer.h similarity index 100% rename from selfdrive/loggerd/video_writer.h rename to system/loggerd/video_writer.h diff --git a/selfdrive/loggerd/xattr_cache.py b/system/loggerd/xattr_cache.py similarity index 100% rename from selfdrive/loggerd/xattr_cache.py rename to system/loggerd/xattr_cache.py diff --git a/tools/lib/README.md b/tools/lib/README.md index 3cf239d2df..d77eef5ac5 100644 --- a/tools/lib/README.md +++ b/tools/lib/README.md @@ -1,6 +1,6 @@ ## LogReader -Route is a class for conveniently accessing all the [logs](/selfdrive/loggerd/) from your routes. The LogReader class reads the non-video logs, i.e. rlog.bz2 and qlog.bz2. There's also a matching FrameReader class for reading the videos. +Route is a class for conveniently accessing all the [logs](/system/loggerd/) from your routes. The LogReader class reads the non-video logs, i.e. rlog.bz2 and qlog.bz2. There's also a matching FrameReader class for reading the videos. ```python from tools.lib.route import Route From 3ff8fc110cbd29f304ed364f4f619afcdf0a729e Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:06:17 -0500 Subject: [PATCH 1061/1179] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202017=20?= =?UTF-8?q?=C5=A0koda=20Kodiaq=20(#27532)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * VW MQB: Add FW for 2017 Škoda Kodiaq * retry CI --- docs/CARS.md | 2 +- selfdrive/car/volkswagen/values.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 426db94f89..070d068cab 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -164,7 +164,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| |Škoda|Kamiq 2021[7](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| |Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| -|Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[10](#footnotes)|| diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index c5868e16f3..8e12923983 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -243,7 +243,7 @@ CAR_INFO: Dict[str, Union[VWCarInfo, List[VWCarInfo]]] = { CAR.SKODA_FABIA_MK4: VWCarInfo("Škoda Fabia 2022-23", footnotes=[Footnote.VW_MQB_A0]), CAR.SKODA_KAMIQ_MK1: VWCarInfo("Škoda Kamiq 2021", footnotes=[Footnote.VW_MQB_A0, Footnote.KAMIQ]), CAR.SKODA_KAROQ_MK1: VWCarInfo("Škoda Karoq 2019-21"), - CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2018-19"), + CAR.SKODA_KODIAQ_MK1: VWCarInfo("Škoda Kodiaq 2017-23"), CAR.SKODA_SCALA_MK1: VWCarInfo("Škoda Scala 2020", footnotes=[Footnote.VW_MQB_A0]), CAR.SKODA_SUPERB_MK3: VWCarInfo("Škoda Superb 2015-22"), CAR.SKODA_OCTAVIA_MK3: [ @@ -1071,17 +1071,20 @@ FW_VERSIONS = { (Ecu.engine, 0x7e0, None): [ b'\xf1\x8704E906027DD\xf1\x893123', b'\xf1\x8704L906026DE\xf1\x895418', + b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026HT\xf1\x893617', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x870D9300043 \xf1\x895202', + b'\xf1\x870DL300011N \xf1\x892014', b'\xf1\x870DL300012M \xf1\x892107', b'\xf1\x870DL300012N \xf1\x892110', b'\xf1\x870DL300013G \xf1\x892119', ], (Ecu.srs, 0x715, None): [ + b'\xf1\x873Q0959655AP\xf1\x890306\xf1\x82\r11110011110011421111314211', b'\xf1\x873Q0959655BJ\xf1\x890703\xf1\x82\x0e1213001211001205212111052100', b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1213001211001244212111442100', b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', @@ -1096,6 +1099,7 @@ FW_VERSIONS = { (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572Q \xf1\x890342', b'\xf1\x872Q0907572R \xf1\x890372', + b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x872Q0907572AA\xf1\x890396', ], }, From 231e9a950dc32b322602815a25486fdc50ec2091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 8 Mar 2023 13:07:33 -0800 Subject: [PATCH 1062/1179] Pigeond: Request sat info msgs (#27529) request sat info msgs --- selfdrive/locationd/test/ublox.py | 1 + selfdrive/locationd/test/ubloxd.py | 1 + selfdrive/locationd/ublox_msg.cc | 3 +++ system/sensord/pigeond.py | 1 + 4 files changed, 6 insertions(+) diff --git a/selfdrive/locationd/test/ublox.py b/selfdrive/locationd/test/ublox.py index 9cffbeac40..80abc64e2c 100644 --- a/selfdrive/locationd/test/ublox.py +++ b/selfdrive/locationd/test/ublox.py @@ -54,6 +54,7 @@ MSG_NAV_DOP = 0x04 MSG_NAV_EKFSTATUS = 0x40 MSG_NAV_SBAS = 0x32 MSG_NAV_SOL = 0x06 +MSG_NAV_SAT = 0x35 # RXM messages MSG_RXM_RAW = 0x15 diff --git a/selfdrive/locationd/test/ubloxd.py b/selfdrive/locationd/test/ubloxd.py index 82aa502ceb..7c7e68b23b 100755 --- a/selfdrive/locationd/test/ubloxd.py +++ b/selfdrive/locationd/test/ubloxd.py @@ -60,6 +60,7 @@ def configure_ublox(dev): dev.configure_message_rate(ublox.CLASS_RXM, ublox.MSG_RXM_SFRBX, 1) dev.configure_message_rate(ublox.CLASS_MON, ublox.MSG_MON_HW, 1) dev.configure_message_rate(ublox.CLASS_MON, ublox.MSG_MON_HW2, 1) + dev.configure_message_rate(ublox.CLASS_NAV, ublox.MSG_NAV_SAT, 1) # Query the backup restore status print("backup restore polling message (implement custom response handler!):") diff --git a/selfdrive/locationd/ublox_msg.cc b/selfdrive/locationd/ublox_msg.cc index 77ca9099ed..ebd904f72f 100644 --- a/selfdrive/locationd/ublox_msg.cc +++ b/selfdrive/locationd/ublox_msg.cc @@ -126,6 +126,9 @@ std::pair> UbloxMsgParser::gen_msg() { return {"ubloxGnss", gen_mon_hw(static_cast(body))}; case 0x0a0b: return {"ubloxGnss", gen_mon_hw2(static_cast(body))}; + case 0x0135: + // TODO return {"ubloxGnss", gen_nav_sat(static_cast(body))}; + return {"ubloxGnss", kj::Array()}; default: LOGE("Unknown message type %x", ubx_message.msg_type()); return {"ubloxGnss", kj::Array()}; diff --git a/system/sensord/pigeond.py b/system/sensord/pigeond.py index 9d0a62bd3b..c9ad7ff22a 100755 --- a/system/sensord/pigeond.py +++ b/system/sensord/pigeond.py @@ -183,6 +183,7 @@ def initialize_pigeon(pigeon: TTYPigeon) -> bool: pigeon.send_with_ack(b"\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C") pigeon.send_with_ack(b"\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70") pigeon.send_with_ack(b"\xB5\x62\x06\x01\x03\x00\x0A\x0B\x01\x20\x74") + pigeon.send_with_ack(b"\xB5\x62\x06\x01\x03\x00\x01\x35\x01\x41\xAD") cloudlog.debug("pigeon configured") # try restoring almanac backup From c97911dbad15c3cc7dc577b305ab9aed775e021f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 8 Mar 2023 16:11:18 -0800 Subject: [PATCH 1063/1179] ubloxd: move to system/ (#27536) * ubloxd: move to system/ * more fixes * add missing sconscript * fix valgrind tests * uncomment --- .github/workflows/selfdrive_tests.yaml | 3 ++- SConstruct | 1 + release/files_common | 15 ++++++------- selfdrive/locationd/.gitignore | 3 --- selfdrive/locationd/SConscript | 21 ++----------------- selfdrive/manager/process_config.py | 2 +- selfdrive/test/test_valgrind_replay.py | 2 +- system/ubloxd/.gitignore | 2 ++ system/ubloxd/SConscript | 20 ++++++++++++++++++ .../ubloxd}/generated/glonass.cpp | 0 .../ubloxd}/generated/glonass.h | 0 .../ubloxd}/generated/gps.cpp | 0 .../ubloxd}/generated/gps.h | 0 .../ubloxd}/generated/ubx.cpp | 0 .../ubloxd}/generated/ubx.h | 0 .../locationd => system/ubloxd}/glonass.ksy | 0 .../ubloxd}/glonass_fix.patch | 6 +++--- .../locationd => system/ubloxd}/gps.ksy | 0 .../ubloxd/tests}/print_gps_stats.py | 0 .../ubloxd/tests}/test_glonass_kaitai.cc | 2 +- .../ubloxd/tests}/test_glonass_runner.cc | 0 .../ubloxd/tests}/test_ublox_processing.py | 0 .../test => system/ubloxd/tests}/ublox.py | 0 .../test => system/ubloxd/tests}/ubloxd.py | 0 .../locationd => system/ubloxd}/ublox_msg.cc | 0 .../locationd => system/ubloxd}/ublox_msg.h | 6 +++--- .../locationd => system/ubloxd}/ubloxd.cc | 2 +- .../locationd => system/ubloxd}/ubx.ksy | 0 28 files changed, 45 insertions(+), 40 deletions(-) create mode 100644 system/ubloxd/.gitignore create mode 100644 system/ubloxd/SConscript rename {selfdrive/locationd => system/ubloxd}/generated/glonass.cpp (100%) rename {selfdrive/locationd => system/ubloxd}/generated/glonass.h (100%) rename {selfdrive/locationd => system/ubloxd}/generated/gps.cpp (100%) rename {selfdrive/locationd => system/ubloxd}/generated/gps.h (100%) rename {selfdrive/locationd => system/ubloxd}/generated/ubx.cpp (100%) rename {selfdrive/locationd => system/ubloxd}/generated/ubx.h (100%) rename {selfdrive/locationd => system/ubloxd}/glonass.ksy (100%) rename {selfdrive/locationd => system/ubloxd}/glonass_fix.patch (68%) rename {selfdrive/locationd => system/ubloxd}/gps.ksy (100%) rename {selfdrive/locationd/test => system/ubloxd/tests}/print_gps_stats.py (100%) rename {selfdrive/locationd/test => system/ubloxd/tests}/test_glonass_kaitai.cc (99%) rename {selfdrive/locationd/test => system/ubloxd/tests}/test_glonass_runner.cc (100%) rename {selfdrive/locationd/test => system/ubloxd/tests}/test_ublox_processing.py (100%) rename {selfdrive/locationd/test => system/ubloxd/tests}/ublox.py (100%) rename {selfdrive/locationd/test => system/ubloxd/tests}/ubloxd.py (100%) rename {selfdrive/locationd => system/ubloxd}/ublox_msg.cc (100%) rename {selfdrive/locationd => system/ubloxd}/ublox_msg.h (96%) rename {selfdrive/locationd => system/ubloxd}/ubloxd.cc (97%) rename {selfdrive/locationd => system/ubloxd}/ubx.ksy (100%) diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index fb85a0fbb6..5873e7aee6 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -207,8 +207,9 @@ jobs: $UNIT_TEST system/loggerd && \ $UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/locationd && \ + $UNIT_TEST system/ubloxd && \ selfdrive/locationd/test/_test_locationd_lib.py && \ - ./selfdrive/locationd/test/test_glonass_runner && \ + ./system/ubloxd/tests/test_glonass_runner && \ $UNIT_TEST selfdrive/athena && \ $UNIT_TEST selfdrive/thermald && \ $UNIT_TEST system/hardware/tici && \ diff --git a/SConstruct b/SConstruct index ba2b377e68..387d2e76f4 100644 --- a/SConstruct +++ b/SConstruct @@ -398,6 +398,7 @@ SConscript([ 'system/camerad/SConscript', 'system/clocksd/SConscript', 'system/proclogd/SConscript', + 'system/ubloxd/SConscript', ]) if arch != "Darwin": SConscript(['system/logcatd/SConscript']) diff --git a/release/files_common b/release/files_common index 42edaa9b12..a20f71018b 100644 --- a/release/files_common +++ b/release/files_common @@ -219,14 +219,15 @@ system/hardware/pc/__init__.py system/hardware/pc/hardware.h system/hardware/pc/hardware.py -selfdrive/locationd/__init__.py -selfdrive/locationd/.gitignore -selfdrive/locationd/SConscript -selfdrive/locationd/ubloxd.cc -selfdrive/locationd/ublox_msg.cc -selfdrive/locationd/ublox_msg.h -selfdrive/locationd/generated/* +system/ubloxd/.gitignore +system/ubloxd/SConscript +system/ubloxd/generated/* +system/ubloxd/*.h +system/ubloxd/*.cc +selfdrive/locationd/__init__.py +selfdrive/locationd/SConscript +selfdrive/locationd/.gitignore selfdrive/locationd/laikad.py selfdrive/locationd/locationd.h selfdrive/locationd/locationd.cc diff --git a/selfdrive/locationd/.gitignore b/selfdrive/locationd/.gitignore index 86a228a6ff..11b9f127b2 100644 --- a/selfdrive/locationd/.gitignore +++ b/selfdrive/locationd/.gitignore @@ -1,6 +1,3 @@ -ubloxd -ubloxd_test params_learner paramsd locationd -test/test_glonass_runner diff --git a/selfdrive/locationd/SConscript b/selfdrive/locationd/SConscript index 61a0ed7f42..740f827a49 100644 --- a/selfdrive/locationd/SConscript +++ b/selfdrive/locationd/SConscript @@ -1,20 +1,6 @@ Import('env', 'common', 'cereal', 'messaging', 'libkf', 'transformations') -loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'kaitai', 'pthread'] - -if GetOption('kaitai'): - generated = Dir('generated').srcnode().abspath - cmd = f"kaitai-struct-compiler --target cpp_stl --outdir {generated} $SOURCES" - env.Command(['generated/ubx.cpp', 'generated/ubx.h'], 'ubx.ksy', cmd) - env.Command(['generated/gps.cpp', 'generated/gps.h'], 'gps.ksy', cmd) - glonass = env.Command(['generated/glonass.cpp', 'generated/glonass.h'], 'glonass.ksy', cmd) - - # kaitai issue: https://github.com/kaitai-io/kaitai_struct/issues/910 - patch = env.Command(None, 'glonass_fix.patch', 'git apply $SOURCES') - env.Depends(patch, glonass) - -glonass_obj = env.Object('generated/glonass.cpp') -env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "generated/ubx.cpp", "generated/gps.cpp", glonass_obj], LIBS=loc_libs) +loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'pthread'] ekf_sym_cc = env.SharedObject("#rednose/helpers/ekf_sym.cc") locationd_sources = ["locationd.cc", "models/live_kf.cc", ekf_sym_cc] @@ -25,7 +11,4 @@ lenv.Depends(locationd, libkf) if File("liblocationd.cc").exists(): liblocationd = lenv.SharedLibrary("liblocationd", ["liblocationd.cc"] + locationd_sources, LIBS=loc_libs + transformations) - lenv.Depends(liblocationd, libkf) - -if GetOption('test'): - env.Program("test/test_glonass_runner", ['test/test_glonass_runner.cc', 'test/test_glonass_kaitai.cc', glonass_obj], LIBS=[loc_libs]) \ No newline at end of file + lenv.Depends(liblocationd, libkf) \ No newline at end of file diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 7b2b38af3a..2bacd951a7 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -54,7 +54,7 @@ procs = [ PythonProcess("navd", "selfdrive.navd.navd"), PythonProcess("pandad", "selfdrive.boardd.pandad", offroad=True), PythonProcess("paramsd", "selfdrive.locationd.paramsd"), - NativeProcess("ubloxd", "selfdrive/locationd", ["./ubloxd"], enabled=TICI, onroad=False, callback=ublox), + NativeProcess("ubloxd", "system/ubloxd", ["./ubloxd"], enabled=TICI, onroad=False, callback=ublox), PythonProcess("pigeond", "system.sensord.pigeond", enabled=TICI, onroad=False, callback=ublox), PythonProcess("plannerd", "selfdrive.controls.plannerd"), PythonProcess("radard", "selfdrive.controls.radard"), diff --git a/selfdrive/test/test_valgrind_replay.py b/selfdrive/test/test_valgrind_replay.py index 238b822ec9..46dd4901e5 100755 --- a/selfdrive/test/test_valgrind_replay.py +++ b/selfdrive/test/test_valgrind_replay.py @@ -28,7 +28,7 @@ CONFIGS = [ }, ignore=[], command="./ubloxd", - path="selfdrive/locationd/", + path="system/ubloxd", segment="0375fdf7b1ce594d|2019-06-13--08-32-25--3", wait_for_response=True ), diff --git a/system/ubloxd/.gitignore b/system/ubloxd/.gitignore new file mode 100644 index 0000000000..05263ff67c --- /dev/null +++ b/system/ubloxd/.gitignore @@ -0,0 +1,2 @@ +ubloxd +tests/test_glonass_runner diff --git a/system/ubloxd/SConscript b/system/ubloxd/SConscript new file mode 100644 index 0000000000..fff0986efd --- /dev/null +++ b/system/ubloxd/SConscript @@ -0,0 +1,20 @@ +Import('env', 'common', 'cereal', 'messaging') + +loc_libs = [cereal, messaging, 'zmq', common, 'capnp', 'kj', 'kaitai', 'pthread'] + +if GetOption('kaitai'): + generated = Dir('generated').srcnode().abspath + cmd = f"kaitai-struct-compiler --target cpp_stl --outdir {generated} $SOURCES" + env.Command(['generated/ubx.cpp', 'generated/ubx.h'], 'ubx.ksy', cmd) + env.Command(['generated/gps.cpp', 'generated/gps.h'], 'gps.ksy', cmd) + glonass = env.Command(['generated/glonass.cpp', 'generated/glonass.h'], 'glonass.ksy', cmd) + + # kaitai issue: https://github.com/kaitai-io/kaitai_struct/issues/910 + patch = env.Command(None, 'glonass_fix.patch', 'git apply $SOURCES') + env.Depends(patch, glonass) + +glonass_obj = env.Object('generated/glonass.cpp') +env.Program("ubloxd", ["ubloxd.cc", "ublox_msg.cc", "generated/ubx.cpp", "generated/gps.cpp", glonass_obj], LIBS=loc_libs) + +if GetOption('test'): + env.Program("tests/test_glonass_runner", ['tests/test_glonass_runner.cc', 'tests/test_glonass_kaitai.cc', glonass_obj], LIBS=[loc_libs]) \ No newline at end of file diff --git a/selfdrive/locationd/generated/glonass.cpp b/system/ubloxd/generated/glonass.cpp similarity index 100% rename from selfdrive/locationd/generated/glonass.cpp rename to system/ubloxd/generated/glonass.cpp diff --git a/selfdrive/locationd/generated/glonass.h b/system/ubloxd/generated/glonass.h similarity index 100% rename from selfdrive/locationd/generated/glonass.h rename to system/ubloxd/generated/glonass.h diff --git a/selfdrive/locationd/generated/gps.cpp b/system/ubloxd/generated/gps.cpp similarity index 100% rename from selfdrive/locationd/generated/gps.cpp rename to system/ubloxd/generated/gps.cpp diff --git a/selfdrive/locationd/generated/gps.h b/system/ubloxd/generated/gps.h similarity index 100% rename from selfdrive/locationd/generated/gps.h rename to system/ubloxd/generated/gps.h diff --git a/selfdrive/locationd/generated/ubx.cpp b/system/ubloxd/generated/ubx.cpp similarity index 100% rename from selfdrive/locationd/generated/ubx.cpp rename to system/ubloxd/generated/ubx.cpp diff --git a/selfdrive/locationd/generated/ubx.h b/system/ubloxd/generated/ubx.h similarity index 100% rename from selfdrive/locationd/generated/ubx.h rename to system/ubloxd/generated/ubx.h diff --git a/selfdrive/locationd/glonass.ksy b/system/ubloxd/glonass.ksy similarity index 100% rename from selfdrive/locationd/glonass.ksy rename to system/ubloxd/glonass.ksy diff --git a/selfdrive/locationd/glonass_fix.patch b/system/ubloxd/glonass_fix.patch similarity index 68% rename from selfdrive/locationd/glonass_fix.patch rename to system/ubloxd/glonass_fix.patch index fa34a8ef15..7eb973a348 100644 --- a/selfdrive/locationd/glonass_fix.patch +++ b/system/ubloxd/glonass_fix.patch @@ -1,7 +1,7 @@ -diff --git a/selfdrive/locationd/generated/glonass.cpp b/selfdrive/locationd/generated/glonass.cpp +diff --git a/system/ubloxd/generated/glonass.cpp b/system/ubloxd/generated/glonass.cpp index 5b17bc327..b5c6aa610 100644 ---- a/selfdrive/locationd/generated/glonass.cpp -+++ b/selfdrive/locationd/generated/glonass.cpp +--- a/system/ubloxd/generated/glonass.cpp ++++ b/system/ubloxd/generated/glonass.cpp @@ -17,7 +17,7 @@ glonass_t::glonass_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, glonass void glonass_t::_read() { m_idle_chip = m__io->read_bits_int_be(1); diff --git a/selfdrive/locationd/gps.ksy b/system/ubloxd/gps.ksy similarity index 100% rename from selfdrive/locationd/gps.ksy rename to system/ubloxd/gps.ksy diff --git a/selfdrive/locationd/test/print_gps_stats.py b/system/ubloxd/tests/print_gps_stats.py similarity index 100% rename from selfdrive/locationd/test/print_gps_stats.py rename to system/ubloxd/tests/print_gps_stats.py diff --git a/selfdrive/locationd/test/test_glonass_kaitai.cc b/system/ubloxd/tests/test_glonass_kaitai.cc similarity index 99% rename from selfdrive/locationd/test/test_glonass_kaitai.cc rename to system/ubloxd/tests/test_glonass_kaitai.cc index 22f5202a3d..5ad274142a 100644 --- a/selfdrive/locationd/test/test_glonass_kaitai.cc +++ b/system/ubloxd/tests/test_glonass_kaitai.cc @@ -6,7 +6,7 @@ #include #include "catch2/catch.hpp" -#include "selfdrive/locationd/generated/glonass.h" +#include "system/ubloxd/generated/glonass.h" typedef std::vector> string_data; diff --git a/selfdrive/locationd/test/test_glonass_runner.cc b/system/ubloxd/tests/test_glonass_runner.cc similarity index 100% rename from selfdrive/locationd/test/test_glonass_runner.cc rename to system/ubloxd/tests/test_glonass_runner.cc diff --git a/selfdrive/locationd/test/test_ublox_processing.py b/system/ubloxd/tests/test_ublox_processing.py similarity index 100% rename from selfdrive/locationd/test/test_ublox_processing.py rename to system/ubloxd/tests/test_ublox_processing.py diff --git a/selfdrive/locationd/test/ublox.py b/system/ubloxd/tests/ublox.py similarity index 100% rename from selfdrive/locationd/test/ublox.py rename to system/ubloxd/tests/ublox.py diff --git a/selfdrive/locationd/test/ubloxd.py b/system/ubloxd/tests/ubloxd.py similarity index 100% rename from selfdrive/locationd/test/ubloxd.py rename to system/ubloxd/tests/ubloxd.py diff --git a/selfdrive/locationd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc similarity index 100% rename from selfdrive/locationd/ublox_msg.cc rename to system/ubloxd/ublox_msg.cc diff --git a/selfdrive/locationd/ublox_msg.h b/system/ubloxd/ublox_msg.h similarity index 96% rename from selfdrive/locationd/ublox_msg.h rename to system/ubloxd/ublox_msg.h index 6988f20b74..3989bbf85b 100644 --- a/selfdrive/locationd/ublox_msg.h +++ b/system/ubloxd/ublox_msg.h @@ -9,9 +9,9 @@ #include "cereal/messaging/messaging.h" #include "common/util.h" -#include "selfdrive/locationd/generated/gps.h" -#include "selfdrive/locationd/generated/glonass.h" -#include "selfdrive/locationd/generated/ubx.h" +#include "system/ubloxd/generated/gps.h" +#include "system/ubloxd/generated/glonass.h" +#include "system/ubloxd/generated/ubx.h" using namespace std::string_literals; diff --git a/selfdrive/locationd/ubloxd.cc b/system/ubloxd/ubloxd.cc similarity index 97% rename from selfdrive/locationd/ubloxd.cc rename to system/ubloxd/ubloxd.cc index d9b3e7647d..81731ac931 100644 --- a/selfdrive/locationd/ubloxd.cc +++ b/system/ubloxd/ubloxd.cc @@ -5,7 +5,7 @@ #include "cereal/messaging/messaging.h" #include "common/swaglog.h" #include "common/util.h" -#include "selfdrive/locationd/ublox_msg.h" +#include "system/ubloxd/ublox_msg.h" ExitHandler do_exit; using namespace ublox; diff --git a/selfdrive/locationd/ubx.ksy b/system/ubloxd/ubx.ksy similarity index 100% rename from selfdrive/locationd/ubx.ksy rename to system/ubloxd/ubx.ksy From 75eaca3cf360614dcc86a7028921bbf022e30fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 9 Mar 2023 11:12:42 -0800 Subject: [PATCH 1064/1179] Update amplifier config (#27443) * update tizi amplifier * Update attenuation --- system/hardware/tici/amplifier.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/system/hardware/tici/amplifier.py b/system/hardware/tici/amplifier.py index 8233834d11..840d575fdf 100644 --- a/system/hardware/tici/amplifier.py +++ b/system/hardware/tici/amplifier.py @@ -24,13 +24,10 @@ BASE_CONFIG = [ AmpConfig("MCLK prescaler", 0b01, 0x10, 4, 0b00110000), AmpConfig("PM: enable speakers", 0b11, 0x4D, 4, 0b00110000), AmpConfig("PM: enable DACs", 0b11, 0x4D, 0, 0b00000011), - AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111), - AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100), AmpConfig("Enable PLL1", 0b1, 0x12, 7, 0b10000000), AmpConfig("Enable PLL2", 0b1, 0x1A, 7, 0b10000000), AmpConfig("DAI1: I2S mode", 0b00100, 0x14, 2, 0b01111100), AmpConfig("DAI2: I2S mode", 0b00100, 0x1C, 2, 0b01111100), - AmpConfig("Right speaker output volume", 0x1c, 0x3E, 0, 0b00011111), AmpConfig("DAI1 Passband filtering: music mode", 0b1, 0x18, 7, 0b10000000), AmpConfig("DAI1 voice mode gain (DV1G)", 0b00, 0x2F, 4, 0b00110000), AmpConfig("DAI1 attenuation (DV1)", 0x0, 0x2F, 0, 0b00001111), @@ -41,7 +38,6 @@ BASE_CONFIG = [ AmpConfig("ALC/excursion limiter release time", 0b101, 0x43, 4, 0b01110000), AmpConfig("ALC multiband enable", 0b1, 0x43, 3, 0b00001000), AmpConfig("DAI1 EQ enable", 0b0, 0x49, 0, 0b00000001), - AmpConfig("DAI2 EQ enable", 0b1, 0x49, 1, 0b00000010), AmpConfig("DAI2 EQ clip detection disabled", 0b1, 0x32, 4, 0b00010000), AmpConfig("DAI2 EQ attenuation", 0x5, 0x32, 0, 0b00001111), AmpConfig("Excursion limiter upper corner freq", 0b100, 0x41, 4, 0b01110000), @@ -64,6 +60,11 @@ BASE_CONFIG = [ CONFIGS = { "tici": [ + AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111), + AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100), + AmpConfig("Right speaker output volume", 0x1c, 0x3E, 0, 0b00011111), + AmpConfig("DAI2 EQ enable", 0b1, 0x49, 1, 0b00000010), + *configs_from_eq_params(0x84, EQParams(0x274F, 0xC0FF, 0x3BF9, 0x0B3C, 0x1656)), *configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF)), *configs_from_eq_params(0x98, EQParams(0x0F75, 0xCBE5, 0x0ED2, 0x2528, 0x3E42)), @@ -72,11 +73,13 @@ CONFIGS = { ], "tizi": [ AmpConfig("Left speaker output from left DAC", 0b1, 0x2B, 0, 0b11111111), + AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111), AmpConfig("Left Speaker Mixer Gain", 0b00, 0x2D, 0, 0b00000011), - AmpConfig("Left speaker output volume", 0x1F, 0x3D, 0, 0b00011111), - AmpConfig("Right speaker output volume", 0x1F, 0x3E, 0, 0b00011111), - AmpConfig("DAI1 attenuation (DV1)", 0x4, 0x2F, 0, 0b00001111), - AmpConfig("DAI2 attenuation (DV2)", 0x4, 0x31, 0, 0b00001111), + AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100), + AmpConfig("Left speaker output volume", 0x17, 0x3D, 0, 0b00011111), + AmpConfig("Right speaker output volume", 0x17, 0x3E, 0, 0b00011111), + + AmpConfig("DAI2 EQ enable", 0b0, 0x49, 1, 0b00000010), AmpConfig("DAI2: DC blocking", 0b0, 0x20, 0, 0b00000001), AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000), AmpConfig("DAI2 EQ attenuation", 0x2, 0x32, 0, 0b00001111), @@ -91,12 +94,6 @@ CONFIGS = { AmpConfig("Right DAC input mixer: DAI2 left", 0b0, 0x22, 1, 0b00000010), AmpConfig("Right DAC input mixer: DAI2 right", 0b1, 0x22, 0, 0b00000001), AmpConfig("Volume adjustment smoothing disabled", 0b1, 0x49, 6, 0b01000000), - - *configs_from_eq_params(0x84, EQParams(0x3084, 0xC023, 0x3D60, 0x042B, 0x1222)), - *configs_from_eq_params(0x8E, EQParams(0x2FB2, 0xC05C, 0x3BD3, 0x06C5, 0x16BB)), - *configs_from_eq_params(0x98, EQParams(0x21F5, 0xDF73, 0x2DFE, 0x371A, 0x2C80)), - *configs_from_eq_params(0xA2, EQParams(0x2A5A, 0x0AD0, 0x14FA, 0x3F14, 0x3C76)), - *configs_from_eq_params(0xAC, EQParams(0x1577, 0x3FAE, 0xEE60, 0x0664, 0x3D86)), ], } From 9b28897f09112ec1dc28d7196964588989029940 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 10 Mar 2023 05:13:29 +0800 Subject: [PATCH 1065/1179] replay: fix incorrect format string in seekTo (#27547) --- tools/replay/replay.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/replay/replay.cc b/tools/replay/replay.cc index 178b116a87..b68330f688 100644 --- a/tools/replay/replay.cc +++ b/tools/replay/replay.cc @@ -193,7 +193,7 @@ std::optional Replay::find(FindFlag flag) { void Replay::pause(bool pause) { updateEvents([=]() { - rWarning("%s at %d s", pause ? "paused..." : "resuming", currentSeconds()); + rWarning("%s at %.2f s", pause ? "paused..." : "resuming", currentSeconds()); paused_ = pause; return true; }); From b5d29b550c4b900d5e5e9dd9322a478e12ec9013 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 10 Mar 2023 05:13:46 +0800 Subject: [PATCH 1066/1179] cabana: get icon size from QStyle::PM_SmallIconSize (#27548) --- tools/cabana/util.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 1a0b9d93ef..778ffbc859 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -170,6 +170,8 @@ QToolButton *toolButton(const QString &icon, const QString &tooltip) { btn->setIcon(utils::icon(icon)); btn->setToolTip(tooltip); btn->setAutoRaise(true); + const int metric = qApp->style()->pixelMetric(QStyle::PM_SmallIconSize); + btn->setIconSize({metric, metric}); return btn; }; From b79f4594c42b4af0fc371b5d48445ce86c1cb3ff Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 9 Mar 2023 22:14:06 +0100 Subject: [PATCH 1067/1179] cabana: scrub by shift dragging on graph (#27545) * cabana: scrub by shift dragging on graph * not while live streaming --- tools/cabana/chartswidget.cc | 26 ++++++++++++++++++++++++++ tools/cabana/chartswidget.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 54966be578..8ef2ae7b4f 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -668,6 +668,16 @@ void ChartView::mousePressEvent(QMouseEvent *event) { if (dropAction == Qt::MoveAction) { return; } + } else if (event->button() == Qt::LeftButton && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { + if (!can->liveStreaming()) { + // Save current playback state when scrubbing + resume_after_scrub = !can->isPaused(); + if (resume_after_scrub) { + can->pause(true); + } + + is_scrubbing = true; + } } else { QChartView::mousePressEvent(event); } @@ -701,9 +711,25 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } else { QGraphicsView::mouseReleaseEvent(event); } + + // Resume playback if we were scrubbing + is_scrubbing = false; + if (resume_after_scrub) { + can->pause(false); + resume_after_scrub = false; + } } void ChartView::mouseMoveEvent(QMouseEvent *ev) { + // Scrubbing + if (is_scrubbing && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { + double t = chart()->mapToValue({(double)ev->x(), (double)ev->y()}).x(); + // Prevent seeking past the end of the route + t = std::clamp(t, 0., can->totalSeconds()); + can->seekTo(t); + return; + } + auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); const auto plot_area = chart()->plotArea(); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index c86c19a04e..22ba020b29 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -97,6 +97,8 @@ private: double cur_sec = 0; const QString mime_type = "application/x-cabanachartview"; SeriesType series_type = SeriesType::Line; + bool is_scrubbing = false; + bool resume_after_scrub = false; friend class ChartsWidget; }; From 5b3a72267c628785859e673eaecc2787e02f1220 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Thu, 9 Mar 2023 22:14:21 +0100 Subject: [PATCH 1068/1179] cabana: fix changing message size (#27544) * cabana: fix changing message size * fix naming signal untitled --- tools/cabana/detailwidget.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 01fbccf7db..71dbf8d56b 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -194,7 +194,7 @@ EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &tit form_layout->addRow(tr("Size"), size_spin); btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - btn_box->button(QDialogButtonBox::Ok)->setEnabled(false); + validateName(name_edit->text()); form_layout->addRow(btn_box); setFixedWidth(parent->width() * 0.9); @@ -204,9 +204,9 @@ EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &tit } void EditMessageDialog::validateName(const QString &text) { - bool valid = false; + bool valid = text.compare(UNTITLED, Qt::CaseInsensitive) != 0; error_label->setVisible(false); - if (!text.isEmpty() && text != original_name && text.compare(UNTITLED, Qt::CaseInsensitive) != 0) { + if (!text.isEmpty() && valid && text != original_name) { valid = std::none_of(dbc()->messages().begin(), dbc()->messages().end(), [&text](auto &m) { return m.second.name == text; }); if (!valid) { From 572eba78a675836e036456afc6e1bb2f14e9a3d6 Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Thu, 9 Mar 2023 22:17:22 -0300 Subject: [PATCH 1069/1179] Multilanguage: update pt-BR translations (#27546) update pt-BR translations --- selfdrive/ui/translations/main_pt-BR.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 5c4eab3327..8dc3a9830d 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -596,16 +596,17 @@ trabalho definido Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - + Não é possível montar a partição de dados. Partição corrompida. Confirme para apagar e redefinir o dispositivo. Press confirm to erase all content and settings. Press cancel to resume boot. - + Pressione confirmar para apagar todo o conteúdo e configurações. Pressione cancelar para voltar. Resetting device... This may take up to a minute. - + Redefinindo o dispositivo +Isso pode levar até um minuto. @@ -707,11 +708,11 @@ This may take up to a minute. No custom software found at this URL. - + Não há software personalizado nesta URL. Something went wrong. Reboot the device. - + Algo deu errado. Reinicie o dispositivo. From 7d32554fe36dd428efa45f9998b3cb0e018d9a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 9 Mar 2023 18:48:32 -0800 Subject: [PATCH 1070/1179] Parse GLONASS ephemeris from mystery satellites (#27541) parse unknown glonass --- system/ubloxd/ublox_msg.cc | 62 ++++++++++++++++++++++++++------------ system/ubloxd/ublox_msg.h | 6 ++-- system/ubloxd/ubloxd.cc | 3 +- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/system/ubloxd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc index ebd904f72f..83e64b7ddc 100644 --- a/system/ubloxd/ublox_msg.cc +++ b/system/ubloxd/ublox_msg.cc @@ -81,7 +81,8 @@ inline uint16_t UbloxMsgParser::get_glonass_year(uint8_t N4, uint16_t Nt) { return year; } -bool UbloxMsgParser::add_data(const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed) { +bool UbloxMsgParser::add_data(float log_time, const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed) { + last_log_time = log_time; int needed = needed_bytes(); if(needed > 0) { bytes_consumed = std::min((uint32_t)needed, incoming_data_len ); @@ -266,12 +267,8 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m } kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_t *msg) { - if (msg->sv_id() == 255) { - // data can be decoded before identifying the SV number, in this case 255 - // is returned, which means "unknown" (ublox p32) - return kj::Array(); - } - + // This parser assumes that no 2 satellites of the same frequency + // can be in view at the same time auto body = *msg->body(); assert(body.size() == 4); { @@ -284,23 +281,48 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ kaitai::kstream stream(string_data); glonass_t gl_string(&stream); - int string_number = gl_string.string_number(); if (string_number < 1 || string_number > 5 || gl_string.idle_chip()) { // dont parse non immediate data, idle_chip == 0 return kj::Array(); } - // immediate data is the same within one superframe - if (glonass_superframes[msg->sv_id()] != gl_string.superframe_number()) { - glonass_strings[msg->sv_id()].clear(); - glonass_superframes[msg->sv_id()] = gl_string.superframe_number(); + // Check if new string either has same superframe_id or log transmission times make sense + bool superframe_unknown = false; + bool needs_clear = false; + for (int i = 1; i <= 5; i++) { + if (glonass_strings[msg->freq_id()].find(i) == glonass_strings[msg->freq_id()].end()) + continue; + if (glonass_string_superframes[msg->freq_id()][i] == 0 || gl_string.superframe_number() == 0) { + superframe_unknown = true; + } + else if (glonass_string_superframes[msg->freq_id()][i] != gl_string.superframe_number()) { + needs_clear = true; + } + // Check if string times add up to being from the same frame + // If superframe is known this is redundant + // Strings are sent 2s apart and frames are 30s apart + if (superframe_unknown && + std::abs((glonass_string_times[msg->freq_id()][i] - 2.0 * i) - (last_log_time - 2.0 * string_number)) > 10) + needs_clear = true; } - glonass_strings[msg->sv_id()][string_number] = string_data; + if (needs_clear) { + glonass_strings[msg->freq_id()].clear(); + glonass_string_superframes[msg->freq_id()].clear(); + glonass_string_times[msg->freq_id()].clear(); + } + glonass_strings[msg->freq_id()][string_number] = string_data; + glonass_string_superframes[msg->freq_id()][string_number] = gl_string.superframe_number(); + glonass_string_times[msg->freq_id()][string_number] = last_log_time; + } + if (msg->sv_id() == 255) { + // data can be decoded before identifying the SV number, in this case 255 + // is returned, which means "unknown" (ublox p32) + return kj::Array(); } // publish if strings 1-5 have been collected - if (glonass_strings[msg->sv_id()].size() != 5) { + if (glonass_strings[msg->freq_id()].size() != 5) { return kj::Array(); } @@ -311,7 +333,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string number 1 { - kaitai::kstream stream(glonass_strings[msg->sv_id()][1]); + kaitai::kstream stream(glonass_strings[msg->freq_id()][1]); glonass_t gl_stream(&stream); glonass_t::string_1_t* data = static_cast(gl_stream.data()); @@ -324,7 +346,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string number 2 { - kaitai::kstream stream(glonass_strings[msg->sv_id()][2]); + kaitai::kstream stream(glonass_strings[msg->freq_id()][2]); glonass_t gl_stream(&stream); glonass_t::string_2_t* data = static_cast(gl_stream.data()); @@ -338,7 +360,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string number 3 { - kaitai::kstream stream(glonass_strings[msg->sv_id()][3]); + kaitai::kstream stream(glonass_strings[msg->freq_id()][3]); glonass_t gl_stream(&stream); glonass_t::string_3_t* data = static_cast(gl_stream.data()); @@ -352,7 +374,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string number 4 { - kaitai::kstream stream(glonass_strings[msg->sv_id()][4]); + kaitai::kstream stream(glonass_strings[msg->freq_id()][4]); glonass_t gl_stream(&stream); glonass_t::string_4_t* data = static_cast(gl_stream.data()); @@ -370,7 +392,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string number 5 { - kaitai::kstream stream(glonass_strings[msg->sv_id()][5]); + kaitai::kstream stream(glonass_strings[msg->freq_id()][5]); glonass_t gl_stream(&stream); glonass_t::string_5_t* data = static_cast(gl_stream.data()); @@ -399,7 +421,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ eph.setSecond((eph.getTk() & 0x1) * 30); } - glonass_strings[msg->sv_id()].clear(); + glonass_strings[msg->freq_id()].clear(); return capnp::messageToFlatArray(msg_builder); } diff --git a/system/ubloxd/ublox_msg.h b/system/ubloxd/ublox_msg.h index 3989bbf85b..06877cc50d 100644 --- a/system/ubloxd/ublox_msg.h +++ b/system/ubloxd/ublox_msg.h @@ -86,7 +86,7 @@ namespace ublox { class UbloxMsgParser { public: - bool add_data(const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed); + bool add_data(float log_time, const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed); inline void reset() {bytes_in_parse_buf = 0;} inline int needed_bytes(); inline std::string data() {return std::string((const char*)msg_parse_buf, bytes_in_parse_buf);} @@ -109,6 +109,7 @@ class UbloxMsgParser { std::unordered_map> gps_subframes; + float last_log_time = 0.0; size_t bytes_in_parse_buf = 0; uint8_t msg_parse_buf[ublox::UBLOX_HEADER_SIZE + ublox::UBLOX_MAX_MSG_SIZE]; @@ -119,5 +120,6 @@ class UbloxMsgParser { {11, 64}, {12, 128}, {13, 256}, {14, 512}, {15, 1024}}; std::unordered_map> glonass_strings; - std::unordered_map glonass_superframes; + std::unordered_map> glonass_string_times; + std::unordered_map> glonass_string_superframes; }; diff --git a/system/ubloxd/ubloxd.cc b/system/ubloxd/ubloxd.cc index 81731ac931..1dae6dc866 100644 --- a/system/ubloxd/ubloxd.cc +++ b/system/ubloxd/ubloxd.cc @@ -35,6 +35,7 @@ int main() { capnp::FlatArrayMessageReader cmsg(aligned_buf.align(msg.get())); cereal::Event::Reader event = cmsg.getRoot(); auto ubloxRaw = event.getUbloxRaw(); + float log_time = 1e-9 * event.getLogMonoTime(); const uint8_t *data = ubloxRaw.begin(); size_t len = ubloxRaw.size(); @@ -42,7 +43,7 @@ int main() { while(bytes_consumed < len && !do_exit) { size_t bytes_consumed_this_time = 0U; - if(parser.add_data(data + bytes_consumed, (uint32_t)(len - bytes_consumed), bytes_consumed_this_time)) { + if(parser.add_data(log_time, data + bytes_consumed, (uint32_t)(len - bytes_consumed), bytes_consumed_this_time)) { try { auto ublox_msg = parser.gen_msg(); From e4d591ecbfaaf12b267e3f93927a89e9b4f6a7b9 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 10 Mar 2023 20:19:37 +0100 Subject: [PATCH 1071/1179] cabana: refactor Msg and Signal into dbc.cc (#27552) --- tools/cabana/SConscript | 2 +- tools/cabana/binaryview.cc | 16 +-- tools/cabana/binaryview.h | 23 ++-- tools/cabana/chartswidget.cc | 14 +-- tools/cabana/chartswidget.h | 31 +++-- tools/cabana/commands.cc | 6 +- tools/cabana/commands.h | 17 ++- tools/cabana/dbc.cc | 77 ++++++++++++ tools/cabana/dbc.h | 78 ++++++++++++ tools/cabana/dbcmanager.cc | 168 +++++++------------------- tools/cabana/dbcmanager.h | 90 ++------------ tools/cabana/detailwidget.cc | 2 +- tools/cabana/historylog.h | 4 +- tools/cabana/mainwin.cc | 2 +- tools/cabana/messageswidget.h | 1 - tools/cabana/signaledit.cc | 28 ++--- tools/cabana/signaledit.h | 26 ++-- tools/cabana/tests/test_cabana.cc | 1 - tools/cabana/tools/findsimilarbits.cc | 1 - tools/cabana/tools/findsimilarbits.h | 1 - tools/cabana/util.cc | 2 +- tools/cabana/util.h | 5 +- tools/cabana/videowidget.h | 1 - 23 files changed, 295 insertions(+), 301 deletions(-) create mode 100644 tools/cabana/dbc.cc create mode 100644 tools/cabana/dbc.h diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index ddd6208c07..3cb5913c01 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -28,7 +28,7 @@ cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "asset prev_moc_path = cabana_env['QT_MOCHPREFIX'] cabana_env['QT_MOCHPREFIX'] = os.path.dirname(prev_moc_path) + '/cabana/moc_' -cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbcmanager.cc', +cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'chartswidget.cc', 'historylog.cc', 'videowidget.cc', 'signaledit.cc', 'dbc.cc', 'dbcmanager.cc', 'commands.cc', 'messageswidget.cc', 'route.cc', 'settings.cc', 'util.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index 120a85a330..b81f7d5e79 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -75,8 +75,8 @@ void BinaryView::addShortcuts() { QShortcut *shortcut_endian = new QShortcut(QKeySequence(Qt::Key_E), this); QObject::connect(shortcut_endian, &QShortcut::activated, [=]{ if (hovered_sig != nullptr) { - const Signal *hovered_sig_prev = hovered_sig; - Signal s = *hovered_sig; + const cabana::Signal *hovered_sig_prev = hovered_sig; + cabana::Signal s = *hovered_sig; s.is_little_endian = !s.is_little_endian; emit editSignal(hovered_sig, s); @@ -89,8 +89,8 @@ void BinaryView::addShortcuts() { QShortcut *shortcut_sign = new QShortcut(QKeySequence(Qt::Key_S), this); QObject::connect(shortcut_sign, &QShortcut::activated, [=]{ if (hovered_sig != nullptr) { - const Signal *hovered_sig_prev = hovered_sig; - Signal s = *hovered_sig; + const cabana::Signal *hovered_sig_prev = hovered_sig; + cabana::Signal s = *hovered_sig; s.is_signed = !s.is_signed; emit editSignal(hovered_sig, s); @@ -117,7 +117,7 @@ QSize BinaryView::minimumSizeHint() const { CELL_HEIGHT * std::min(model->rowCount(), 10) + 2}; } -void BinaryView::highlight(const Signal *sig) { +void BinaryView::highlight(const cabana::Signal *sig) { if (sig != hovered_sig) { for (int i = 0; i < model->items.size(); ++i) { auto &item_sigs = model->items[i].sigs; @@ -176,7 +176,7 @@ void BinaryView::mousePressEvent(QMouseEvent *event) { void BinaryView::highlightPosition(const QPoint &pos) { if (auto index = indexAt(viewport()->mapFromGlobal(pos)); index.isValid()) { auto item = (BinaryViewModel::Item *)index.internalPointer(); - const Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); + const cabana::Signal *sig = item->sigs.isEmpty() ? nullptr : item->sigs.back(); highlight(sig); } } @@ -226,8 +226,8 @@ void BinaryView::refresh() { highlightPosition(QCursor::pos()); } -QSet BinaryView::getOverlappingSignals() const { - QSet overlapping; +QSet BinaryView::getOverlappingSignals() const { + QSet overlapping; for (auto &item : model->items) { if (item.sigs.size() > 1) for (auto s : item.sigs) overlapping += s; diff --git a/tools/cabana/binaryview.h b/tools/cabana/binaryview.h index 681ac1fbf3..f677d11941 100644 --- a/tools/cabana/binaryview.h +++ b/tools/cabana/binaryview.h @@ -8,7 +8,6 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; class BinaryItemDelegate : public QStyledItemDelegate { public: @@ -44,7 +43,7 @@ public: bool is_msb = false; bool is_lsb = false; QString val = "-"; - QList sigs; + QList sigs; }; std::vector items; @@ -59,19 +58,19 @@ class BinaryView : public QTableView { public: BinaryView(QWidget *parent = nullptr); void setMessage(const MessageId &message_id); - void highlight(const Signal *sig); - QSet getOverlappingSignals() const; + void highlight(const cabana::Signal *sig); + QSet getOverlappingSignals() const; inline void updateState() { model->updateState(); } QSize minimumSizeHint() const override; signals: - void signalClicked(const Signal *sig); - void signalHovered(const Signal *sig); + void signalClicked(const cabana::Signal *sig); + void signalHovered(const cabana::Signal *sig); void addSignal(int start_bit, int size, bool little_endian); - void resizeSignal(const Signal *sig, int from, int size); - void removeSignal(const Signal *sig); - void editSignal(const Signal *origin_s, Signal &s); - void showChart(const MessageId &id, const Signal *sig, bool show, bool merge); + void resizeSignal(const cabana::Signal *sig, int from, int size); + void removeSignal(const cabana::Signal *sig); + void editSignal(const cabana::Signal *origin_s, cabana::Signal &s); + void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge); private: void addShortcuts(); @@ -87,7 +86,7 @@ private: QModelIndex anchor_index; BinaryViewModel *model; BinaryItemDelegate *delegate; - const Signal *resize_sig = nullptr; - const Signal *hovered_sig = nullptr; + const cabana::Signal *resize_sig = nullptr; + const cabana::Signal *hovered_sig = nullptr; friend class BinaryItemDelegate; }; diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 8ef2ae7b4f..5bab261ba7 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -189,7 +189,7 @@ void ChartsWidget::settingChanged() { } } -ChartView *ChartsWidget::findChart(const MessageId &id, const Signal *sig) { +ChartView *ChartsWidget::findChart(const MessageId &id, const cabana::Signal *sig) { for (auto c : charts) if (c->hasSeries(id, sig)) return c; return nullptr; @@ -212,7 +212,7 @@ ChartView *ChartsWidget::createChart() { return chart; } -void ChartsWidget::showChart(const MessageId &id, const Signal *sig, bool show, bool merge) { +void ChartsWidget::showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge) { ChartView *chart = findChart(id, sig); if (show && !chart) { chart = merge && charts.size() > 0 ? charts.back() : createChart(); @@ -377,7 +377,7 @@ void ChartView::createToolButtons() { }); } -void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) { +void ChartView::addSeries(const MessageId &msg_id, const cabana::Signal *sig) { if (hasSeries(msg_id, sig)) return; QXYSeries *series = createSeries(series_type, getColor(sig)); @@ -388,7 +388,7 @@ void ChartView::addSeries(const MessageId &msg_id, const Signal *sig) { emit seriesAdded(msg_id, sig); } -bool ChartView::hasSeries(const MessageId &msg_id, const Signal *sig) const { +bool ChartView::hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const { return std::any_of(sigs.begin(), sigs.end(), [&](auto &s) { return s.msg_id == msg_id && s.sig == sig; }); } @@ -413,7 +413,7 @@ void ChartView::removeIf(std::function predicate) { } } -void ChartView::signalUpdated(const Signal *sig) { +void ChartView::signalUpdated(const cabana::Signal *sig) { if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.sig == sig; })) { updateTitle(); // TODO: don't update series if only name changed. @@ -502,7 +502,7 @@ void ChartView::updateSeriesPoints() { } } -void ChartView::updateSeries(const Signal *sig, const std::vector *events, bool clear) { +void ChartView::updateSeries(const cabana::Signal *sig, const std::vector *events, bool clear) { events = events ? events : can->events(); for (auto &s : sigs) { if (!sig || s.sig == sig) { @@ -980,7 +980,7 @@ void SeriesSelector::updateAvailableList(int index) { } } -void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name) { +void SeriesSelector::addItemToList(QListWidget *parent, const MessageId id, const cabana::Signal *sig, bool show_msg_name) { QString text = QString(" %1").arg(getColor(sig).name(), sig->name); if (show_msg_name) text += QString(" %0 %1").arg(msgName(id), id.toString()); diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index 22ba020b29..fdfbbc11ff 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -15,7 +15,6 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; using namespace QtCharts; const int CHART_MIN_WIDTH = 300; @@ -31,16 +30,16 @@ class ChartView : public QChartView { public: ChartView(QWidget *parent = nullptr); - void addSeries(const MessageId &msg_id, const Signal *sig); - bool hasSeries(const MessageId &msg_id, const Signal *sig) const; - void updateSeries(const Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); + void addSeries(const MessageId &msg_id, const cabana::Signal *sig); + bool hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const; + void updateSeries(const cabana::Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); void updatePlot(double cur, double min, double max); void setSeriesType(SeriesType type); void updatePlotArea(int left); struct SigItem { MessageId msg_id; - const Signal *sig = nullptr; + const cabana::Signal *sig = nullptr; QXYSeries *series = nullptr; QVector vals; QVector step_vals; @@ -50,8 +49,8 @@ public: }; signals: - void seriesRemoved(const MessageId &id, const Signal *sig); - void seriesAdded(const MessageId &id, const Signal *sig); + void seriesRemoved(const MessageId &id, const cabana::Signal *sig); + void seriesAdded(const MessageId &id, const cabana::Signal *sig); void zoomIn(double min, double max); void zoomReset(); void remove(); @@ -59,11 +58,11 @@ signals: private slots: void msgUpdated(uint32_t address); - void signalUpdated(const Signal *sig); + void signalUpdated(const cabana::Signal *sig); void manageSeries(); void handleMarkerClicked(); void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.msg_id.address == address; }); } - void signalRemoved(const Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } + void signalRemoved(const cabana::Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: void createToolButtons(); @@ -107,8 +106,8 @@ class ChartsWidget : public QFrame { public: ChartsWidget(QWidget *parent = nullptr); - void showChart(const MessageId &id, const Signal *sig, bool show, bool merge); - inline bool hasSignal(const MessageId &id, const Signal *sig) { return findChart(id, sig) != nullptr; } + void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge); + inline bool hasSignal(const MessageId &id, const cabana::Signal *sig) { return findChart(id, sig) != nullptr; } public slots: void setColumnCount(int n); @@ -134,7 +133,7 @@ private: void updateLayout(); void settingChanged(); bool eventFilter(QObject *obj, QEvent *event) override; - ChartView *findChart(const MessageId &id, const Signal *sig); + ChartView *findChart(const MessageId &id, const cabana::Signal *sig); QLabel *title_label; QLabel *range_lb; @@ -160,18 +159,18 @@ private: class SeriesSelector : public QDialog { public: struct ListItem : public QListWidgetItem { - ListItem(const MessageId &msg_id, const Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {} + ListItem(const MessageId &msg_id, const cabana::Signal *sig, QListWidget *parent) : msg_id(msg_id), sig(sig), QListWidgetItem(parent) {} MessageId msg_id; - const Signal *sig; + const cabana::Signal *sig; }; SeriesSelector(QString title, QWidget *parent); QList seletedItems(); - inline void addSelected(const MessageId &id, const Signal *sig) { addItemToList(selected_list, id, sig, true); } + inline void addSelected(const MessageId &id, const cabana::Signal *sig) { addItemToList(selected_list, id, sig, true); } private: void updateAvailableList(int index); - void addItemToList(QListWidget *parent, const MessageId id, const Signal *sig, bool show_msg_name = false); + void addItemToList(QListWidget *parent, const MessageId id, const cabana::Signal *sig, bool show_msg_name = false); void add(QListWidgetItem *item); void remove(QListWidgetItem *item); diff --git a/tools/cabana/commands.cc b/tools/cabana/commands.cc index 9b9724aada..337de1c702 100644 --- a/tools/cabana/commands.cc +++ b/tools/cabana/commands.cc @@ -50,7 +50,7 @@ void RemoveMsgCommand::redo() { // AddSigCommand -AddSigCommand::AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent) +AddSigCommand::AddSigCommand(const MessageId &id, const cabana::Signal &sig, QUndoCommand *parent) : id(id), signal(sig), QUndoCommand(parent) { setText(QObject::tr("add signal %1 to %2:%3").arg(sig.name).arg(msgName(id)).arg(id.address)); } @@ -60,7 +60,7 @@ void AddSigCommand::redo() { dbc()->addSignal(id, signal); } // RemoveSigCommand -RemoveSigCommand::RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent) +RemoveSigCommand::RemoveSigCommand(const MessageId &id, const cabana::Signal *sig, QUndoCommand *parent) : id(id), signal(*sig), QUndoCommand(parent) { setText(QObject::tr("remove signal %1 from %2:%3").arg(signal.name).arg(msgName(id)).arg(id.address)); } @@ -70,7 +70,7 @@ void RemoveSigCommand::redo() { dbc()->removeSignal(id, signal.name); } // EditSignalCommand -EditSignalCommand::EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent) +EditSignalCommand::EditSignalCommand(const MessageId &id, const cabana::Signal *sig, const cabana::Signal &new_sig, QUndoCommand *parent) : id(id), old_signal(*sig), new_signal(new_sig), QUndoCommand(parent) { setText(QObject::tr("edit signal %1 in %2:%3").arg(old_signal.name).arg(msgName(id)).arg(id.address)); } diff --git a/tools/cabana/commands.h b/tools/cabana/commands.h index 3565211eb9..2a5f40d584 100644 --- a/tools/cabana/commands.h +++ b/tools/cabana/commands.h @@ -5,7 +5,6 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; class EditMsgCommand : public QUndoCommand { public: @@ -27,41 +26,41 @@ public: private: const MessageId id; - Msg message; + cabana::Msg message; }; class AddSigCommand : public QUndoCommand { public: - AddSigCommand(const MessageId &id, const Signal &sig, QUndoCommand *parent = nullptr); + AddSigCommand(const MessageId &id, const cabana::Signal &sig, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: const MessageId id; - Signal signal = {}; + cabana::Signal signal = {}; }; class RemoveSigCommand : public QUndoCommand { public: - RemoveSigCommand(const MessageId &id, const Signal *sig, QUndoCommand *parent = nullptr); + RemoveSigCommand(const MessageId &id, const cabana::Signal *sig, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: const MessageId id; - Signal signal = {}; + cabana::Signal signal = {}; }; class EditSignalCommand : public QUndoCommand { public: - EditSignalCommand(const MessageId &id, const Signal *sig, const Signal &new_sig, QUndoCommand *parent = nullptr); + EditSignalCommand(const MessageId &id, const cabana::Signal *sig, const cabana::Signal &new_sig, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: const MessageId id; - Signal old_signal = {}; - Signal new_signal = {}; + cabana::Signal old_signal = {}; + cabana::Signal new_signal = {}; }; namespace UndoStack { diff --git a/tools/cabana/dbc.cc b/tools/cabana/dbc.cc new file mode 100644 index 0000000000..8ffb660286 --- /dev/null +++ b/tools/cabana/dbc.cc @@ -0,0 +1,77 @@ +#include "tools/cabana/dbc.h" + +uint qHash(const MessageId &item) { + return qHash(item.source) ^ qHash(item.address); +} + +std::vector cabana::Msg::getSignals() const { + std::vector ret; + ret.reserve(sigs.size()); + for (auto &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 = []() { + QVector ret; + for (int i = 0; i < 64; i++) + for (int j = 7; j >= 0; j--) + ret.push_back(j + i * 8); + return ret; +}(); + +double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig) { + int64_t val = 0; + + int i = sig.msb / 8; + int bits = sig.size; + while (i >= 0 && i < data_size && bits > 0) { + int lsb = (int)(sig.lsb / 8) == i ? sig.lsb : i * 8; + int msb = (int)(sig.msb / 8) == i ? sig.msb : (i + 1) * 8 - 1; + int size = msb - lsb + 1; + + uint64_t d = (data[i] >> (lsb - (i * 8))) & ((1ULL << size) - 1); + val |= d << (bits - size); + + bits -= size; + i = sig.is_little_endian ? i - 1 : i + 1; + } + if (sig.is_signed) { + val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0; + } + return val * sig.factor + sig.offset; +} + +bool cabana::operator==(const cabana::Signal &l, const cabana::Signal &r) { + return l.name == r.name && l.size == r.size && + l.start_bit == r.start_bit && + l.msb == r.msb && l.lsb == r.lsb && + l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian && + l.factor == r.factor && l.offset == r.offset && + l.min == r.min && l.max == r.max && l.comment == r.comment && l.unit == r.unit && l.val_desc == r.val_desc; +} + +int bigEndianStartBitsIndex(int start_bit) { return BIG_ENDIAN_START_BITS[start_bit]; } +int bigEndianBitIndex(int index) { return BIG_ENDIAN_START_BITS.indexOf(index); } + +void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size) { + s.start_bit = s.is_little_endian ? start_bit : bigEndianBitIndex(start_bit); + s.size = size; + if (s.is_little_endian) { + s.lsb = s.start_bit; + s.msb = s.start_bit + s.size - 1; + } else { + s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); + s.msb = s.start_bit; + } +} + +std::pair getSignalRange(const cabana::Signal *s) { + int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit); + int to = from + s->size - 1; + return {from, to}; +} + +std::vector allDBCNames() { return get_dbc_names(); } diff --git a/tools/cabana/dbc.h b/tools/cabana/dbc.h new file mode 100644 index 0000000000..3c58e38055 --- /dev/null +++ b/tools/cabana/dbc.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "opendbc/can/common_dbc.h" + +const QString UNTITLED = "untitled"; + +struct MessageId { + uint8_t source; + uint32_t address; + + QString toString() const { + return QString("%1:%2").arg(source).arg(address, 1, 16); + } + + bool operator==(const MessageId &other) const { + return source == other.source && address == other.address; + } + + bool operator!=(const MessageId &other) const { + return !(*this == other); + } + + bool operator<(const MessageId &other) const { + return std::pair{source, address} < std::pair{other.source, other.address}; + } + + bool operator>(const MessageId &other) const { + return std::pair{source, address} > std::pair{other.source, other.address}; + } +}; + +uint qHash(const MessageId &item); +Q_DECLARE_METATYPE(MessageId); + + +typedef QList> ValueDescription; + +namespace cabana { + struct Signal { + QString name; + int start_bit, msb, lsb, size; + bool is_signed; + double factor, offset; + bool is_little_endian; + QString min, max, unit; + QString comment; + ValueDescription val_desc; + }; + + struct Msg { + QString name; + uint32_t size; + QList sigs; + + std::vector getSignals() const; + const cabana::Signal *sig(const QString &sig_name) const { + auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; }); + return it != sigs.end() ? &(*it) : nullptr; + } + }; + + bool operator==(const cabana::Signal &l, const cabana::Signal &r); + inline bool operator!=(const cabana::Signal &l, const cabana::Signal &r) { return !(l == r); } +} + +// Helper functions +double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig); +int bigEndianStartBitsIndex(int start_bit); +int bigEndianBitIndex(int index); +void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size); +std::pair getSignalRange(const cabana::Signal *s); +std::vector allDBCNames(); diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 32113c2f22..e9ebcd2791 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -8,8 +8,6 @@ #include #include -namespace dbcmanager { - bool DBCManager::open(const QString &dbc_file_name, QString *error) { QString opendbc_file_path = QString("%1/%2.dbc").arg(OPENDBC_FILE_PATH, dbc_file_name); QFile file(opendbc_file_path); @@ -19,15 +17,49 @@ bool DBCManager::open(const QString &dbc_file_name, QString *error) { return false; } +bool DBCManager::open(const QString &name, const QString &content, QString *error) { + try { + std::istringstream stream(content.toStdString()); + auto dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); + msgs.clear(); + for (auto &msg : dbc->msgs) { + auto &m = msgs[msg.address]; + m.name = msg.name.c_str(); + m.size = msg.size; + for (auto &s : msg.sigs) { + m.sigs.push_back({}); + auto &sig = m.sigs.last(); + sig.name = s.name.c_str(); + sig.start_bit = s.start_bit; + sig.msb = s.msb; + sig.lsb = s.lsb; + sig.size = s.size; + sig.is_signed = s.is_signed; + sig.factor = s.factor; + sig.offset = s.offset; + sig.is_little_endian = s.is_little_endian; + } + } + parseExtraInfo(content); + name_ = name; + emit DBCFileChanged(); + delete dbc; + } catch (std::exception &e) { + if (error) *error = e.what(); + return false; + } + return true; +} + void DBCManager::parseExtraInfo(const QString &content) { static QRegularExpression bo_regexp(R"(^BO_ (\w+) (\w+) *: (\w+) (\w+))"); static QRegularExpression sg_regexp(R"(^SG_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sgm_regexp(R"(^SG_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*))"); static QRegularExpression sg_comment_regexp(R"(^CM_ SG_ *(\w+) *(\w+) *\"(.*)\";)"); static QRegularExpression val_regexp(R"(VAL_ (\w+) (\w+) (.*);)"); - auto get_sig = [this](uint32_t address, const QString &name) -> Signal * { - auto m = (Msg *)msg(address); - return m ? (Signal *)m->sig(name) : nullptr; + auto get_sig = [this](uint32_t address, const QString &name) -> cabana::Signal * { + auto m = (cabana::Msg *)msg(address); + return m ? (cabana::Signal *)m->sig(name) : nullptr; }; QTextStream stream((QString *)&content); @@ -119,17 +151,17 @@ void DBCManager::removeMsg(const MessageId &id) { emit msgRemoved(id.address); } -void DBCManager::addSignal(const MessageId &id, const Signal &sig) { - if (auto m = const_cast(msg(id.address))) { +void DBCManager::addSignal(const MessageId &id, const cabana::Signal &sig) { + if (auto m = const_cast(msg(id.address))) { m->sigs.push_back(sig); auto s = &m->sigs.last(); emit signalAdded(id.address, s); } } -void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig) { - if (auto m = const_cast(msg(id))) { - if (auto s = (Signal *)m->sig(sig_name)) { +void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig) { + if (auto m = const_cast(msg(id))) { + if (auto s = (cabana::Signal *)m->sig(sig_name)) { *s = sig; emit signalUpdated(s); } @@ -137,7 +169,7 @@ void DBCManager::updateSignal(const MessageId &id, const QString &sig_name, cons } void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { - if (auto m = const_cast(msg(id))) { + if (auto m = const_cast(msg(id))) { auto it = std::find_if(m->sigs.begin(), m->sigs.end(), [&](auto &s) { return s.name == sig_name; }); if (it != m->sigs.end()) { emit signalRemoved(&(*it)); @@ -151,117 +183,3 @@ DBCManager *dbc() { return &dbc_manager; } -// Msg - -std::vector Msg::getSignals() const { - std::vector ret; - ret.reserve(sigs.size()); - for (auto &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 = []() { - QVector ret; - for (int i = 0; i < 64; i++) - for (int j = 7; j >= 0; j--) - ret.push_back(j + i * 8); - return ret; -}(); - -int bigEndianStartBitsIndex(int start_bit) { return BIG_ENDIAN_START_BITS[start_bit]; } -int bigEndianBitIndex(int index) { return BIG_ENDIAN_START_BITS.indexOf(index); } - -double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig) { - int64_t val = 0; - - int i = sig.msb / 8; - int bits = sig.size; - while (i >= 0 && i < data_size && bits > 0) { - int lsb = (int)(sig.lsb / 8) == i ? sig.lsb : i * 8; - int msb = (int)(sig.msb / 8) == i ? sig.msb : (i + 1) * 8 - 1; - int size = msb - lsb + 1; - - uint64_t d = (data[i] >> (lsb - (i * 8))) & ((1ULL << size) - 1); - val |= d << (bits - size); - - bits -= size; - i = sig.is_little_endian ? i - 1 : i + 1; - } - if (sig.is_signed) { - val -= ((val >> (sig.size - 1)) & 0x1) ? (1ULL << sig.size) : 0; - } - return val * sig.factor + sig.offset; -} - -void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size) { - s.start_bit = s.is_little_endian ? start_bit : bigEndianBitIndex(start_bit); - s.size = size; - if (s.is_little_endian) { - s.lsb = s.start_bit; - s.msb = s.start_bit + s.size - 1; - } else { - s.lsb = bigEndianStartBitsIndex(bigEndianBitIndex(s.start_bit) + s.size - 1); - s.msb = s.start_bit; - } -} - -std::pair getSignalRange(const Signal *s) { - int from = s->is_little_endian ? s->start_bit : bigEndianBitIndex(s->start_bit); - int to = from + s->size - 1; - return {from, to}; -} - -bool operator==(const Signal &l, const Signal &r) { - return l.name == r.name && l.size == r.size && - l.start_bit == r.start_bit && - l.msb == r.msb && l.lsb == r.lsb && - l.is_signed == r.is_signed && l.is_little_endian == r.is_little_endian && - l.factor == r.factor && l.offset == r.offset && - l.min == r.min && l.max == r.max && l.comment == r.comment && l.unit == r.unit && l.val_desc == r.val_desc; -} - -} // namespace dbcmanager - -#include "opendbc/can/common_dbc.h" -std::vector dbcmanager::DBCManager::allDBCNames() { return get_dbc_names(); } - -bool dbcmanager::DBCManager::open(const QString &name, const QString &content, QString *error) { - try { - std::istringstream stream(content.toStdString()); - auto dbc = const_cast(dbc_parse_from_stream(name.toStdString(), stream)); - msgs.clear(); - for (auto &msg : dbc->msgs) { - auto &m = msgs[msg.address]; - m.name = msg.name.c_str(); - m.size = msg.size; - for (auto &s : msg.sigs) { - m.sigs.push_back({}); - auto &sig = m.sigs.last(); - sig.name = s.name.c_str(); - sig.start_bit = s.start_bit; - sig.msb = s.msb; - sig.lsb = s.lsb; - sig.size = s.size; - sig.is_signed = s.is_signed; - sig.factor = s.factor; - sig.offset = s.offset; - sig.is_little_endian = s.is_little_endian; - } - } - parseExtraInfo(content); - name_ = name; - emit DBCFileChanged(); - delete dbc; - } catch (std::exception &e) { - if (error) *error = e.what(); - return false; - } - return true; -} - -uint qHash(const MessageId &item) { - return qHash(item.source) ^ qHash(item.address); -} diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index d877347796..3b222b1dcb 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -6,63 +6,7 @@ #include #include -struct MessageId { - uint8_t source; - uint32_t address; - - QString toString() const { - return QString("%1:%2").arg(source).arg(address, 1, 16); - } - - bool operator==(const MessageId &other) const { - return source == other.source && address == other.address; - } - - bool operator!=(const MessageId &other) const { - return !(*this == other); - } - - bool operator<(const MessageId &other) const { - return std::pair{source, address} < std::pair{other.source, other.address}; - } - - bool operator>(const MessageId &other) const { - return std::pair{source, address} > std::pair{other.source, other.address}; - } -}; - -uint qHash(const MessageId &item); -Q_DECLARE_METATYPE(MessageId); - -namespace dbcmanager { - -typedef QList> ValueDescription; - -struct Signal { - QString name; - int start_bit, msb, lsb, size; - bool is_signed; - double factor, offset; - bool is_little_endian; - QString min, max, unit; - QString comment; - ValueDescription val_desc; -}; - -struct Msg { - QString name; - uint32_t size; - - std::vector getSignals() const; - const Signal *sig(const QString &sig_name) const { - auto it = std::find_if(sigs.begin(), sigs.end(), [&](auto &s) { return s.name == sig_name; }); - return it != sigs.end() ? &(*it) : nullptr; - } - -private: - QList sigs; - friend class DBCManager; -}; +#include "tools/cabana/dbc.h" class DBCManager : public QObject { Q_OBJECT @@ -73,49 +17,37 @@ public: bool open(const QString &dbc_file_name, QString *error = nullptr); bool open(const QString &name, const QString &content, QString *error = nullptr); QString generateDBC(); - void addSignal(const MessageId &id, const Signal &sig); - void updateSignal(const MessageId &id, const QString &sig_name, const Signal &sig); + void addSignal(const MessageId &id, const cabana::Signal &sig); + void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig); void removeSignal(const MessageId &id, const QString &sig_name); - static std::vector allDBCNames(); inline QString name() const { return name_; } void updateMsg(const MessageId &id, const QString &name, uint32_t size); void removeMsg(const MessageId &id); - inline const std::map &messages() const { return msgs; } - inline const Msg *msg(const MessageId &id) const { return msg(id.address); } - inline const Msg *msg(uint32_t address) const { + inline const std::map &messages() const { return msgs; } + inline const cabana::Msg *msg(const MessageId &id) const { return msg(id.address); } + inline const cabana::Msg *msg(uint32_t address) const { auto it = msgs.find(address); return it != msgs.end() ? &it->second : nullptr; } signals: - void signalAdded(uint32_t address, const Signal *sig); - void signalRemoved(const Signal *sig); - void signalUpdated(const Signal *sig); + void signalAdded(uint32_t address, const cabana::Signal *sig); + void signalRemoved(const cabana::Signal *sig); + void signalUpdated(const cabana::Signal *sig); void msgUpdated(uint32_t address); void msgRemoved(uint32_t address); void DBCFileChanged(); private: void parseExtraInfo(const QString &content); - std::map msgs; + std::map msgs; QString name_; }; -const QString UNTITLED = "untitled"; - -// TODO: Add helper function in dbc.h -double get_raw_value(uint8_t *data, size_t data_size, const Signal &sig); -bool operator==(const Signal &l, const Signal &r); -inline bool operator!=(const Signal &l, const Signal &r) { return !(l == r); } -int bigEndianStartBitsIndex(int start_bit); -int bigEndianBitIndex(int index); -void updateSigSizeParamsFromRange(Signal &s, int start_bit, int size); -std::pair getSignalRange(const Signal *s); DBCManager *dbc(); + inline QString msgName(const MessageId &id) { auto msg = dbc()->msg(id); return msg ? msg->name : UNTITLED; } - -} // namespace dbcmanager diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 71dbf8d56b..05a0528d0e 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -68,7 +68,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart QObject::connect(binary_view, &BinaryView::resizeSignal, signal_view->model, &SignalModel::resizeSignal); QObject::connect(binary_view, &BinaryView::addSignal, signal_view->model, &SignalModel::addSignal); QObject::connect(binary_view, &BinaryView::signalHovered, signal_view, &SignalView::signalHovered); - QObject::connect(binary_view, &BinaryView::signalClicked, [this](const Signal *s) { signal_view->selectSignal(s, true); }); + QObject::connect(binary_view, &BinaryView::signalClicked, [this](const cabana::Signal *s) { signal_view->selectSignal(s, true); }); QObject::connect(binary_view, &BinaryView::editSignal, signal_view->model, &SignalModel::saveSignal); QObject::connect(binary_view, &BinaryView::removeSignal, signal_view->model, &SignalModel::removeSignal); QObject::connect(binary_view, &BinaryView::showChart, charts, &ChartsWidget::showChart); diff --git a/tools/cabana/historylog.h b/tools/cabana/historylog.h index 206d53bc8d..119b61a0e8 100644 --- a/tools/cabana/historylog.h +++ b/tools/cabana/historylog.h @@ -11,8 +11,6 @@ #include "tools/cabana/streams/abstractstream.h" #include "tools/cabana/util.h" -using namespace dbcmanager; - class HeaderView : public QHeaderView { public: HeaderView(Qt::Orientation orientation, QWidget *parent = nullptr) : QHeaderView(orientation, parent) {} @@ -64,7 +62,7 @@ public: uint64_t last_fetch_time = 0; std::function filter_cmp = nullptr; std::deque messages; - std::vector sigs; + std::vector sigs; bool dynamic_mode = true; bool display_signals_mode = true; }; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index abcb4948a9..17b720bd55 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -97,7 +97,7 @@ void MainWindow::createActions() { file_menu->addSeparator(); QMenu *load_opendbc_menu = file_menu->addMenu(tr("Load DBC from commaai/opendbc")); // load_opendbc_menu->setStyleSheet("QMenu { menu-scrollable: true; }"); - auto dbc_names = dbc()->allDBCNames(); + auto dbc_names = allDBCNames(); std::sort(dbc_names.begin(), dbc_names.end()); for (const auto &name : dbc_names) { load_opendbc_menu->addAction(QString::fromStdString(name), this, &MainWindow::openOpendbcFile); diff --git a/tools/cabana/messageswidget.h b/tools/cabana/messageswidget.h index ed9e241b0c..08dac0d69a 100644 --- a/tools/cabana/messageswidget.h +++ b/tools/cabana/messageswidget.h @@ -8,7 +8,6 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; class MessageListModel : public QAbstractTableModel { Q_OBJECT diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 5684edf95a..8c28d92437 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -22,7 +22,7 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p QObject::connect(can, &AbstractStream::msgsReceived, this, &SignalModel::updateState); } -void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig) { +void SignalModel::insertItem(SignalModel::Item *parent_item, int pos, const cabana::Signal *sig) { Item *item = new Item{.sig = sig, .parent = parent_item, .title = sig->name, .type = Item::Sig}; parent_item->children.insert(pos, item); QString titles[]{"Name", "Size", "Little Endian", "Signed", "Offset", "Factor", "Extra Info", "Unit", "Comment", "Minimum Value", "Maximum Value", "Value Descriptions"}; @@ -104,7 +104,7 @@ Qt::ItemFlags SignalModel::flags(const QModelIndex &index) const { return flags; } -int SignalModel::signalRow(const Signal *sig) const { +int SignalModel::signalRow(const cabana::Signal *sig) const { for (int i = 0; i < root->children.size(); ++i) { if (root->children[i]->sig == sig) return i; } @@ -168,7 +168,7 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r if (role != Qt::EditRole && role != Qt::CheckStateRole) return false; Item *item = getItem(index); - Signal s = *item->sig; + cabana::Signal s = *item->sig; switch (item->type) { case Item::Name: s.name = value.toString(); break; case Item::Size: s.size = value.toInt(); break; @@ -203,7 +203,7 @@ void SignalModel::showExtraInfo(const QModelIndex &index) { } } -bool SignalModel::saveSignal(const Signal *origin_s, Signal &s) { +bool SignalModel::saveSignal(const cabana::Signal *origin_s, cabana::Signal &s) { auto msg = dbc()->msg(msg_id); if (s.name != origin_s->name && msg->sig(s.name) != nullptr) { QString text = tr("There is already a signal with the same name '%1'").arg(s.name); @@ -243,7 +243,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { } } - Signal sig = {.is_little_endian = little_endian, .factor = 1}; + cabana::Signal sig = {.is_little_endian = little_endian, .factor = 1}; for (int i = 1; /**/; ++i) { sig.name = QString("NEW_SIGNAL_%1").arg(i); if (msg->sig(sig.name) == nullptr) break; @@ -252,13 +252,13 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { UndoStack::push(new AddSigCommand(msg_id, sig)); } -void SignalModel::resizeSignal(const Signal *sig, int start_bit, int size) { - Signal s = *sig; +void SignalModel::resizeSignal(const cabana::Signal *sig, int start_bit, int size) { + cabana::Signal s = *sig; updateSigSizeParamsFromRange(s, start_bit, size); saveSignal(sig, s); } -void SignalModel::removeSignal(const Signal *sig) { +void SignalModel::removeSignal(const cabana::Signal *sig) { UndoStack::push(new RemoveSigCommand(msg_id, sig)); } @@ -268,7 +268,7 @@ void SignalModel::handleMsgChanged(uint32_t address) { } } -void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) { +void SignalModel::handleSignalAdded(uint32_t address, const cabana::Signal *sig) { if (address == msg_id.address) { int i = 0; for (; i < root->children.size(); ++i) { @@ -280,13 +280,13 @@ void SignalModel::handleSignalAdded(uint32_t address, const Signal *sig) { } } -void SignalModel::handleSignalUpdated(const Signal *sig) { +void SignalModel::handleSignalUpdated(const cabana::Signal *sig) { if (int row = signalRow(sig); row != -1) { emit dataChanged(index(row, 0), index(row, 1), {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole}); } } -void SignalModel::handleSignalRemoved(const Signal *sig) { +void SignalModel::handleSignalRemoved(const cabana::Signal *sig) { if (int row = signalRow(sig); row != -1) { beginRemoveRows({}, row, row); delete root->children.takeAt(row); @@ -431,7 +431,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); - QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const Signal *sig) { selectSignal(sig); }); + QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const cabana::Signal *sig) { selectSignal(sig); }); setWhatsThis(tr(R"( Signal view
@@ -485,7 +485,7 @@ void SignalView::rowClicked(const QModelIndex &index) { } } -void SignalView::selectSignal(const Signal *sig, bool expand) { +void SignalView::selectSignal(const cabana::Signal *sig, bool expand) { if (int row = model->signalRow(sig); row != -1) { auto idx = model->index(row, 0); if (expand) { @@ -509,7 +509,7 @@ void SignalView::updateChartState() { } } -void SignalView::signalHovered(const Signal *sig) { +void SignalView::signalHovered(const cabana::Signal *sig) { auto &children = model->root->children; for (int i = 0; i < children.size(); ++i) { bool highlight = children[i]->sig == sig; diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index da3bc36c62..39fe5f270f 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -21,7 +21,7 @@ public: Item *parent = nullptr; QList children; - const Signal *sig = nullptr; + const cabana::Signal *sig = nullptr; QString title; bool highlight = false; bool extra_expanded = false; @@ -39,18 +39,18 @@ public: void setMessage(const MessageId &id); void setFilter(const QString &txt); void addSignal(int start_bit, int size, bool little_endian); - bool saveSignal(const Signal *origin_s, Signal &s); - void resizeSignal(const Signal *sig, int start_bit, int size); - void removeSignal(const Signal *sig); + bool saveSignal(const cabana::Signal *origin_s, cabana::Signal &s); + void resizeSignal(const cabana::Signal *sig, int start_bit, int size); + void removeSignal(const cabana::Signal *sig); Item *getItem(const QModelIndex &index) const; - int signalRow(const Signal *sig) const; + int signalRow(const cabana::Signal *sig) const; void showExtraInfo(const QModelIndex &index); private: - void insertItem(SignalModel::Item *parent_item, int pos, const Signal *sig); - void handleSignalAdded(uint32_t address, const Signal *sig); - void handleSignalUpdated(const Signal *sig); - void handleSignalRemoved(const Signal *sig); + void insertItem(SignalModel::Item *parent_item, int pos, const cabana::Signal *sig); + void handleSignalAdded(uint32_t address, const cabana::Signal *sig); + void handleSignalUpdated(const cabana::Signal *sig); + void handleSignalRemoved(const cabana::Signal *sig); void handleMsgChanged(uint32_t address); void refresh(); void updateState(const QHash *msgs); @@ -94,15 +94,15 @@ class SignalView : public QFrame { public: SignalView(ChartsWidget *charts, QWidget *parent); void setMessage(const MessageId &id); - void signalHovered(const Signal *sig); + void signalHovered(const cabana::Signal *sig); void updateChartState(); - void selectSignal(const Signal *sig, bool expand = false); + void selectSignal(const cabana::Signal *sig, bool expand = false); void rowClicked(const QModelIndex &index); SignalModel *model = nullptr; signals: - void highlight(const Signal *sig); - void showChart(const MessageId &id, const Signal *sig, bool show, bool merge); + void highlight(const cabana::Signal *sig); + void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge); private: void rowsChanged(); diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 6f9f2d016b..124eb7428a 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -5,7 +5,6 @@ #include "tools/replay/logreader.h" #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; // demo route, first segment const std::string TEST_RLOG_URL = "https://commadata2.blob.core.windows.net/commadata2/4cf7a6ad03080c90/2021-09-29--13-46-36/0/rlog.bz2"; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 27cb7bced8..ffb0e54b0e 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -9,7 +9,6 @@ #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::WindowFlags() | Qt::Window) { setWindowTitle(tr("Find similar bits")); diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index ba9b063baf..53d7806a8f 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -7,7 +7,6 @@ #include #include "tools/cabana/dbcmanager.h" -using namespace dbcmanager; class FindSimilarBitsDlg : public QDialog { Q_OBJECT diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 778ffbc859..656c97489c 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -128,7 +128,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & } } -QColor getColor(const Signal *sig) { +QColor getColor(const cabana::Signal *sig) { float h = 19 * (float)sig->lsb / 64.0; h = fmod(h, 1.0); diff --git a/tools/cabana/util.h b/tools/cabana/util.h index cf1b5d4b20..03732ee13f 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -11,8 +11,7 @@ #include #include -#include "tools/cabana/dbcmanager.h" -using namespace dbcmanager; +#include "tools/cabana/dbc.h" class ChangeTracker { public: @@ -59,7 +58,7 @@ public: inline QString toHex(const QByteArray &dat) { return dat.toHex(' ').toUpper(); } QString toHex(uint8_t byte); -QColor getColor(const dbcmanager::Signal *sig); +QColor getColor(const cabana::Signal *sig); class NameValidator : public QRegExpValidator { Q_OBJECT diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 1a7e27f1b3..d10b09fec5 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -13,7 +13,6 @@ #include "selfdrive/ui/qt/widgets/controls.h" #include "tools/cabana/dbcmanager.h" #include "tools/cabana/streams/abstractstream.h" -using namespace dbcmanager; class Slider : public QSlider { Q_OBJECT From c32a45b5b59396d7c7b90ede8db4e8ad678f39c5 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 10 Mar 2023 20:20:59 +0100 Subject: [PATCH 1072/1179] cabana: autocomplete signal names (#27553) --- tools/cabana/dbcmanager.cc | 13 +++++++++++++ tools/cabana/dbcmanager.h | 1 + tools/cabana/signaledit.cc | 9 +++++++++ 3 files changed, 23 insertions(+) diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index e9ebcd2791..b3a90e0b70 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -178,6 +178,19 @@ void DBCManager::removeSignal(const MessageId &id, const QString &sig_name) { } } +QStringList DBCManager::signalNames() { + // Used for autocompletion + QStringList ret; + for (auto const& [_, msg] : msgs) { + for (auto sig: msg.getSignals()) { + ret << sig->name; + } + } + ret.sort(); + ret.removeDuplicates(); + return ret; +} + DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 3b222b1dcb..4be7593808 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -30,6 +30,7 @@ public: auto it = msgs.find(address); return it != msgs.end() ? &it->second : nullptr; } + QStringList signalNames(); signals: void signalAdded(uint32_t address, const cabana::Signal *sig); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 8c28d92437..5fb56dc1bc 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -1,6 +1,7 @@ #include "tools/cabana/signaledit.h" #include +#include #include #include #include @@ -368,6 +369,14 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie QLineEdit *e = new QLineEdit(parent); e->setFrame(false); e->setValidator(index.row() == 0 ? name_validator : double_validator); + + if (item->type == SignalModel::Item::Name) { + QCompleter *completer = new QCompleter(dbc()->signalNames()); + completer->setCaseSensitivity(Qt::CaseInsensitive); + completer->setFilterMode(Qt::MatchContains); + e->setCompleter(completer); + } + return e; } else if (item->type == SignalModel::Item::Size) { QSpinBox *spin = new QSpinBox(parent); From ee615a30775c56be2c13a4acb4a755072000b8d6 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 10 Mar 2023 20:21:34 +0100 Subject: [PATCH 1073/1179] cabana: create autosave file when there are unsaved changes (#27542) --- tools/cabana/mainwin.cc | 31 ++++++++++++++++++++++++++++++- tools/cabana/mainwin.h | 4 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 17b720bd55..1559700951 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -214,6 +214,7 @@ void MainWindow::undoStackIndexChanged(int index) { } prev_undostack_index = index; prev_undostack_count = count; + autoSave(); } void MainWindow::undoStackCleanChanged(bool clean) { @@ -255,7 +256,18 @@ void MainWindow::openFile() { void MainWindow::loadFile(const QString &fn) { if (!fn.isEmpty()) { - QFile file(fn); + QString dbc_fn = fn; + + // Prompt user to load auto saved file if it exists. + if (QFile::exists(fn + AUTO_SAVE_EXTENSION)) { + auto ret = QMessageBox::question(this, tr("Auto saved DBC found"), tr("Auto saved DBC file from previous session found. Do you want to load it instead?")); + if (ret == QMessageBox::Yes) { + dbc_fn += AUTO_SAVE_EXTENSION; + UndoStack::instance()->resetClean(); // Force user to save on close so the auto saved file is not lost + } + } + + QFile file(dbc_fn); if (file.open(QIODevice::ReadOnly)) { auto dbc_name = QFileInfo(fn).baseName(); QString error; @@ -340,7 +352,23 @@ void MainWindow::save() { } } +void MainWindow::autoSave() { + if (!current_file.isEmpty() && !UndoStack::instance()->isClean()) { + QFile file(current_file + AUTO_SAVE_EXTENSION); + if (file.open(QIODevice::WriteOnly)) { + file.write(dbc()->generateDBC().toUtf8()); + } + } +} + +void MainWindow::cleanupAutoSaveFile() { + if (!current_file.isEmpty()) { + QFile::remove(current_file + AUTO_SAVE_EXTENSION); + } +} + void MainWindow::saveFile(const QString &fn) { + cleanupAutoSaveFile(); QFile file(fn); if (file.open(QIODevice::WriteOnly)) { file.write(dbc()->generateDBC().toUtf8()); @@ -445,6 +473,7 @@ void MainWindow::dockCharts(bool dock) { } void MainWindow::closeEvent(QCloseEvent *event) { + cleanupAutoSaveFile(); remindSaveChanges(); main_win = nullptr; diff --git a/tools/cabana/mainwin.h b/tools/cabana/mainwin.h index 1c21d69370..3258b95cde 100644 --- a/tools/cabana/mainwin.h +++ b/tools/cabana/mainwin.h @@ -13,6 +13,8 @@ #include "tools/cabana/videowidget.h" #include "tools/cabana/tools/findsimilarbits.h" +const QString AUTO_SAVE_EXTENSION = ".tmp"; + class MainWindow : public QMainWindow { Q_OBJECT @@ -42,6 +44,8 @@ signals: protected: void remindSaveChanges(); void saveFile(const QString &fn); + void autoSave(); + void cleanupAutoSaveFile(); void setCurrentFile(const QString &fn); void updateRecentFileActions(); void createActions(); From 0fb8e974801b3a9fc664076830a8595a752d5c87 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Fri, 10 Mar 2023 22:29:11 +0100 Subject: [PATCH 1074/1179] cabana: use ID as NEW_MSG_ suffix (#27554) * cabana: use ID as NEW_MSG_ suffix * start suffix at _1 --- tools/cabana/signaledit.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 5fb56dc1bc..ced7cd7d24 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -236,8 +236,9 @@ bool SignalModel::saveSignal(const cabana::Signal *origin_s, cabana::Signal &s) void SignalModel::addSignal(int start_bit, int size, bool little_endian) { auto msg = dbc()->msg(msg_id); - for (int i = 1; !msg; ++i) { - QString name = QString("NEW_MSG_%1").arg(i); + for (int i = 0; !msg; ++i) { + QString name = QString("NEW_MSG_") + QString::number(msg_id.address, 16).toUpper(); + if (i > 0) name += QString("_%1").arg(i); if (std::none_of(dbc()->messages().begin(), dbc()->messages().end(), [&](auto &m) { return m.second.name == name; })) { UndoStack::push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size())); msg = dbc()->msg(msg_id); From dc5a65049ef93cd0c342d32cc5eecef32e0bb145 Mon Sep 17 00:00:00 2001 From: protonchang <2095341+protonchang@users.noreply.github.com> Date: Sat, 11 Mar 2023 07:39:16 +0800 Subject: [PATCH 1075/1179] Update CHT translation (#27530) * Update zh-CHT translation * Update zh-CHT translation * Update zh-CHT Translation * Update to resolve translation consistency issue * Update zh-CHT translation --- selfdrive/ui/translations/main_zh-CHT.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index e4058ee0db..83db0b7301 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -200,7 +200,7 @@
openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. - openpilot 需要將裝置固定在左右偏差 4° 以內,朝上偏差 5° 以内或朝下偏差 8° 以内。鏡頭在後台會持續自動校準,很少有需要重置的情况。 + openpilot 需要將設備固定在左右偏差 4° 以內,朝上偏差 5° 以内或朝下偏差 8° 以内。鏡頭在後台會持續自動校準,很少有需要重置的情况。 Your device is pointed %1° %2 and %3° %4. @@ -592,16 +592,16 @@ location set Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - + 無法掛載資料分割區 分割區可能已經毀損 請確認是否要刪除並重新設定 Press confirm to erase all content and settings. Press cancel to resume boot. - + 按下確認以刪除所有內容及設定 按下取消來繼續開機 Resetting device... This may take up to a minute. - + 設備重置中 此過程可能需要幾分鐘
@@ -703,11 +703,11 @@ This may take up to a minute. No custom software found at this URL. - + 無法在此URL找到定制的軟體 Something went wrong. Reboot the device. - + 發生了一些錯誤 請重新啟動您的設備 @@ -1028,11 +1028,11 @@ This may take up to a minute. openpilot longitudinal control may come in a future update. - + 未來可能會推出openpilot縱向控制 An experimental version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - + 在非發行分支中 可找到包含實驗模式的openpilot縱向控制測試版本 Enable experimental longitudinal control to allow Experimental mode. From eb67deef92be8af17596c08e9f98c240fc7d23e3 Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Fri, 10 Mar 2023 17:43:18 -0600 Subject: [PATCH 1076/1179] Add missing LEXUS_ESH_TSS2 engine f/w (#27506) `awesome-fu#6174` 2019 Lexus ES300h DongleID/route e5fc06c3b27fb519|2023-03-05--17-21-28 https://github.com/commaai/openpilot/issues/27501 --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 35e2db8b1e..a8e143e80a 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1637,6 +1637,7 @@ FW_VERSIONS = { b'\x028966333S8000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966333T0100\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x028966333V4000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', + b'\x028966333W1000\x00\x00\x00\x00897CF3305001\x00\x00\x00\x00', b'\x02896633T09000\x00\x00\x00\x00897CF3307001\x00\x00\x00\x00', b'\x01896633T38000\x00\x00\x00\x00', b'\x01896633T58000\x00\x00\x00\x00', From dc31c50aa7bda8d5aab43b0382342ae5162ed37d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 12 Mar 2023 04:47:34 +0800 Subject: [PATCH 1077/1179] cabana: split events into chunks and processed concurrently (#27562) --- tools/cabana/streams/abstractstream.cc | 56 ++++++++++++++++++-------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 3e631d3709..6af831a1d0 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,5 +1,7 @@ #include "tools/cabana/streams/abstractstream.h" +#include + AbstractStream *can = nullptr; AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_live_streaming(is_live_streaming), QObject(parent) { @@ -59,39 +61,59 @@ const CanData &AbstractStream::lastMessage(const MessageId &id) { return it != can_msgs.end() ? it.value() : empty_data; } -void AbstractStream::updateLastMsgsTo(double sec) { - QHash last_msgs; - last_msgs.reserve(can_msgs.size()); - double route_start_time = routeStartTime(); - uint64_t last_ts = (sec + route_start_time) * 1e9; - auto evs = events(); - auto last = std::upper_bound(evs->rbegin(), evs->rend(), last_ts, [](uint64_t ts, auto &e) { return e->mono_time < ts; }); - for (auto it = last; it != evs->rend(); ++it) { +static QHash parseEvents(std::vector::const_reverse_iterator first, + std::vector::const_reverse_iterator last, double route_start_time) { + QHash msgs; + msgs.reserve(500); + for (auto it = first; it != last; ++it) { if ((*it)->which == cereal::Event::Which::CAN) { for (const auto &c : (*it)->event.getCan()) { - auto &m = last_msgs[{.source = c.getSrc(), .address = c.getAddress()}]; + auto &m = msgs[{.source = c.getSrc(), .address = c.getAddress()}]; if (++m.count == 1) { m.ts = ((*it)->mono_time / 1e9) - route_start_time; m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); m.last_change_t = QVector(m.dat.size(), m.ts); m.bit_change_counts.resize(m.dat.size()); - } else { - m.freq = m.count / std::max(1.0, m.ts); } } } } + return msgs; +}; + +// it is thread safe to update data in updateLastMsgsTo. +// updateEvent will not be called before replayStream::seekedTo return. +void AbstractStream::updateLastMsgsTo(double sec) { + uint64_t ts = (sec + routeStartTime()) * 1e9; + const uint64_t delta = std::max(std::ceil(sec / std::thread::hardware_concurrency()), 30.0) * 1e9; + const auto evs = events(); + auto first = std::upper_bound(evs->crbegin(), evs->crend(), ts, [](uint64_t ts, auto &e) { return ts > e->mono_time; }); + QFutureSynchronizer> synchronizer; + while(first != evs->crend()) { + ts = (*first)->mono_time > delta ? (*first)->mono_time - delta : 0; + auto last = std::lower_bound(first, evs->crend(), ts, [](auto &e, uint64_t ts) { return e->mono_time > ts; }); + synchronizer.addFuture(QtConcurrent::run(parseEvents, first, last, routeStartTime())); + first = last; + } + synchronizer.waitForFinished(); - // it is thread safe to update data here. - // updateEvent will not be called before replayStream::seekedTo return. new_msgs->clear(); change_trackers.clear(); - counters.clear(); can_msgs.clear(); - for (auto it = last_msgs.cbegin(); it != last_msgs.cend(); ++it) { - can_msgs[it.key()] = it.value(); - counters[it.key()] = it.value().count; + counters.clear(); + for (const auto &f : synchronizer.futures()) { + auto msgs = f.result(); + for (auto it = msgs.cbegin(); it != msgs.cend(); ++it) { + counters[it.key()] += it.value().count; + auto m = can_msgs.find(it.key()); + if (m == can_msgs.end()) { + m = can_msgs.insert(it.key(), it.value()); + } else { + m.value().count += it.value().count; + } + m.value().freq = m.value().count / std::max(1.0, m.value().ts); + } } emit updated(); emit msgsReceived(&can_msgs); From fc44ed63d78c3b45020db1130dae41f597c91e18 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Sat, 11 Mar 2023 21:47:53 +0100 Subject: [PATCH 1078/1179] cabana: extend max chart range to 30 minutes (#27555) --- tools/cabana/chartswidget.cc | 4 ++-- tools/cabana/chartswidget.h | 2 +- tools/cabana/settings.cc | 2 +- tools/cabana/settings.h | 2 +- tools/cabana/util.h | 18 ++++++++++++++++++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 5bab261ba7..c0432d0c09 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -45,7 +45,7 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { toolbar->addWidget(stretch_label); range_lb_action = toolbar->addWidget(range_lb = new QLabel(this)); - range_slider = new QSlider(Qt::Horizontal, this); + range_slider = new LogSlider(1000, Qt::Horizontal, this); range_slider->setMaximumWidth(200); range_slider->setToolTip(tr("Set the chart range")); range_slider->setRange(1, settings.max_cached_minutes * 60); @@ -163,7 +163,7 @@ void ChartsWidget::updateState() { } void ChartsWidget::setMaxChartRange(int value) { - max_chart_range = settings.chart_range = value; + max_chart_range = settings.chart_range = range_slider->value(); updateToolBar(); updateState(); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index fdfbbc11ff..adce1e0f4d 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -137,7 +137,7 @@ private: QLabel *title_label; QLabel *range_lb; - QSlider *range_slider; + LogSlider *range_slider; QAction *range_lb_action; QAction *range_slider_action; bool docking = true; diff --git a/tools/cabana/settings.cc b/tools/cabana/settings.cc index 23f001efff..00bbb94de5 100644 --- a/tools/cabana/settings.cc +++ b/tools/cabana/settings.cc @@ -32,7 +32,7 @@ void Settings::save() { void Settings::load() { QSettings s("settings", QSettings::IniFormat); fps = s.value("fps", 10).toInt(); - max_cached_minutes = s.value("max_cached_minutes", 5).toInt(); + max_cached_minutes = s.value("max_cached_minutes", 30).toInt(); chart_height = s.value("chart_height", 200).toInt(); chart_range = s.value("chart_range", 3 * 60).toInt(); chart_column_count = s.value("chart_column_count", 1).toInt(); diff --git a/tools/cabana/settings.h b/tools/cabana/settings.h index a302d20077..c3ba906576 100644 --- a/tools/cabana/settings.h +++ b/tools/cabana/settings.h @@ -14,7 +14,7 @@ public: void load(); int fps = 10; - int max_cached_minutes = 5; + int max_cached_minutes = 30; int chart_height = 200; int chart_column_count = 1; int chart_range = 3 * 60; // e minutes diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 03732ee13f..b1acdd8c6e 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -29,6 +30,23 @@ private: QByteArray prev_dat; }; +class LogSlider : public QSlider { + Q_OBJECT + +public: + LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {}; + + void setRange(double min, double max) { QSlider::setRange(logScale(min), logScale(max)); } + int value() const { return invLogScale(QSlider::value()); } + void setValue(int value) { QSlider::setValue(logScale(value)); } + +private: + double factor; + int logScale(int value) const { return factor * std::log10(value); } + int invLogScale(int value) const { return std::pow(10, value / factor); } +}; + + enum { ColorsRole = Qt::UserRole + 1, BytesRole = Qt::UserRole + 2 From e146bb1a96e98e2dc3d9b777a259044e73a9a633 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Sat, 11 Mar 2023 16:26:39 -0800 Subject: [PATCH 1079/1179] update modeld/models readme (#27564) * update readme with new model design * typo * space --- selfdrive/modeld/models/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/selfdrive/modeld/models/README.md b/selfdrive/modeld/models/README.md index 6b704cbfa8..1bfca8e95a 100644 --- a/selfdrive/modeld/models/README.md +++ b/selfdrive/modeld/models/README.md @@ -2,7 +2,7 @@ To view the architecture of the ONNX networks, you can use [netron](https://netron.app/) ## Supercombo -### Supercombo input format (Full size: 393738 x float32) +### Supercombo input format (Full size: 799906 x float32) * **image stream** * Two consecutive images (256 * 512 * 3 in RGB) recorded at 20 Hz : 393216 = 2 * 6 * 128 * 256 * Each 256 * 512 image is represented in YUV420 with 6 channels : 6 * 128 * 256 @@ -16,11 +16,11 @@ To view the architecture of the ONNX networks, you can use [netron](https://netr * Channel 4 represents the half-res U channel * Channel 5 represents the half-res V channel * **desire** - * one-hot encoded vector to command model to execute certain actions, bit only needs to be sent for 1 frame : 8 + * one-hot encoded buffer to command model to execute certain actions, bit needs to be sent for the past 5 seconds (at 20FPS) : 100 * 8 * **traffic convention** * one-hot encoded vector to tell model whether traffic is right-hand or left-hand traffic : 2 -* **recurrent state** - * The recurrent state vector that is fed back into the GRU for temporal context : 512 +* **feature buffer** + * A buffer of intermediate features that gets appended to the current feature to form a 5 seconds temporal context (at 20FPS) : 99 * 128 ### Supercombo output format (Full size: XXX x float32) From 3eb74d805a1d81722bb2b00105d584a11f8d5c9b Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:24:30 -0300 Subject: [PATCH 1080/1179] Update Directory Structure (#27569) * Update Directory Structure Update directory structure to the latest commits [ sensord: move to system/ (#27531) , loggerd: move to system/ (#27534) , ubloxd: move to system/ (#27536) ]. * Update README.md --------- Co-authored-by: Adeeb Shihadeh --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4896d9ff72..a71a9e671e 100755 --- a/README.md +++ b/README.md @@ -108,7 +108,10 @@ Directory Structure ├── clocksd # Broadcasts current time ├── hardware # Hardware abstraction classes ├── logcatd # systemd journal as a service - └── proclogd # Logs information from /proc + ├── loggerd # Logger and uploader of car data + ├── proclogd # Logs information from /proc + ├── sensord # IMU interface code + └── ubloxd # u-blox GNSS module interface code └── selfdrive # Code needed to drive the car ├── assets # Fonts, images, and sounds for UI ├── athena # Allows communication with the app @@ -117,12 +120,10 @@ Directory Structure ├── controls # Planning and controls ├── debug # Tools to help you debug and do car ports ├── locationd # Precise localization and vehicle parameter estimation - ├── loggerd # Logger and uploader of car data ├── manager # Daemon that starts/stops all other daemons as needed ├── modeld # Driving and monitoring model runners ├── monitoring # Daemon to determine driver attention ├── navd # Turn-by-turn navigation - ├── sensord # IMU interface code ├── test # Unit tests, system tests, and a car simulator └── ui # The UI From d09a9a08fc21edc03edeb40e1080d8495a7d2915 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Tue, 14 Mar 2023 01:25:16 +0800 Subject: [PATCH 1081/1179] cabana: fix hang on scrubbing in zommed chart (#27568) --- tools/cabana/chartswidget.cc | 10 ++++++---- tools/cabana/streams/abstractstream.cc | 8 +++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index c0432d0c09..f9661046c8 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -723,10 +723,12 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { void ChartView::mouseMoveEvent(QMouseEvent *ev) { // Scrubbing if (is_scrubbing && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { - double t = chart()->mapToValue({(double)ev->x(), (double)ev->y()}).x(); - // Prevent seeking past the end of the route - t = std::clamp(t, 0., can->totalSeconds()); - can->seekTo(t); + if (chart()->plotArea().contains(ev->pos())) { + double t = chart()->mapToValue(ev->pos()).x(); + // Prevent seeking past the end of the route + t = std::clamp(t, 0., can->totalSeconds()); + can->seekTo(t); + } return; } diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 6af831a1d0..40e9cbc8a5 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,5 +1,5 @@ #include "tools/cabana/streams/abstractstream.h" - +#include #include AbstractStream *can = nullptr; @@ -115,6 +115,8 @@ void AbstractStream::updateLastMsgsTo(double sec) { m.value().freq = m.value().count / std::max(1.0, m.value().ts); } } - emit updated(); - emit msgsReceived(&can_msgs); + QTimer::singleShot(0, [this]() { + emit updated(); + emit msgsReceived(&can_msgs); + }); } From 9ecf3e7c327e616fcdc65db73606f838f55bdaa5 Mon Sep 17 00:00:00 2001 From: Jason Young <46612682+jyoung8607@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:28:45 -0400 Subject: [PATCH 1082/1179] VW PQ: Message corrections for ACC_GRA_Anzeige (#27572) * VW PQ: Correct message name for ACC_GRA_Anzeige * bump opendbc --- opendbc | 2 +- selfdrive/car/volkswagen/carstate.py | 10 +++++----- selfdrive/car/volkswagen/pqcan.py | 2 +- selfdrive/car/volkswagen/values.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/opendbc b/opendbc index 510bfc0695..b7d4a6e271 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit 510bfc06954e31257f8d8de17adf92f9a68a1b71 +Subproject commit b7d4a6e2718d9ec3cf436441696528bedb1d44cf diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index 64d1246880..f3cd2808a8 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -228,13 +228,13 @@ class CarState(CarStateBase): ret.cruiseState.available = bool(pt_cp.vl["Motor_5"]["GRA_Hauptschalter"]) ret.cruiseState.enabled = pt_cp.vl["Motor_2"]["GRA_Status"] in (1, 2) if self.CP.pcmCruise: - ret.accFaulted = ext_cp.vl["ACC_GRA_Anziege"]["ACA_StaACC"] in (6, 7) + ret.accFaulted = ext_cp.vl["ACC_GRA_Anzeige"]["ACA_StaACC"] in (6, 7) else: ret.accFaulted = pt_cp.vl["Motor_2"]["GRA_Status"] == 3 # Update ACC setpoint. When the setpoint reads as 255, the driver has not # yet established an ACC setpoint, so treat it as zero. - ret.cruiseState.speed = ext_cp.vl["ACC_GRA_Anziege"]["ACA_V_Wunsch"] * CV.KPH_TO_MS + ret.cruiseState.speed = ext_cp.vl["ACC_GRA_Anzeige"]["ACA_V_Wunsch"] * CV.KPH_TO_MS if ret.cruiseState.speed > 70: # 255 kph in m/s == no current setpoint ret.cruiseState.speed = 0 @@ -516,12 +516,12 @@ class PqExtraSignals: # Additional signal and message lists for optional or bus-portable controllers fwd_radar_signals = [ ("ACS_Typ_ACC", "ACC_System"), # Basic vs FtS (no SnG support on PQ) - ("ACA_StaACC", "ACC_GRA_Anziege"), # ACC drivetrain coordinator status - ("ACA_V_Wunsch", "ACC_GRA_Anziege"), # ACC set speed + ("ACA_StaACC", "ACC_GRA_Anzeige"), # ACC drivetrain coordinator status + ("ACA_V_Wunsch", "ACC_GRA_Anzeige"), # ACC set speed ] fwd_radar_checks = [ ("ACC_System", 50), # From J428 ACC radar control module - ("ACC_GRA_Anziege", 25), # From J428 ACC radar control module + ("ACC_GRA_Anzeige", 25), # From J428 ACC radar control module ] bsm_radar_signals = [ ("SWA_Infostufe_SWA_li", "SWA_1"), # Blind spot object info, left diff --git a/selfdrive/car/volkswagen/pqcan.py b/selfdrive/car/volkswagen/pqcan.py index 130f107950..84200c2921 100644 --- a/selfdrive/car/volkswagen/pqcan.py +++ b/selfdrive/car/volkswagen/pqcan.py @@ -88,4 +88,4 @@ def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, lead_distance # kmh_mph handling probably needed to resolve rounding errors in displayed setpoint } - return packer.make_can_msg("ACC_GRA_Anziege", bus, values) + return packer.make_can_msg("ACC_GRA_Anzeige", bus, values) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 8e12923983..694b4006f8 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -36,7 +36,7 @@ class CarControllerParams: if CP.carFingerprint in PQ_CARS: self.LDW_STEP = 5 # LDW_1 message frequency 20Hz - self.ACC_HUD_STEP = 4 # ACC_GRA_Anziege frequency 25Hz + self.ACC_HUD_STEP = 4 # ACC_GRA_Anzeige frequency 25Hz self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm self.STEER_DELTA_UP = 6 # Max HCA reached in 1.00s (STEER_MAX / (50Hz * 1.00)) self.STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60)) From 17b71b477e596529d36dc7f95e3fa42697adfadc Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 13 Mar 2023 15:30:38 -0700 Subject: [PATCH 1083/1179] plannerd: add frameId to uiPlan (#27573) * plannerd: add frameId to uiPlan * update refs --- cereal | 2 +- selfdrive/controls/plannerd.py | 1 + selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cereal b/cereal index 42f84fd85d..9888e0476c 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 42f84fd85d06c0fc85371daa2b4820fca49d763e +Subproject commit 9888e0476c05069d46f273569467e4371b2d8690 diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index d8cf9386d1..14934254af 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -19,6 +19,7 @@ def publish_ui_plan(sm, pm, lateral_planner, longitudinal_planner): ui_send = messaging.new_message('uiPlan') ui_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'modelV2']) uiPlan = ui_send.uiPlan + uiPlan.frameId = sm['modelV2'].frameId uiPlan.position.x = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,0]).tolist() uiPlan.position.y = np.interp(plan_odo, model_odo, lateral_planner.lat_mpc.x_sol[:,1]).tolist() uiPlan.position.z = np.interp(plan_odo, model_odo, lateral_planner.path_xyz[:,2]).tolist() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 79769e14b6..a8896884e1 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -f9c7e05b836c4bff364978752e82d64b90f9d6e6 +3c5ebb007f76ba0de710ff7a8cf5910ad2edf22f \ No newline at end of file From 4692cf7d1ccc9d76f9c0189ca86c84d784ea85de Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 13 Mar 2023 17:07:42 -0700 Subject: [PATCH 1084/1179] Chrysler Pacifica 2018: add missing CAN fp (#27576) new pacifica FPs --- selfdrive/car/chrysler/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 2af5246b88..9f00484f34 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -99,7 +99,7 @@ FINGERPRINTS = { 55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 8, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8 }, { - 55: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 926: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8 + 55: 8, 58: 6, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 678: 8, 680: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 779: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 926: 3, 937: 8, 947: 8, 948: 8, 956: 8, 969: 4, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1537: 8, 1538: 8, 1562: 8 }], CAR.PACIFICA_2020: [{ 55: 8, 179: 8, 181: 8, 257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 294: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 469: 8, 480: 8, 500: 8, 501: 8, 512: 8, 514: 8, 516: 7, 517: 7, 520: 8, 524: 8, 526: 6, 528: 8, 532: 8, 536: 8, 542: 8, 544: 8, 557: 8, 559: 8, 560: 8, 564: 8, 571: 3, 579: 8, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 650: 8, 656: 4, 658: 6, 660: 8, 669: 3, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 711: 8, 719: 8, 720: 6, 729: 5, 736: 8, 746: 5, 752: 2, 754: 8, 760: 8, 764: 8, 766: 8, 770: 8, 773: 8, 776: 8, 779: 8, 782: 8, 784: 8, 792: 8, 793: 8, 794: 8, 795: 8, 799: 8, 800: 8, 801: 8, 802: 8, 803: 8, 804: 8, 808: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 832: 8, 838: 2, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 886: 8, 897: 8, 906: 8, 924: 8, 926: 3, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 962: 8, 969: 4, 973: 8, 974: 5, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 7, 1225: 8, 1227: 8, 1235: 8, 1242: 8, 1246: 8, 1250: 8, 1251: 8, 1252: 8, 1284: 8, 1543: 8, 1568: 8, 1570: 8, 1856: 8, 1858: 8, 1860: 8, 1863: 8, 1865: 8, 1867: 8, 1875: 8, 1882: 8, 1886: 8, 1890: 8, 1891: 8, 1892: 8, 1898: 8, 2015: 8, 2016: 8, 2017:8, 2024: 8, 2025: 8 From d75ee19defc279837f64fd62a0dbe2db4acd1a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 14 Mar 2023 09:25:09 -0700 Subject: [PATCH 1085/1179] Only trust locationd for nav (#27579) * Only trust locationd for nav * unused var --- selfdrive/ui/qt/maps/map.cc | 38 ------------------------------------- selfdrive/ui/ui.cc | 3 +-- 2 files changed, 1 insertion(+), 40 deletions(-) diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index dd30b5feff..abbf434d69 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -24,8 +24,6 @@ const float MAX_PITCH = 50; const float MIN_PITCH = 0; const float MAP_SCALE = 2; -const float VALID_POS_STD = 50.0; // m - const QString ICON_SUFFIX = ".png"; MapWindow::MapWindow(const QMapboxGLSettings &settings) : m_settings(settings), velocity_filter(0, 10, 0.05) { @@ -125,42 +123,6 @@ void MapWindow::updateState(const UIState &s) { } } - // TODO should check a valid/status flag - if (sm.updated("gnssMeasurements") && sm["gnssMeasurements"].getGnssMeasurements().getGpsWeek() > 0){ - auto laikad_location = sm["gnssMeasurements"].getGnssMeasurements(); - auto laikad_pos = laikad_location.getPositionECEF(); - auto laikad_pos_ecef = laikad_pos.getValue(); - auto laikad_pos_std = laikad_pos.getStd(); - auto laikad_velocity_ecef = laikad_location.getVelocityECEF().getValue(); - - laikad_valid = laikad_pos.getValid() && Eigen::Vector3d(laikad_pos_std[0], laikad_pos_std[1], laikad_pos_std[2]).norm() < VALID_POS_STD; - - if (laikad_valid && !locationd_valid) { - ECEF ecef = {.x = laikad_pos_ecef[0], .y = laikad_pos_ecef[1], .z = laikad_pos_ecef[2]}; - Geodetic laikad_pos_geodetic = ecef2geodetic(ecef); - last_position = QMapbox::Coordinate(laikad_pos_geodetic.lat, laikad_pos_geodetic.lon); - - // Compute NED velocity - LocalCoord converter(ecef); - ECEF next_ecef = {.x = ecef.x + laikad_velocity_ecef[0], .y = ecef.y + laikad_velocity_ecef[1], .z = ecef.z + laikad_velocity_ecef[2]}; - Eigen::VectorXd ned_vel = converter.ecef2ned(next_ecef).to_vector() - converter.ecef2ned(ecef).to_vector(); - - float velocity = ned_vel.norm(); - velocity_filter.update(velocity); - - // Convert NED velocity to angle - if (velocity > 1.0) { - float new_bearing = fmod(RAD2DEG(atan2(ned_vel[1], ned_vel[0])) + 360.0, 360.0); - if (last_bearing) { - float delta = 0.1 * angle_difference(*last_bearing, new_bearing); // Smooth heading - last_bearing = fmod(*last_bearing + delta + 360.0, 360.0); - } else { - last_bearing = new_bearing; - } - } - } - } - if (sm.updated("navRoute") && sm["navRoute"].getNavRoute().getCoordinates().size()) { qWarning() << "Got new navRoute from navd. Opening map:" << allow_open; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 50843de68e..c9e8c4e2d6 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -252,8 +252,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { sm = std::make_unique>({ "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "roadCameraState", "pandaStates", "carParams", "driverMonitoringState", "carState", "liveLocationKalman", "driverStateV2", - "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "gnssMeasurements", - "uiPlan", + "wideRoadCameraState", "managerState", "navInstruction", "navRoute", "uiPlan", }); Params params; From b591b0c764b3ba025ec31b083143fcab4ffcb0d8 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 14 Mar 2023 19:29:00 +0100 Subject: [PATCH 1086/1179] cabana: show signal values with consistent number of digits (#27556) --- tools/cabana/dbc.cc | 5 +++++ tools/cabana/dbc.h | 2 ++ tools/cabana/dbcmanager.cc | 1 + tools/cabana/historylog.cc | 7 +++++-- tools/cabana/signaledit.cc | 3 ++- tools/cabana/util.cc | 10 ++++++++++ tools/cabana/util.h | 1 + 7 files changed, 26 insertions(+), 3 deletions(-) diff --git a/tools/cabana/dbc.cc b/tools/cabana/dbc.cc index 8ffb660286..ff100e01f7 100644 --- a/tools/cabana/dbc.cc +++ b/tools/cabana/dbc.cc @@ -1,4 +1,5 @@ #include "tools/cabana/dbc.h" +#include "tools/cabana/util.h" uint qHash(const MessageId &item) { return qHash(item.source) ^ qHash(item.address); @@ -12,6 +13,10 @@ std::vector cabana::Msg::getSignals() const { return ret; } +void cabana::Signal::updatePrecision() { + precision = std::max(num_decimals(factor), num_decimals(offset)); +} + // helper functions static QVector BIG_ENDIAN_START_BITS = []() { diff --git a/tools/cabana/dbc.h b/tools/cabana/dbc.h index 3c58e38055..a2ebbc16cc 100644 --- a/tools/cabana/dbc.h +++ b/tools/cabana/dbc.h @@ -51,6 +51,8 @@ namespace cabana { QString min, max, unit; QString comment; ValueDescription val_desc; + int precision = 0; + void updatePrecision(); }; struct Msg { diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index b3a90e0b70..edf0007ed2 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -38,6 +38,7 @@ bool DBCManager::open(const QString &name, const QString &content, QString *erro sig.factor = s.factor; sig.offset = s.offset; sig.is_little_endian = s.is_little_endian; + sig.updatePrecision(); } } parseExtraInfo(content); diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 57f65b97d8..830fd30d49 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -14,11 +14,14 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { if (index.column() == 0) { return QString::number((m.mono_time / (double)1e9) - can->routeStartTime(), 'f', 2); } - return show_signals ? QString::number(m.sig_values[index.column() - 1]) : toHex(m.data); + int i = index.column() - 1; + return show_signals ? QString::number(m.sig_values[i], 'f', sigs[i]->precision) : toHex(m.data); } else if (role == ColorsRole) { return QVariant::fromValue(m.colors); } else if (role == BytesRole) { return m.data; + } else if (role == Qt::TextAlignmentRole) { + return Qt::AlignRight; } return {}; } @@ -235,7 +238,7 @@ LogsWidget::LogsWidget(QWidget *parent) : QFrame(parent) { delegate = new MessageBytesDelegate(this); logs->setItemDelegateForColumn(1, new MessageBytesDelegate(this)); logs->setHorizontalHeader(new HeaderView(Qt::Horizontal, this)); - logs->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | (Qt::Alignment)Qt::TextWordWrap); + logs->horizontalHeader()->setDefaultAlignment(Qt::AlignRight | (Qt::Alignment)Qt::TextWordWrap); logs->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); logs->verticalHeader()->setVisible(false); logs->setFrameShape(QFrame::NoFrame); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index ced7cd7d24..fd04a75f81 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -62,7 +62,7 @@ void SignalModel::updateState(const QHash *msgs) { auto &dat = can->lastMessage(msg_id).dat; int row = 0; for (auto item : root->children) { - QString value = QString::number(get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig)); + QString value = QString::number(get_raw_value((uint8_t *)dat.begin(), dat.size(), *item->sig), 'f', item->sig->precision); if (!item->sig->unit.isEmpty()){ value += " " + item->sig->unit; } @@ -184,6 +184,7 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r case Item::Desc: s.val_desc = value.value(); break; default: return false; } + s.updatePrecision(); bool ret = saveSignal(item->sig, s); emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, Qt::CheckStateRole}); return ret; diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index 656c97489c..b37b7911ed 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -184,3 +184,13 @@ QString toHex(uint8_t byte) { }(); return hex[byte]; } + +int num_decimals(double num) { + const QString string = QString::number(num); + const QStringList split = string.split('.'); + if (split.size() == 1) { + return 0; + } else { + return split[1].size(); + } + } diff --git a/tools/cabana/util.h b/tools/cabana/util.h index b1acdd8c6e..3cf14982a9 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -91,3 +91,4 @@ QPixmap icon(const QString &id); } QToolButton *toolButton(const QString &icon, const QString &tooltip); +int num_decimals(double num); From 0afd3bab34432e0ba83818c264f17e3ef16005df Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Tue, 14 Mar 2023 19:31:04 +0100 Subject: [PATCH 1087/1179] cabana: DBCManager only expose methods/signals through MessageId (#27540) --- tools/cabana/chartswidget.cc | 4 +-- tools/cabana/chartswidget.h | 4 +-- tools/cabana/dbcmanager.cc | 22 +++++++++++++-- tools/cabana/dbcmanager.h | 38 +++++++++++++++++++++----- tools/cabana/detailwidget.cc | 5 ++-- tools/cabana/detailwidget.h | 1 + tools/cabana/mainwin.cc | 4 ++- tools/cabana/signaledit.cc | 13 ++++----- tools/cabana/signaledit.h | 4 +-- tools/cabana/streams/abstractstream.cc | 5 ++++ tools/cabana/streams/abstractstream.h | 2 ++ tools/cabana/tests/test_cabana.cc | 12 ++++---- tools/cabana/tools/findsimilarbits.cc | 5 ++-- 13 files changed, 84 insertions(+), 35 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index f9661046c8..184d41ca0b 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -421,8 +421,8 @@ void ChartView::signalUpdated(const cabana::Signal *sig) { } } -void ChartView::msgUpdated(uint32_t address) { - if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.msg_id.address == address; })) +void ChartView::msgUpdated(MessageId id) { + if (std::any_of(sigs.begin(), sigs.end(), [=](auto &s) { return s.msg_id == id; })) updateTitle(); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index adce1e0f4d..bdc924ff83 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -57,11 +57,11 @@ signals: void axisYLabelWidthChanged(int w); private slots: - void msgUpdated(uint32_t address); void signalUpdated(const cabana::Signal *sig); void manageSeries(); void handleMarkerClicked(); - void msgRemoved(uint32_t address) { removeIf([=](auto &s) { return s.msg_id.address == address; }); } + void msgUpdated(MessageId id); + void msgRemoved(MessageId id) { removeIf([=](auto &s) { return s.msg_id == id; }); } void signalRemoved(const cabana::Signal *sig) { removeIf([=](auto &s) { return s.sig == sig; }); } private: diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index edf0007ed2..651367ba57 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -144,19 +144,31 @@ void DBCManager::updateMsg(const MessageId &id, const QString &name, uint32_t si auto &m = msgs[id.address]; m.name = name; m.size = size; - emit msgUpdated(id.address); + + // This DBC applies to all active sources, emit for every source + for (uint8_t source : sources) { + emit msgUpdated({.source = source, .address = id.address}); + } } void DBCManager::removeMsg(const MessageId &id) { msgs.erase(id.address); - emit msgRemoved(id.address); + + // This DBC applies to all active sources, emit for every source + for (uint8_t source : sources) { + emit msgRemoved({.source = source, .address = id.address}); + } } void DBCManager::addSignal(const MessageId &id, const cabana::Signal &sig) { if (auto m = const_cast(msg(id.address))) { m->sigs.push_back(sig); auto s = &m->sigs.last(); - emit signalAdded(id.address, s); + + // This DBC applies to all active sources, emit for every source + for (uint8_t source : sources) { + emit signalAdded({.source = source, .address = id.address}, s); + } } } @@ -192,6 +204,10 @@ QStringList DBCManager::signalNames() { return ret; } +void DBCManager::updateSources(const QSet &s) { + sources = s; +} + DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; diff --git a/tools/cabana/dbcmanager.h b/tools/cabana/dbcmanager.h index 4be7593808..dd3d9811c7 100644 --- a/tools/cabana/dbcmanager.h +++ b/tools/cabana/dbcmanager.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "tools/cabana/dbc.h" @@ -20,30 +22,52 @@ public: void addSignal(const MessageId &id, const cabana::Signal &sig); void updateSignal(const MessageId &id, const QString &sig_name, const cabana::Signal &sig); void removeSignal(const MessageId &id, const QString &sig_name); + inline int msgCount() const { return msgs.size(); } inline QString name() const { return name_; } void updateMsg(const MessageId &id, const QString &name, uint32_t size); void removeMsg(const MessageId &id); - inline const std::map &messages() const { return msgs; } + inline std::map getMessages(uint8_t source) { + std::map ret; + for (auto &[address, msg] : msgs) { + MessageId id = {.source = source, .address = address}; + ret[id] = msg; + } + return ret; + } inline const cabana::Msg *msg(const MessageId &id) const { return msg(id.address); } - inline const cabana::Msg *msg(uint32_t address) const { - auto it = msgs.find(address); - return it != msgs.end() ? &it->second : nullptr; + inline const cabana::Msg* msg(uint8_t source, const QString &name) { + for (auto &[_, msg] : msgs) { + if (msg.name == name) { + return &msg; + } + } + + return nullptr; } QStringList signalNames(); +public slots: + void updateSources(const QSet &s); + signals: - void signalAdded(uint32_t address, const cabana::Signal *sig); + void signalAdded(MessageId id, const cabana::Signal *sig); void signalRemoved(const cabana::Signal *sig); void signalUpdated(const cabana::Signal *sig); - void msgUpdated(uint32_t address); - void msgRemoved(uint32_t address); + void msgUpdated(MessageId id); + void msgRemoved(MessageId id); void DBCFileChanged(); private: void parseExtraInfo(const QString &content); std::map msgs; QString name_; + QSet sources; + + inline const cabana::Msg *msg(uint32_t address) const { + auto it = msgs.find(address); + return it != msgs.end() ? &it->second : nullptr; + } }; DBCManager *dbc(); diff --git a/tools/cabana/detailwidget.cc b/tools/cabana/detailwidget.cc index 05a0528d0e..ab723fa0e2 100644 --- a/tools/cabana/detailwidget.cc +++ b/tools/cabana/detailwidget.cc @@ -177,7 +177,7 @@ void DetailWidget::removeMsg() { // EditMessageDialog EditMessageDialog::EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent) - : original_name(title), QDialog(parent) { + : original_name(title), msg_id(msg_id), QDialog(parent) { setWindowTitle(tr("Edit message: %1").arg(msg_id.toString())); QFormLayout *form_layout = new QFormLayout(this); @@ -207,8 +207,7 @@ void EditMessageDialog::validateName(const QString &text) { bool valid = text.compare(UNTITLED, Qt::CaseInsensitive) != 0; error_label->setVisible(false); if (!text.isEmpty() && valid && text != original_name) { - valid = std::none_of(dbc()->messages().begin(), dbc()->messages().end(), - [&text](auto &m) { return m.second.name == text; }); + valid = dbc()->msg(msg_id.source, text) == nullptr; if (!valid) { error_label->setText(tr("Name already exists")); error_label->setVisible(true); diff --git a/tools/cabana/detailwidget.h b/tools/cabana/detailwidget.h index 0bfd8a74af..cc5bffd534 100644 --- a/tools/cabana/detailwidget.h +++ b/tools/cabana/detailwidget.h @@ -15,6 +15,7 @@ public: EditMessageDialog(const MessageId &msg_id, const QString &title, int size, QWidget *parent); void validateName(const QString &text); + MessageId msg_id; QString original_name; QDialogButtonBox *btn_box; QLineEdit *name_edit; diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 1559700951..56ffe872d6 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -42,6 +42,7 @@ MainWindow::MainWindow() : QMainWindow() { messages_widget->restoreHeaderState(settings.message_header_state); qRegisterMetaType("uint64_t"); + qRegisterMetaType>("QSet"); qRegisterMetaType("ReplyMsgType"); installMessageHandler([this](ReplyMsgType type, const std::string msg) { // use queued connection to recv the log messages from replay. @@ -70,6 +71,7 @@ MainWindow::MainWindow() : QMainWindow() { QObject::connect(can, &AbstractStream::streamStarted, this, &MainWindow::loadDBCFromFingerprint); QObject::connect(can, &AbstractStream::eventsMerged, this, &MainWindow::updateStatus); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &MainWindow::DBCFileChanged); + QObject::connect(can, &AbstractStream::sourcesUpdated, dbc(), &DBCManager::updateSources); QObject::connect(UndoStack::instance(), &QUndoStack::cleanChanged, this, &MainWindow::undoStackCleanChanged); QObject::connect(UndoStack::instance(), &QUndoStack::indexChanged, this, &MainWindow::undoStackIndexChanged); QObject::connect(&settings, &Settings::changed, this, &MainWindow::updateStatus); @@ -310,7 +312,7 @@ void MainWindow::loadDBCFromClipboard() { QString dbc_str = QGuiApplication::clipboard()->text(); QString error; bool ret = dbc()->open("clipboard", dbc_str, &error); - if (ret && dbc()->messages().size() > 0) { + if (ret && dbc()->msgCount() > 0) { QMessageBox::information(this, tr("Load From Clipboard"), tr("DBC Successfully Loaded!")); } else { QMessageBox msg_box(QMessageBox::Warning, tr("Failed to load DBC from clipboard"), tr("Make sure that you paste the text with correct format.")); diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index fd04a75f81..673a68a50b 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -239,8 +239,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { auto msg = dbc()->msg(msg_id); for (int i = 0; !msg; ++i) { QString name = QString("NEW_MSG_") + QString::number(msg_id.address, 16).toUpper(); - if (i > 0) name += QString("_%1").arg(i); - if (std::none_of(dbc()->messages().begin(), dbc()->messages().end(), [&](auto &m) { return m.second.name == name; })) { + if (!dbc()->msg(msg_id.source, name)) { UndoStack::push(new EditMsgCommand(msg_id, name, can->lastMessage(msg_id).dat.size())); msg = dbc()->msg(msg_id); } @@ -265,14 +264,14 @@ void SignalModel::removeSignal(const cabana::Signal *sig) { UndoStack::push(new RemoveSigCommand(msg_id, sig)); } -void SignalModel::handleMsgChanged(uint32_t address) { - if (address == msg_id.address) { +void SignalModel::handleMsgChanged(MessageId id) { + if (id == msg_id) { refresh(); } } -void SignalModel::handleSignalAdded(uint32_t address, const cabana::Signal *sig) { - if (address == msg_id.address) { +void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) { + if (id == msg_id) { int i = 0; for (; i < root->children.size(); ++i) { if (sig->start_bit < root->children[i]->sig->start_bit) break; @@ -442,7 +441,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); - QObject::connect(dbc(), &DBCManager::signalAdded, [this](uint32_t address, const cabana::Signal *sig) { selectSignal(sig); }); + QObject::connect(dbc(), &DBCManager::signalAdded, [this](MessageId id, const cabana::Signal *sig) { selectSignal(sig); }); setWhatsThis(tr(R"( Signal view
diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index 39fe5f270f..ae73a7b3bc 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -48,10 +48,10 @@ public: private: void insertItem(SignalModel::Item *parent_item, int pos, const cabana::Signal *sig); - void handleSignalAdded(uint32_t address, const cabana::Signal *sig); + void handleSignalAdded(MessageId id, const cabana::Signal *sig); void handleSignalUpdated(const cabana::Signal *sig); void handleSignalRemoved(const cabana::Signal *sig); - void handleMsgChanged(uint32_t address); + void handleMsgChanged(MessageId id); void refresh(); void updateState(const QHash *msgs); diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index 40e9cbc8a5..c8ff449098 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -39,6 +39,11 @@ bool AbstractStream::updateEvent(const Event *event) { data.colors = tracker.colors; data.last_change_t = tracker.last_change_t; data.bit_change_counts = tracker.bit_change_counts; + + if (!sources.contains(id.source)) { + sources.insert(id.source); + emit sourcesUpdated(sources); + } } double ts = millis_since_boot(); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index e582682971..de7c394303 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -52,9 +52,11 @@ signals: void updated(); void msgsReceived(const QHash *); void received(QHash *); + void sourcesUpdated(const QSet &s); public: QHash can_msgs; + QSet sources; protected: void process(QHash *); diff --git a/tools/cabana/tests/test_cabana.cc b/tools/cabana/tests/test_cabana.cc index 124eb7428a..8445867acb 100644 --- a/tools/cabana/tests/test_cabana.cc +++ b/tools/cabana/tests/test_cabana.cc @@ -15,11 +15,11 @@ TEST_CASE("DBCManager::generateDBC") { DBCManager dbc_from_generated(nullptr); dbc_from_generated.open("", dbc_origin.generateDBC()); - auto &msgs = dbc_origin.messages(); - auto &new_msgs = dbc_from_generated.messages(); - REQUIRE(msgs.size() == new_msgs.size()); - for (auto &[address, m] : msgs) { - auto &new_m = new_msgs.at(address); + REQUIRE(dbc_origin.msgCount() == dbc_from_generated.msgCount()); + auto msgs = dbc_origin.getMessages(0); + auto new_msgs = dbc_from_generated.getMessages(0); + for (auto &[id, m] : msgs) { + auto &new_m = new_msgs.at(id); REQUIRE(m.name == new_m.name); REQUIRE(m.size == new_m.size); REQUIRE(m.getSignals().size() == new_m.getSignals().size()); @@ -43,7 +43,7 @@ TEST_CASE("Parse can messages") { if (e->which == cereal::Event::Which::CAN) { std::map, std::vector> values_1; for (const auto &c : e->event.getCan()) { - const auto msg = dbc.msg(c.getAddress()); + const auto msg = dbc.msg({.source = c.getSrc(), .address = c.getAddress()}); if (c.getSrc() == 0 && msg) { for (auto sig : msg->getSignals()) { double val = get_raw_value((uint8_t *)c.getDat().begin(), c.getDat().size(), *sig); diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index ffb0e54b0e..7768359df4 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -29,8 +29,9 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi bus_combo->setCurrentIndex(0); msg_cb = new QComboBox(this); - for (auto &[address, msg] : dbc()->messages()) { - msg_cb->addItem(msg.name, address); + // TODO: update when bus_combo changes + for (auto &[id, msg] : dbc()->getMessages(0)) { + msg_cb->addItem(msg.name, id.address); } msg_cb->model()->sort(0); msg_cb->setCurrentIndex(0); From 696cbb3e242a0613d4a8183df1eafd2fbcaf755b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 15 Mar 2023 02:31:57 +0800 Subject: [PATCH 1088/1179] cabana: fix incorrect current ts in live stream mode (#27578) --- tools/cabana/streams/livestream.cc | 21 ++++++++++----------- tools/cabana/streams/livestream.h | 1 - 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 8f63d3baec..592d883c4c 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -45,12 +45,11 @@ void LiveStream::streamThread() { } void LiveStream::handleEvent(Event *evt) { - current_ts = evt->mono_time; - if (start_ts == 0 || current_ts < start_ts) { - if (current_ts < start_ts) { + if (start_ts == 0 || evt->mono_time < start_ts) { + if (evt->mono_time < start_ts) { qDebug() << "stream is looping back to old time stamp"; } - start_ts = current_ts.load(); + start_ts = current_ts = evt->mono_time; emit streamStarted(); } @@ -58,19 +57,19 @@ void LiveStream::handleEvent(Event *evt) { can_events.push_back(evt); if (!pause_) { if (speed_ < 1 && last_update_ts > 0) { - auto it = std::upper_bound(can_events.begin(), can_events.end(), last_update_event_ts, [](uint64_t ts, auto &e) { + auto it = std::upper_bound(can_events.cbegin(), can_events.cend(), current_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); + if (it != can_events.cend()) { + bool skip = (nanos_since_boot() - last_update_ts) < ((*it)->mono_time - current_ts) / speed_; + if (skip) return; - if (it != can_events.end() && - (nanos_since_boot() - last_update_ts) < ((*it)->mono_time - last_update_event_ts) / speed_) { - return; + evt = *it; } - evt = (*it); } - updateEvent(evt); - last_update_event_ts = evt->mono_time; + current_ts = evt->mono_time; last_update_ts = nanos_since_boot(); + updateEvent(evt); } } diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index ba20032b67..43f67ae95f 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -32,7 +32,6 @@ protected: std::atomic current_ts = 0; std::atomic speed_ = 1; std::atomic pause_ = false; - uint64_t last_update_event_ts = 0; uint64_t last_update_ts = 0; const QString zmq_address; From 39cf8c6694731e43a45462be8c645b732059f324 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 14 Mar 2023 13:31:49 -0700 Subject: [PATCH 1089/1179] only run rawgpsd without a ublox (#27577) --- selfdrive/manager/process_config.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 2bacd951a7..57c42aaaaa 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -17,11 +17,17 @@ def logging(started, params, CP: car.CarParams) -> bool: run = (not CP.notCar) or not params.get_bool("DisableLogging") return started and run +def ublox_available() -> bool: + return os.path.exists('/dev/ttyHS0') and not os.path.exists('/persist/comma/use-quectel-gps') + def ublox(started, params, CP: car.CarParams) -> bool: - use_ublox = os.path.exists('/dev/ttyHS0') and not os.path.exists('/persist/comma/use-quectel-gps') + use_ublox = ublox_available() params.put_bool("UbloxAvailable", use_ublox) return started and use_ublox +def qcomgps(started, params, CP: car.CarParams) -> bool: + return started and not ublox_available() + procs = [ # due to qualcomm kernel bugs SIGKILLing camerad sometimes causes page table corruption NativeProcess("camerad", "system/camerad", ["./camerad"], unkillable=True, callback=driverview), @@ -50,7 +56,7 @@ procs = [ PythonProcess("deleter", "system.loggerd.deleter", offroad=True), PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=(not PC or WEBCAM), callback=driverview), PythonProcess("laikad", "selfdrive.locationd.laikad"), - PythonProcess("rawgpsd", "system.sensord.rawgps.rawgpsd", enabled=TICI), + PythonProcess("rawgpsd", "system.sensord.rawgps.rawgpsd", enabled=TICI, onroad=False, callback=qcomgps), PythonProcess("navd", "selfdrive.navd.navd"), PythonProcess("pandad", "selfdrive.boardd.pandad", offroad=True), PythonProcess("paramsd", "selfdrive.locationd.paramsd"), From d5375af2f5c9f74cb88ffa1ab52feb9fef77a43c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 15 Mar 2023 04:59:22 +0800 Subject: [PATCH 1090/1179] ui: auto detect available streams (#27470) * auto detect available streams * no switch if wide cam not available * clear frames before getAvailableStreams * warning * clear at same time --------- Co-authored-by: Adeeb Shihadeh --- selfdrive/ui/qt/onroad.cc | 20 +++++++++++--------- selfdrive/ui/qt/widgets/cameraview.cc | 15 +++++++++++++++ selfdrive/ui/qt/widgets/cameraview.h | 5 +++++ selfdrive/ui/ui.cc | 2 -- selfdrive/ui/ui.h | 1 - 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index dc2f1368ac..009798a569 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -648,16 +648,18 @@ void AnnotatedCameraWidget::paintGL() { } // Wide or narrow cam dependent on speed - float v_ego = sm["carState"].getCarState().getVEgo(); - if ((v_ego < 10) || s->wide_cam_only) { - wide_cam_requested = true; - } else if (v_ego > 15) { - wide_cam_requested = false; + bool has_wide_cam = available_streams.count(VISION_STREAM_WIDE_ROAD); + if (has_wide_cam) { + float v_ego = sm["carState"].getCarState().getVEgo(); + if ((v_ego < 10) || available_streams.size() == 1) { + wide_cam_requested = true; + } else if (v_ego > 15) { + wide_cam_requested = false; + } + wide_cam_requested = wide_cam_requested && sm["controlsState"].getControlsState().getExperimentalMode(); + // for replay of old routes, never go to widecam + wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; } - wide_cam_requested = wide_cam_requested && sm["controlsState"].getControlsState().getExperimentalMode(); - // TODO: also detect when ecam vision stream isn't available - // for replay of old routes, never go to widecam - wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid; CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD); s->scene.wide_cam = CameraWidget::getStreamType() == VISION_STREAM_WIDE_ROAD; diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 8c7a7072e2..10300da55c 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -96,8 +96,10 @@ mat4 get_fit_view_transform(float widget_aspect_ratio, float frame_aspect_ratio) CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, bool zoom, QWidget* parent) : stream_name(stream_name), requested_stream_type(type), zoomed_view(zoom), QOpenGLWidget(parent) { setAttribute(Qt::WA_OpaquePaintEvent); + qRegisterMetaType>("availableStreams"); QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); + QObject::connect(this, &CameraWidget::vipcAvailableStreamsUpdated, this, &CameraWidget::availableStreamsUpdated, Qt::QueuedConnection); } CameraWidget::~CameraWidget() { @@ -181,6 +183,10 @@ void CameraWidget::stopVipcThread() { } } +void CameraWidget::availableStreamsUpdated(std::set streams) { + available_streams = streams; +} + void CameraWidget::updateFrameMat() { int w = width(), h = height(); @@ -366,6 +372,14 @@ void CameraWidget::vipcThread() { if (!vipc_client->connected) { clearFrames(); + auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); + if (streams.empty()) { + qWarning() << "VisionIPC connected, but no streams available"; + QThread::msleep(100); + continue; + } + emit vipcAvailableStreamsUpdated(streams); + if (!vipc_client->connect(false)) { QThread::msleep(100); continue; @@ -400,4 +414,5 @@ void CameraWidget::vipcThread() { void CameraWidget::clearFrames() { std::lock_guard lk(frame_lock); frames.clear(); + available_streams.clear(); } diff --git a/selfdrive/ui/qt/widgets/cameraview.h b/selfdrive/ui/qt/widgets/cameraview.h index f8b97be03e..9135620d35 100644 --- a/selfdrive/ui/qt/widgets/cameraview.h +++ b/selfdrive/ui/qt/widgets/cameraview.h @@ -41,6 +41,7 @@ signals: void clicked(); void vipcThreadConnected(VisionIpcClient *); void vipcThreadFrameReceived(); + void vipcAvailableStreamsUpdated(std::set); protected: void paintGL() override; @@ -71,6 +72,7 @@ protected: int stream_stride = 0; std::atomic active_stream_type; std::atomic requested_stream_type; + std::set available_streams; QThread *vipc_thread = nullptr; // Calibration @@ -88,4 +90,7 @@ protected: protected slots: void vipcConnected(VisionIpcClient *vipc_client); void vipcFrameReceived(); + void availableStreamsUpdated(std::set streams); }; + +Q_DECLARE_METATYPE(std::set); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index c9e8c4e2d6..50ffc84f4f 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -234,7 +234,6 @@ void UIState::updateStatus() { if (scene.started) { status = STATUS_DISENGAGED; scene.started_frame = sm->frame; - wide_cam_only = Params().getBool("WideCameraOnly"); } started_prev = scene.started; emit offroadTransition(!scene.started); @@ -256,7 +255,6 @@ UIState::UIState(QObject *parent) : QObject(parent) { }); Params params; - wide_cam_only = params.getBool("WideCameraOnly"); prime_type = std::atoi(params.get("PrimeType").c_str()); language = QString::fromStdString(params.get("LanguageSetting")); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index ad2a1fe1f4..4c4bd462e7 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -150,7 +150,6 @@ public: QString language; QTransform car_space_transform; - bool wide_cam_only; signals: void uiUpdate(const UIState &s); From e2f4a82c03543651eab1e7e51c411f79b5684a5a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 14 Mar 2023 14:00:39 -0700 Subject: [PATCH 1091/1179] Add CAN fingerprint to qlog (#27574) --- selfdrive/car/car_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 370772c902..dc82f56197 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -180,7 +180,7 @@ def get_car(logcan, sendcan, experimental_long_allowed, 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) + cloudlog.event("car doesn't match any fingerprints", fingerprints=fingerprints, error=True) candidate = "mock" CarInterface, CarController, CarState = interfaces[candidate] From 2749205b4a8d87b18051d3fa8c680b2e9a849a33 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 14 Mar 2023 20:55:41 -0700 Subject: [PATCH 1092/1179] allow running amp config script standalone (#27587) Co-authored-by: Comma Device --- system/hardware/tici/amplifier.py | 9 +++++++++ 1 file changed, 9 insertions(+) mode change 100644 => 100755 system/hardware/tici/amplifier.py diff --git a/system/hardware/tici/amplifier.py b/system/hardware/tici/amplifier.py old mode 100644 new mode 100755 index 840d575fdf..9725cd689c --- a/system/hardware/tici/amplifier.py +++ b/system/hardware/tici/amplifier.py @@ -129,3 +129,12 @@ class Amplifier: self.set_config(config) self.set_global_shutdown(amp_disabled=False) + + +if __name__ == "__main__": + with open("/sys/firmware/devicetree/base/model") as f: + model = f.read().strip('\x00') + model = model.split('comma ')[-1] + + amp = Amplifier() + amp.initialize_configuration(model) From 5c704827619e774c9877b4598af06d1c6bca80d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 00:02:56 -0700 Subject: [PATCH 1093/1179] Use structs in laika (#27585) * doesnt crash * New cacher * unused import * help linter * Annotate list * print error * fix caching bugs * wrong name * small fixes * fix sum * wrong brackets * fix tests * update ref * bump submodules --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 82 ++++++++++-------------- selfdrive/locationd/test/test_laikad.py | 57 ++++++++++++---- selfdrive/test/process_replay/ref_commit | 2 +- system/ubloxd/ublox_msg.cc | 66 ++++++++----------- system/ubloxd/ublox_msg.h | 6 +- 7 files changed, 115 insertions(+), 102 deletions(-) diff --git a/cereal b/cereal index 9888e0476c..c579889f39 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 9888e0476c05069d46f273569467e4371b2d8690 +Subproject commit c579889f396cd754048c7b1a51c6f33b1988762a diff --git a/laika_repo b/laika_repo index b740b71c82..b896cdbbd1 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit b740b71c82a748e3520b1599487d9a7aaf728670 +Subproject commit b896cdbbd1e8f85df25a1afa0c9a2ec150b72f92 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2b18dcf152..53fbf36066 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import json import math import os import time @@ -17,7 +16,7 @@ from common.params import Params, put_nonblocking from laika import AstroDog from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed -from laika.ephemeris import Ephemeris, EphemerisType, convert_ublox_gps_ephem, convert_ublox_glonass_ephem, parse_qcom_ephem +from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom @@ -51,10 +50,11 @@ class Laikad: self.auto_fetch_navs = auto_fetch_navs self.orbit_fetch_executor: Optional[ProcessPoolExecutor] = None self.orbit_fetch_future: Optional[Future] = None - - self.last_fetch_navs_t = None self.got_first_gnss_msg = False - self.last_cached_t = None + + self.last_report_time = GPSTime(0, 0) + self.last_fetch_navs_t = GPSTime(0, 0) + self.last_cached_t = GPSTime(0, 0) self.save_ephemeris = save_ephemeris self.load_cache() @@ -69,31 +69,34 @@ class Laikad: if not self.save_ephemeris: return - cache = Params().get(EPHEMERIS_CACHE) - if not cache: + cache_bytes = Params().get(EPHEMERIS_CACHE) + if not cache_bytes: return + nav_dict = {} try: - cache = json.loads(cache, object_hook=deserialize_hook) - if cache['version'] == CACHE_VERSION: - self.astro_dog.add_navs(cache['navs']) - self.last_fetch_navs_t = cache['last_fetch_navs_t'] - else: - cache['navs'] = {} - except json.decoder.JSONDecodeError: + ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) + glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] + for e in sum([glonass_navs, gps_navs], []): + if e.prn not in nav_dict: + nav_dict[e.prn] = [] + nav_dict[e.prn].append(e) + self.astro_dog.add_navs(nav_dict) + except Exception: cloudlog.exception("Error parsing cache") - timestamp = self.last_fetch_navs_t.as_datetime() if self.last_fetch_navs_t is not None else 'Nan' cloudlog.debug( - f"Loaded navs ({sum([len(v) for v in cache['navs']])}) cache with timestamp: {timestamp}. Unique orbit and nav sats: {list(cache['navs'].keys())} " + - f"With time range: {[f'{start.as_datetime()}, {end.as_datetime()}' for (start,end) in self.astro_dog.navs_fetched_times._ranges]}") + f"Loaded navs ({sum([len(nav_dict[prn]) for prn in nav_dict.keys()])}). Unique orbit and nav sats: {list(nav_dict.keys())} ") - def cache_ephemeris(self, t: GPSTime): - if self.save_ephemeris and (self.last_cached_t is None or t - self.last_cached_t > SECS_IN_MIN): - put_nonblocking(EPHEMERIS_CACHE, json.dumps( - {'version': CACHE_VERSION, 'last_fetch_navs_t': self.last_fetch_navs_t, 'navs': self.astro_dog.navs}, - cls=CacheSerializer)) + def cache_ephemeris(self): + + if self.save_ephemeris and (self.last_report_time - self.last_cached_t > SECS_IN_MIN): + nav_list: List = sum([v for k,v in self.astro_dog.navs.items()], []) + ephem_cache = ephemeris_structs.EphemerisCache(**{'glonassEphemerides': [e.data for e in nav_list if e.prn[0]=='R'], + 'gpsEphemerides': [e.data for e in nav_list if e.prn[0]=='G']}) + put_nonblocking(EPHEMERIS_CACHE, ephem_cache.to_bytes()) cloudlog.debug("Cache saved") - self.last_cached_t = t + self.last_cached_t = self.last_report_time def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: @@ -139,6 +142,7 @@ class Laikad: week = report.gpsWeek tow = report.rcvTow new_meas = read_raw_ublox(report) + self.last_report_time = GPSTime(week, tow) return week, tow, new_meas def is_ephemeris(self, gnss_msg): @@ -155,14 +159,16 @@ class Laikad: ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) else: if gnss_msg.which() == 'ephemeris': - ephem = convert_ublox_gps_ephem(gnss_msg.ephemeris) + data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) + ephem = GPSEphemeris(data_struct) elif gnss_msg.which() == 'glonassEphemeris': - ephem = convert_ublox_glonass_ephem(gnss_msg.glonassEphemeris) + data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) + ephem = GLONASSEphemeris(data_struct) else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return self.astro_dog.add_navs({ephem.prn: [ephem]}) - self.cache_ephemeris(t=ephem.epoch) + self.cache_ephemeris() def process_report(self, new_meas, t): # Filter measurements with unexpected pseudoranges for GPS and GLONASS satellites @@ -272,7 +278,7 @@ class Laikad: def fetch_navs(self, t: GPSTime, block): # Download new navs if 1 hour of navs data left - if t + SECS_IN_HR not in self.astro_dog.navs_fetched_times and (self.last_fetch_navs_t is None or abs(t - self.last_fetch_navs_t) > SECS_IN_MIN): + if t + SECS_IN_HR not in self.astro_dog.navs_fetched_times and (abs(t - self.last_fetch_navs_t) > SECS_IN_MIN): astro_dog_vars = self.astro_dog.valid_const, self.astro_dog.auto_update, self.astro_dog.valid_ephem_types, self.astro_dog.cache_dir ret = None @@ -290,7 +296,7 @@ class Laikad: self.last_fetch_navs_t = ret[2] else: self.astro_dog.navs, self.astro_dog.navs_fetched_times, self.last_fetch_navs_t = ret - self.cache_ephemeris(t=t) + self.cache_ephemeris() def get_orbit_data(t: GPSTime, valid_const, auto_update, valid_ephem_types, cache_dir): @@ -360,26 +366,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) -class CacheSerializer(json.JSONEncoder): - - def default(self, o): - if isinstance(o, Ephemeris): - return o.to_json() - if isinstance(o, GPSTime): - return o.__dict__ - if isinstance(o, np.ndarray): - return o.tolist() - return json.JSONEncoder.default(self, o) - - -def deserialize_hook(dct): - if 'ephemeris' in dct: - return Ephemeris.from_json(dct) - if 'week' in dct: - return GPSTime(dct['week'], dct['tow']) - return dct - - class EphemerisSourceType(IntEnum): nav = 0 nasaUltraRapid = 1 diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 10ac7790b6..be79ff16bc 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -1,21 +1,51 @@ #!/usr/bin/env python3 import time import unittest -from collections import defaultdict +from cereal import log +import cereal.messaging as messaging +from common.params import Params from datetime import datetime from unittest import mock from unittest.mock import patch +from tqdm import tqdm + -from common.params import Params from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType, GPSEphemeris +from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime from laika.helpers import ConstellationId, TimeRangeHolder from laika.raw_gnss import GNSSMeasurement, read_raw_ublox from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader +from selfdrive.manager.process_config import managed_processes + +from selfdrive.test.process_replay.helpers import OpenpilotPrefix + + +def get_ublox_gnss(ubloxraw): + with OpenpilotPrefix(): + managed_processes['ubloxd'].start() + timeout_ms = 30 + pm = messaging.PubMaster(['ubloxRaw']) + sock = messaging.sub_sock('ubloxGnss', timeout=timeout_ms) + + log_msgs = [] + log_t = [] + for x in tqdm(ubloxraw): + pm.send(x.which(), x.as_builder()) + ret = messaging.recv_one(sock) + if ret is not None: + msg = log.Event.new_message(ubloxGnss=ret.ubloxGnss.to_dict()) + msg.logMonoTime = x.logMonoTime + log_msgs.append(msg) + log_t.append(1e-9 * x.logMonoTime) + assert managed_processes['ubloxd'].get_process_state_msg().running + assert len(log_msgs) > 1 or len(ubloxraw) == 0 + managed_processes['ubloxd'].stop() + return log_t, log_msgs + def get_log(segs=range(0)): @@ -23,7 +53,8 @@ def get_log(segs=range(0)): for i in segs: logs.extend(LogReader(get_url("4cf7a6ad03080c90|2021-09-29--13-46-36", i))) - all_logs = [m for m in logs if m.which() == 'ubloxGnss'] + raw_logs = [m for m in logs if m.which() == 'ubloxRaw'] + all_logs = get_ublox_gnss(raw_logs)[1] low_gnss = [] for m in all_logs: if m.ubloxGnss.which() != 'measurementReport': @@ -31,7 +62,8 @@ def get_log(segs=range(0)): MAX_MEAS = 7 if m.ubloxGnss.measurementReport.numMeas > MAX_MEAS: - mb = m.as_builder() + mb = log.Event.new_message(ubloxGnss=m.ubloxGnss.to_dict()) + mb.logMonoTime = m.logMonoTime mb.ubloxGnss.measurementReport.numMeas = MAX_MEAS mb.ubloxGnss.measurementReport.measurements = list(m.ubloxGnss.measurementReport.measurements)[:MAX_MEAS] mb.ubloxGnss.measurementReport.measurements[0].pseudorange += 1000 @@ -128,8 +160,8 @@ class TestLaikad(unittest.TestCase): self.assertEqual(laikad.last_fetch_navs_t, real_current_time) def test_ephemeris_source_in_msg(self): - data_mock = defaultdict(str) - data_mock['sv_id'] = 1 + dicto = {'svId': 1} + data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC laikad = Laikad() @@ -151,7 +183,7 @@ class TestLaikad(unittest.TestCase): self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) # Test nav source type - ephem = GPSEphemeris(data_mock, gpstime) + ephem = GPSEphemeris(data_mock) meas = get_measurement_mock(gpstime, ephem) msg = create_measurement_msg(meas) self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) @@ -195,8 +227,8 @@ class TestLaikad(unittest.TestCase): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(255, len(correct_msgs)) - self.assertEqual(255, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(375, len(correct_msgs)) + self.assertEqual(375, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) @@ -241,11 +273,13 @@ class TestLaikad(unittest.TestCase): self.fail("Cache has not been written after 2 seconds") # Test cache with no ephemeris - laikad.cache_ephemeris(t=GPSTime(0, 0)) + laikad.last_report_time = GPSTime(1,0) + laikad.cache_ephemeris() wait_for_cache() Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) + laikad.last_report_time = GPSTime(2,0) laikad.fetch_navs(self.first_gps_time, block=True) # Wait for cache to save @@ -272,6 +306,7 @@ class TestLaikad(unittest.TestCase): # Verify orbit data is not downloaded mock_method.assert_not_called() + def test_low_gnss_meas(self): cnt = 0 laikad = Laikad() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index a8896884e1..dae7ceab1a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3c5ebb007f76ba0de710ff7a8cf5910ad2edf22f \ No newline at end of file +b79fa775682401c25aa9ce38b5542b4206d0c56b diff --git a/system/ubloxd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc index 83e64b7ddc..811492ba9b 100644 --- a/system/ubloxd/ublox_msg.cc +++ b/system/ubloxd/ublox_msg.cc @@ -65,22 +65,6 @@ inline bool UbloxMsgParser::valid_so_far() { return true; } -inline uint16_t UbloxMsgParser::get_glonass_year(uint8_t N4, uint16_t Nt) { - // convert time to year (conversion from A3.1.3) - int J = 0; - if (1 <= Nt && Nt <= 366) { - J = 1; - } else if (367 <= Nt && Nt <= 731) { - J = 2; - } else if (732 <= Nt && Nt <= 1096) { - J = 3; - } else if (1097 <= Nt && Nt <= 1461) { - J = 4; - } - uint16_t year = 1996 + 4*(N4 -1) + (J - 1); - return year; -} - bool UbloxMsgParser::add_data(float log_time, const uint8_t *incoming_data, uint32_t incoming_data_len, size_t &bytes_consumed) { last_log_time = log_time; int needed = needed_bytes(); @@ -203,6 +187,7 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m int iode_s2 = 0; int iode_s3 = 0; int iodc_lsb = 0; + int week; // Subframe 1 { @@ -210,7 +195,14 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m gps_t subframe(&stream); gps_t::subframe_1_t* subframe_1 = static_cast(subframe.body()); - eph.setGpsWeek(subframe_1->week_no()); + // Each message is incremented to be greater or equal than week 1877 (2015-12-27). + // To skip this use the current_time argument + week = subframe_1->week_no(); + week += 1024; + if (week < 1877) { + week += 1024; + } + //eph.setGpsWeek(subframe_1->week_no()); eph.setTgd(subframe_1->t_gd() * pow(2, -31)); eph.setToc(subframe_1->t_oc() * pow(2, 4)); eph.setAf2(subframe_1->af_2() * pow(2, -55)); @@ -227,6 +219,12 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m gps_t subframe(&stream); gps_t::subframe_2_t* subframe_2 = static_cast(subframe.body()); + // GPS week refers to current week, the ephemeris can be valid for the next + // if toe equals 0, this can be verified by the TOW count if it is within the + // last 2 hours of the week (gps ephemeris valid for 4hours) + if (subframe_2->t_oe() == 0 and subframe.how()->tow_count()*6 >= (SECS_IN_WEEK - 2*SECS_IN_HR)){ + week += 1; + } eph.setCrs(subframe_2->c_rs() * pow(2, -5)); eph.setDeltaN(subframe_2->delta_n() * pow(2, -43) * gpsPi); eph.setM0(subframe_2->m_0() * pow(2, -31) * gpsPi); @@ -256,6 +254,9 @@ kj::Array UbloxMsgParser::parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *m iode_s3 = subframe_3->iode(); } + eph.setToeWeek(week); + eph.setTocWeek(week); + gps_subframes[msg->sv_id()].clear(); if (iodc_lsb != iode_s2 || iodc_lsb != iode_s3) { // data set cutover, reject ephemeris @@ -329,7 +330,10 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ MessageBuilder msg_builder; auto eph = msg_builder.initEvent().initUbloxGnss().initGlonassEphemeris(); eph.setSvId(msg->sv_id()); + eph.setFreqNum(msg->freq_id() - 7); + uint16_t current_day = 0; + uint16_t tk = 0; // string number 1 { @@ -338,7 +342,8 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ glonass_t::string_1_t* data = static_cast(gl_stream.data()); eph.setP1(data->p1()); - eph.setTk(data->t_k()); + tk = data->t_k(); + eph.setTkDEPRECATED(tk); eph.setXVel(data->x_vel() * pow(2, -20)); eph.setXAccel(data->x_accel() * pow(2, -30)); eph.setX(data->x() * pow(2, -11)); @@ -379,6 +384,7 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ glonass_t::string_4_t* data = static_cast(gl_stream.data()); current_day = data->n_t(); + eph.setNt(current_day); eph.setTauN(data->tau_n() * pow(2, -30)); eph.setDeltaTauN(data->delta_tau_n() * pow(2, -30)); eph.setAge(data->e_n()); @@ -398,27 +404,9 @@ kj::Array UbloxMsgParser::parse_glonass_ephemeris(ubx_t::rxm_sfrbx_ // string5 parsing is only needed to get the year, this can be removed and // the year can be fetched later in laika (note rollovers and leap year) - uint8_t n_4 = data->n_4(); - uint16_t year = get_glonass_year(n_4, current_day); - if (current_day > 1461) { - // impossible day within last 4 year, reject ephemeris - // TODO: check if this can be detected via hamming code - LOGE("INVALID DATA: current day out of range: %d, %d", current_day, n_4); - glonass_strings[msg->sv_id()].clear(); - return kj::Array(); - } - - uint16_t last_leap_year = 1996 + 4*(n_4-1); - uint16_t days_till_this_year = (year - last_leap_year)*365; - if (days_till_this_year != 0) { - days_till_this_year++; - } - - eph.setYear(year); - eph.setDayInYear(current_day - days_till_this_year); - eph.setHour((eph.getTk()>>7) & 0x1F); - eph.setMinute((eph.getTk()>>1) & 0x3F); - eph.setSecond((eph.getTk() & 0x1) * 30); + eph.setN4(data->n_4()); + int tk_seconds = SECS_IN_HR * ((tk>>7) & 0x1F) + SECS_IN_MIN * ((tk>>1) & 0x3F) + (tk & 0x1) * 30; + eph.setTkSeconds(tk_seconds); } glonass_strings[msg->freq_id()].clear(); diff --git a/system/ubloxd/ublox_msg.h b/system/ubloxd/ublox_msg.h index 06877cc50d..a6e0623aa0 100644 --- a/system/ubloxd/ublox_msg.h +++ b/system/ubloxd/ublox_msg.h @@ -15,6 +15,11 @@ using namespace std::string_literals; +const int SECS_IN_MIN = 60; +const int SECS_IN_HR = 60 * SECS_IN_MIN; +const int SECS_IN_DAY = 24 * SECS_IN_HR; +const int SECS_IN_WEEK = 7 * SECS_IN_DAY; + // protocol constants namespace ublox { const uint8_t PREAMBLE1 = 0xb5; @@ -102,7 +107,6 @@ class UbloxMsgParser { inline bool valid_cheksum(); inline bool valid(); inline bool valid_so_far(); - inline uint16_t get_glonass_year(uint8_t N4, uint16_t Nt); kj::Array parse_gps_ephemeris(ubx_t::rxm_sfrbx_t *msg); kj::Array parse_glonass_ephemeris(ubx_t::rxm_sfrbx_t *msg); From 153ffa3f68bc316d17b46a94327bdc5777f39b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 01:21:18 -0700 Subject: [PATCH 1094/1179] Sat info from ublox (#27526) * squashed * bump cereal --- cereal | 2 +- system/ubloxd/generated/ubx.cpp | 136 ++++++++++++++++++++++++++------ system/ubloxd/generated/ubx.h | 94 +++++++++++++++++++--- system/ubloxd/tests/ublox.py | 1 + system/ubloxd/ublox_msg.cc | 18 ++++- system/ubloxd/ublox_msg.h | 1 + system/ubloxd/ubx.ksy | 40 +++++++++- 7 files changed, 253 insertions(+), 39 deletions(-) diff --git a/cereal b/cereal index c579889f39..80a8eb8459 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit c579889f396cd754048c7b1a51c6f33b1988762a +Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 diff --git a/system/ubloxd/generated/ubx.cpp b/system/ubloxd/generated/ubx.cpp index 34fe1e52ca..81b82ccafc 100644 --- a/system/ubloxd/generated/ubx.cpp +++ b/system/ubloxd/generated/ubx.cpp @@ -40,6 +40,11 @@ void ubx_t::_read() { m_body = new rxm_sfrbx_t(m__io, this, m__root); break; } + case 309: { + n_body = false; + m_body = new nav_sat_t(m__io, this, m__root); + break; + } case 2571: { n_body = false; m_body = new mon_hw2_t(m__io, this, m__root); @@ -70,9 +75,9 @@ void ubx_t::_clean_up() { ubx_t::rxm_rawx_t::rxm_rawx_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; - m_measurements = 0; - m__raw_measurements = 0; - m__io__raw_measurements = 0; + m_meas = 0; + m__raw_meas = 0; + m__io__raw_meas = 0; try { _read(); @@ -89,15 +94,15 @@ void ubx_t::rxm_rawx_t::_read() { m_num_meas = m__io->read_u1(); m_rec_stat = m__io->read_u1(); m_reserved1 = m__io->read_bytes(3); - m__raw_measurements = new std::vector(); - m__io__raw_measurements = new std::vector(); - m_measurements = new std::vector(); - const int l_measurements = num_meas(); - for (int i = 0; i < l_measurements; i++) { - m__raw_measurements->push_back(m__io->read_bytes(32)); - kaitai::kstream* io__raw_measurements = new kaitai::kstream(m__raw_measurements->at(m__raw_measurements->size() - 1)); - m__io__raw_measurements->push_back(io__raw_measurements); - m_measurements->push_back(new meas_t(io__raw_measurements, this, m__root)); + m__raw_meas = new std::vector(); + m__io__raw_meas = new std::vector(); + m_meas = new std::vector(); + const int l_meas = num_meas(); + for (int i = 0; i < l_meas; i++) { + m__raw_meas->push_back(m__io->read_bytes(32)); + kaitai::kstream* io__raw_meas = new kaitai::kstream(m__raw_meas->at(m__raw_meas->size() - 1)); + m__io__raw_meas->push_back(io__raw_meas); + m_meas->push_back(new measurement_t(io__raw_meas, this, m__root)); } } @@ -106,24 +111,24 @@ ubx_t::rxm_rawx_t::~rxm_rawx_t() { } void ubx_t::rxm_rawx_t::_clean_up() { - if (m__raw_measurements) { - delete m__raw_measurements; m__raw_measurements = 0; + if (m__raw_meas) { + delete m__raw_meas; m__raw_meas = 0; } - if (m__io__raw_measurements) { - for (std::vector::iterator it = m__io__raw_measurements->begin(); it != m__io__raw_measurements->end(); ++it) { + if (m__io__raw_meas) { + for (std::vector::iterator it = m__io__raw_meas->begin(); it != m__io__raw_meas->end(); ++it) { delete *it; } - delete m__io__raw_measurements; m__io__raw_measurements = 0; + delete m__io__raw_meas; m__io__raw_meas = 0; } - if (m_measurements) { - for (std::vector::iterator it = m_measurements->begin(); it != m_measurements->end(); ++it) { + if (m_meas) { + for (std::vector::iterator it = m_meas->begin(); it != m_meas->end(); ++it) { delete *it; } - delete m_measurements; m_measurements = 0; + delete m_meas; m_meas = 0; } } -ubx_t::rxm_rawx_t::meas_t::meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { +ubx_t::rxm_rawx_t::measurement_t::measurement_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; @@ -135,7 +140,7 @@ ubx_t::rxm_rawx_t::meas_t::meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__ } } -void ubx_t::rxm_rawx_t::meas_t::_read() { +void ubx_t::rxm_rawx_t::measurement_t::_read() { m_pr_mes = m__io->read_f8le(); m_cp_mes = m__io->read_f8le(); m_do_mes = m__io->read_f4le(); @@ -152,11 +157,11 @@ void ubx_t::rxm_rawx_t::meas_t::_read() { m_reserved3 = m__io->read_bytes(1); } -ubx_t::rxm_rawx_t::meas_t::~meas_t() { +ubx_t::rxm_rawx_t::measurement_t::~measurement_t() { _clean_up(); } -void ubx_t::rxm_rawx_t::meas_t::_clean_up() { +void ubx_t::rxm_rawx_t::measurement_t::_clean_up() { } ubx_t::rxm_sfrbx_t::rxm_sfrbx_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { @@ -198,6 +203,89 @@ void ubx_t::rxm_sfrbx_t::_clean_up() { } } +ubx_t::nav_sat_t::nav_sat_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + m_svs = 0; + m__raw_svs = 0; + m__io__raw_svs = 0; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::nav_sat_t::_read() { + m_itow = m__io->read_u4le(); + m_version = m__io->read_u1(); + m_num_svs = m__io->read_u1(); + m_reserved = m__io->read_bytes(2); + m__raw_svs = new std::vector(); + m__io__raw_svs = new std::vector(); + m_svs = new std::vector(); + const int l_svs = num_svs(); + for (int i = 0; i < l_svs; i++) { + m__raw_svs->push_back(m__io->read_bytes(12)); + kaitai::kstream* io__raw_svs = new kaitai::kstream(m__raw_svs->at(m__raw_svs->size() - 1)); + m__io__raw_svs->push_back(io__raw_svs); + m_svs->push_back(new nav_t(io__raw_svs, this, m__root)); + } +} + +ubx_t::nav_sat_t::~nav_sat_t() { + _clean_up(); +} + +void ubx_t::nav_sat_t::_clean_up() { + if (m__raw_svs) { + delete m__raw_svs; m__raw_svs = 0; + } + if (m__io__raw_svs) { + for (std::vector::iterator it = m__io__raw_svs->begin(); it != m__io__raw_svs->end(); ++it) { + delete *it; + } + delete m__io__raw_svs; m__io__raw_svs = 0; + } + if (m_svs) { + for (std::vector::iterator it = m_svs->begin(); it != m_svs->end(); ++it) { + delete *it; + } + delete m_svs; m_svs = 0; + } +} + +ubx_t::nav_sat_t::nav_t::nav_t(kaitai::kstream* p__io, ubx_t::nav_sat_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { + m__parent = p__parent; + m__root = p__root; + + try { + _read(); + } catch(...) { + _clean_up(); + throw; + } +} + +void ubx_t::nav_sat_t::nav_t::_read() { + m_gnss_id = static_cast(m__io->read_u1()); + m_sv_id = m__io->read_u1(); + m_cno = m__io->read_u1(); + m_elev = m__io->read_s1(); + m_azim = m__io->read_s2le(); + m_pr_res = m__io->read_s2le(); + m_flags = m__io->read_u4le(); +} + +ubx_t::nav_sat_t::nav_t::~nav_t() { + _clean_up(); +} + +void ubx_t::nav_sat_t::nav_t::_clean_up() { +} + ubx_t::nav_pvt_t::nav_pvt_t(kaitai::kstream* p__io, ubx_t* p__parent, ubx_t* p__root) : kaitai::kstruct(p__io) { m__parent = p__parent; m__root = p__root; diff --git a/system/ubloxd/generated/ubx.h b/system/ubloxd/generated/ubx.h index 6be4ce8c4b..022108489f 100644 --- a/system/ubloxd/generated/ubx.h +++ b/system/ubloxd/generated/ubx.h @@ -16,6 +16,7 @@ class ubx_t : public kaitai::kstruct { public: class rxm_rawx_t; class rxm_sfrbx_t; + class nav_sat_t; class nav_pvt_t; class mon_hw2_t; class mon_hw_t; @@ -42,7 +43,7 @@ public: class rxm_rawx_t : public kaitai::kstruct { public: - class meas_t; + class measurement_t; rxm_rawx_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); @@ -53,18 +54,18 @@ public: public: ~rxm_rawx_t(); - class meas_t : public kaitai::kstruct { + class measurement_t : public kaitai::kstruct { public: - meas_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent = 0, ubx_t* p__root = 0); + measurement_t(kaitai::kstream* p__io, ubx_t::rxm_rawx_t* p__parent = 0, ubx_t* p__root = 0); private: void _read(); void _clean_up(); public: - ~meas_t(); + ~measurement_t(); private: double m_pr_mes; @@ -110,11 +111,11 @@ public: uint8_t m_num_meas; uint8_t m_rec_stat; std::string m_reserved1; - std::vector* m_measurements; + std::vector* m_meas; ubx_t* m__root; ubx_t* m__parent; - std::vector* m__raw_measurements; - std::vector* m__io__raw_measurements; + std::vector* m__raw_meas; + std::vector* m__io__raw_meas; public: double rcv_tow() const { return m_rcv_tow; } @@ -123,11 +124,11 @@ public: uint8_t num_meas() const { return m_num_meas; } uint8_t rec_stat() const { return m_rec_stat; } std::string reserved1() const { return m_reserved1; } - std::vector* measurements() const { return m_measurements; } + std::vector* meas() const { return m_meas; } ubx_t* _root() const { return m__root; } ubx_t* _parent() const { return m__parent; } - std::vector* _raw_measurements() const { return m__raw_measurements; } - std::vector* _io__raw_measurements() const { return m__io__raw_measurements; } + std::vector* _raw_meas() const { return m__raw_meas; } + std::vector* _io__raw_meas() const { return m__io__raw_meas; } }; class rxm_sfrbx_t : public kaitai::kstruct { @@ -170,6 +171,79 @@ public: ubx_t* _parent() const { return m__parent; } }; + class nav_sat_t : public kaitai::kstruct { + + public: + class nav_t; + + nav_sat_t(kaitai::kstream* p__io, ubx_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~nav_sat_t(); + + class nav_t : public kaitai::kstruct { + + public: + + nav_t(kaitai::kstream* p__io, ubx_t::nav_sat_t* p__parent = 0, ubx_t* p__root = 0); + + private: + void _read(); + void _clean_up(); + + public: + ~nav_t(); + + private: + gnss_type_t m_gnss_id; + uint8_t m_sv_id; + uint8_t m_cno; + int8_t m_elev; + int16_t m_azim; + int16_t m_pr_res; + uint32_t m_flags; + ubx_t* m__root; + ubx_t::nav_sat_t* m__parent; + + public: + gnss_type_t gnss_id() const { return m_gnss_id; } + uint8_t sv_id() const { return m_sv_id; } + uint8_t cno() const { return m_cno; } + int8_t elev() const { return m_elev; } + int16_t azim() const { return m_azim; } + int16_t pr_res() const { return m_pr_res; } + uint32_t flags() const { return m_flags; } + ubx_t* _root() const { return m__root; } + ubx_t::nav_sat_t* _parent() const { return m__parent; } + }; + + private: + uint32_t m_itow; + uint8_t m_version; + uint8_t m_num_svs; + std::string m_reserved; + std::vector* m_svs; + ubx_t* m__root; + ubx_t* m__parent; + std::vector* m__raw_svs; + std::vector* m__io__raw_svs; + + public: + uint32_t itow() const { return m_itow; } + uint8_t version() const { return m_version; } + uint8_t num_svs() const { return m_num_svs; } + std::string reserved() const { return m_reserved; } + std::vector* svs() const { return m_svs; } + ubx_t* _root() const { return m__root; } + ubx_t* _parent() const { return m__parent; } + std::vector* _raw_svs() const { return m__raw_svs; } + std::vector* _io__raw_svs() const { return m__io__raw_svs; } + }; + class nav_pvt_t : public kaitai::kstruct { public: diff --git a/system/ubloxd/tests/ublox.py b/system/ubloxd/tests/ublox.py index 80abc64e2c..0d271ad785 100644 --- a/system/ubloxd/tests/ublox.py +++ b/system/ubloxd/tests/ublox.py @@ -48,6 +48,7 @@ MSG_NAV_TIMEGPS = 0x20 MSG_NAV_TIMEUTC = 0x21 MSG_NAV_CLOCK = 0x22 MSG_NAV_SVINFO = 0x30 +MSG_NAV_SAT = 0x35 MSG_NAV_AOPSTATUS = 0x60 MSG_NAV_DGPS = 0x31 MSG_NAV_DOP = 0x04 diff --git a/system/ubloxd/ublox_msg.cc b/system/ubloxd/ublox_msg.cc index 811492ba9b..a01187d560 100644 --- a/system/ubloxd/ublox_msg.cc +++ b/system/ubloxd/ublox_msg.cc @@ -434,7 +434,7 @@ kj::Array UbloxMsgParser::gen_rxm_rawx(ubx_t::rxm_rawx_t *msg) { mr.setGpsWeek(msg->week()); auto mb = mr.initMeasurements(msg->num_meas()); - auto measurements = *msg->measurements(); + auto measurements = *msg->meas(); for(int8_t i = 0; i < msg->num_meas(); i++) { mb[i].setSvId(measurements[i]->sv_id()); mb[i].setPseudorange(measurements[i]->pr_mes()); @@ -463,6 +463,22 @@ kj::Array UbloxMsgParser::gen_rxm_rawx(ubx_t::rxm_rawx_t *msg) { return capnp::messageToFlatArray(msg_builder); } +kj::Array UbloxMsgParser::gen_nav_sat(ubx_t::nav_sat_t *msg) { + MessageBuilder msg_builder; + auto sr = msg_builder.initEvent().initUbloxGnss().initSatReport(); + sr.setITow(msg->itow()); + + auto svs = sr.initSvs(msg->num_svs()); + auto svs_data = *msg->svs(); + for(int8_t i = 0; i < msg->num_svs(); i++) { + svs[i].setSvId(svs_data[i]->sv_id()); + svs[i].setGnssId(svs_data[i]->gnss_id()); + svs[i].setFlagsBitfield(svs_data[i]->flags()); + } + + return capnp::messageToFlatArray(msg_builder); +} + kj::Array UbloxMsgParser::gen_mon_hw(ubx_t::mon_hw_t *msg) { MessageBuilder msg_builder; auto hwStatus = msg_builder.initEvent().initUbloxGnss().initHwStatus(); diff --git a/system/ubloxd/ublox_msg.h b/system/ubloxd/ublox_msg.h index a6e0623aa0..a52a7db3e5 100644 --- a/system/ubloxd/ublox_msg.h +++ b/system/ubloxd/ublox_msg.h @@ -102,6 +102,7 @@ class UbloxMsgParser { kj::Array gen_rxm_rawx(ubx_t::rxm_rawx_t *msg); kj::Array gen_mon_hw(ubx_t::mon_hw_t *msg); kj::Array gen_mon_hw2(ubx_t::mon_hw2_t *msg); + kj::Array gen_nav_sat(ubx_t::nav_sat_t *msg); private: inline bool valid_cheksum(); diff --git a/system/ubloxd/ubx.ksy b/system/ubloxd/ubx.ksy index 6945680d32..02c757fe71 100644 --- a/system/ubloxd/ubx.ksy +++ b/system/ubloxd/ubx.ksy @@ -17,6 +17,7 @@ seq: 0x0215: rxm_rawx 0x0a09: mon_hw 0x0a0b: mon_hw2 + 0x0135: nav_sat instances: checksum: pos: length + 6 @@ -142,13 +143,13 @@ types: type: u1 - id: reserved1 size: 3 - - id: measurements - type: meas + - id: meas + type: measurement size: 32 repeat: expr repeat-expr: num_meas types: - meas: + measurement: seq: - id: pr_mes type: f8 @@ -179,6 +180,39 @@ types: type: u1 - id: reserved3 size: 1 + nav_sat: + seq: + - id: itow + type: u4 + - id: version + type: u1 + - id: num_svs + type: u1 + - id: reserved + size: 2 + - id: svs + type: nav + size: 12 + repeat: expr + repeat-expr: num_svs + types: + nav: + seq: + - id: gnss_id + type: u1 + enum: gnss_type + - id: sv_id + type: u1 + - id: cno + type: u1 + - id: elev + type: s1 + - id: azim + type: s2 + - id: pr_res + type: s2 + - id: flags + type: u4 nav_pvt: seq: From f00c108acb49bb633167dfdfcbdf84461cf59025 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 16 Mar 2023 01:54:22 +0800 Subject: [PATCH 1095/1179] cabana: eliminate deep copy of events in live stream mode (#27588) --- tools/cabana/chartswidget.cc | 23 +++++------- tools/cabana/chartswidget.h | 2 +- tools/cabana/streams/abstractstream.h | 2 +- tools/cabana/streams/livestream.cc | 51 ++++++++++----------------- tools/cabana/streams/livestream.h | 24 +++++++++---- 5 files changed, 45 insertions(+), 57 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 184d41ca0b..61afb871ae 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -108,14 +108,14 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { void ChartsWidget::eventsMerged() { { - assert(!can->liveStreaming()); QFutureSynchronizer future_synchronizer; - const auto events = can->events(); for (auto c : charts) { - future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr, events, true)); + future_synchronizer.addFuture(QtConcurrent::run(c, &ChartView::updateSeries, nullptr)); } } - updateState(); + if (can->isPaused()) { + updateState(); + } } void ChartsWidget::zoomIn(double min, double max) { @@ -133,20 +133,13 @@ void ChartsWidget::zoomReset() { void ChartsWidget::updateState() { if (charts.isEmpty()) return; - const auto events = can->events(); - if (can->liveStreaming()) { - // appends incoming events to the end of series - for (auto c : charts) { - c->updateSeries(nullptr, events, false); - } - } - const double cur_sec = can->currentSec(); if (!is_zoomed) { double pos = (cur_sec - display_range.first) / std::max(1.0, (display_range.second - display_range.first)); if (pos < 0 || pos > 0.8) { display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1); } + auto events = can->events(); double max_event_sec = events->empty() ? 0 : (events->back()->mono_time / 1e9 - can->routeStartTime()); double max_sec = std::min(std::floor(display_range.first + max_chart_range), max_event_sec); display_range.first = std::max(0.0, max_sec - max_chart_range); @@ -502,11 +495,11 @@ void ChartView::updateSeriesPoints() { } } -void ChartView::updateSeries(const cabana::Signal *sig, const std::vector *events, bool clear) { - events = events ? events : can->events(); +void ChartView::updateSeries(const cabana::Signal *sig) { + const auto events = can->events(); for (auto &s : sigs) { if (!sig || s.sig == sig) { - if (clear) { + if (!can->liveStreaming()) { s.vals.clear(); s.step_vals.clear(); s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index bdc924ff83..c7470a6f12 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -32,7 +32,7 @@ public: ChartView(QWidget *parent = nullptr); void addSeries(const MessageId &msg_id, const cabana::Signal *sig); bool hasSeries(const MessageId &msg_id, const cabana::Signal *sig) const; - void updateSeries(const cabana::Signal *sig = nullptr, const std::vector *events = nullptr, bool clear = true); + void updateSeries(const cabana::Signal *sig = nullptr); void updatePlot(double cur, double min, double max); void setSeriesType(SeriesType type); void updatePlotArea(int left); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index de7c394303..d1cf9d8037 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -59,7 +59,7 @@ public: QSet sources; protected: - void process(QHash *); + virtual void process(QHash *); bool updateEvent(const Event *event); void updateLastMsgsTo(double sec); diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 592d883c4c..256cfc5a3e 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -1,10 +1,8 @@ #include "tools/cabana/streams/livestream.h" -LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), AbstractStream(parent, true) { - timer = new QTimer(this); - timer->callOnTimeout(this, &LiveStream::removeExpiredEvents); - timer->start(3 * 1000); +#include +LiveStream::LiveStream(QObject *parent, QString address) : zmq_address(address), AbstractStream(parent, true) { stream_thread = new QThread(this); QObject::connect(stream_thread, &QThread::started, [=]() { streamThread(); }); QObject::connect(stream_thread, &QThread::finished, stream_thread, &QThread::deleteLater); @@ -15,8 +13,6 @@ LiveStream::~LiveStream() { stream_thread->requestInterruption(); stream_thread->quit(); stream_thread->wait(); - for (Event *e : can_events) ::delete e; - for (auto m : messages) delete m; } void LiveStream::streamThread() { @@ -35,11 +31,8 @@ void LiveStream::streamThread() { QThread::msleep(50); continue; } - AlignedBuffer *buf = messages.emplace_back(new AlignedBuffer()); - Event *evt = ::new Event(buf->align(msg)); - delete msg; - - handleEvent(evt); + std::lock_guard lk(lock); + handleEvent(messages.emplace_back(msg).event); // TODO: write stream to log file to replay it with cabana --data_dir flag. } } @@ -53,11 +46,10 @@ void LiveStream::handleEvent(Event *evt) { emit streamStarted(); } - std::lock_guard lk(lock); - can_events.push_back(evt); + received.push_back(evt); if (!pause_) { if (speed_ < 1 && last_update_ts > 0) { - auto it = std::upper_bound(can_events.cbegin(), can_events.cend(), current_ts, [](uint64_t ts, auto &e) { + auto it = std::upper_bound(received.cbegin(), received.cend(), current_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); if (it != can_events.cend()) { @@ -73,27 +65,20 @@ void LiveStream::handleEvent(Event *evt) { } } -void LiveStream::removeExpiredEvents() { - std::lock_guard lk(lock); - if (can_events.size() > 0) { - const uint64_t max_ns = settings.max_cached_minutes * 60 * 1e9; - const uint64_t last_ns = can_events.back()->mono_time; - while (!can_events.empty() && (last_ns - can_events.front()->mono_time) > max_ns) { - ::delete can_events.front(); - delete messages.front(); - can_events.pop_front(); - messages.pop_front(); +void LiveStream::process(QHash *last_messages) { + { + std::lock_guard lk(lock); + uint64_t last_ts = can_events.empty() ? 0 : can_events.back()->mono_time; + auto first = std::upper_bound(received.cbegin(), received.cend(), last_ts, [](uint64_t ts, auto &e) { + return ts < e->mono_time; + }); + can_events.insert(can_events.end(), first, received.cend()); + if (speed_ == 1) { + received.clear(); } } -} - -const std::vector *LiveStream::events() const { - std::lock_guard lk(lock); - if (events_vector.capacity() <= can_events.size()) { - events_vector.reserve(can_events.size() * 2); - } - events_vector.assign(can_events.begin(), can_events.end()); - return &events_vector; + emit eventsMerged(); + AbstractStream::process(last_messages); } void LiveStream::pause(bool pause) { diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 43f67ae95f..657d7e407f 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -1,6 +1,5 @@ #pragma once -#include #include "tools/cabana/streams/abstractstream.h" class LiveStream : public AbstractStream { @@ -17,17 +16,29 @@ public: void setSpeed(float speed) override { speed_ = std::min(1.0, speed); } bool isPaused() const override { return pause_; } void pause(bool pause) override; - const std::vector *events() const override; + const std::vector *events() const override { return &can_events; } protected: + void process(QHash *) override; virtual void handleEvent(Event *evt); virtual void streamThread(); - virtual void removeExpiredEvents(); + + struct Msg { + Msg(Message *m) { + event = ::new Event(aligned_buf.align(m)); + delete m; + } + ~Msg() { + ::delete event; + } + Event *event; + AlignedBuffer aligned_buf; + }; mutable std::mutex lock; - mutable std::vector events_vector; - std::deque can_events; - std::deque messages; + std::vector can_events; + std::vector received; + std::deque messages; std::atomic start_ts = 0; std::atomic current_ts = 0; std::atomic speed_ = 1; @@ -36,5 +47,4 @@ protected: const QString zmq_address; QThread *stream_thread; - QTimer *timer; }; From 9a6bcba7416b9e3f4dcf527131f4ca7250bb0f35 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Wed, 15 Mar 2023 14:34:33 -0700 Subject: [PATCH 1096/1179] UI: remove spammy CameraView log --- selfdrive/ui/qt/widgets/cameraview.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc index 10300da55c..de3b64cffd 100644 --- a/selfdrive/ui/qt/widgets/cameraview.cc +++ b/selfdrive/ui/qt/widgets/cameraview.cc @@ -374,7 +374,6 @@ void CameraWidget::vipcThread() { clearFrames(); auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); if (streams.empty()) { - qWarning() << "VisionIPC connected, but no streams available"; QThread::msleep(100); continue; } From 629e5f6bf21460f1f50d0a56c131440e0ab4f0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 15:16:47 -0700 Subject: [PATCH 1097/1179] Fix qcom laika caching and test (#27594) --- selfdrive/locationd/laikad.py | 6 +- selfdrive/locationd/test/test_laikad.py | 154 ++++++++++++++---------- 2 files changed, 93 insertions(+), 67 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 53fbf36066..5b12c7a16a 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -94,6 +94,7 @@ class Laikad: nav_list: List = sum([v for k,v in self.astro_dog.navs.items()], []) ephem_cache = ephemeris_structs.EphemerisCache(**{'glonassEphemerides': [e.data for e in nav_list if e.prn[0]=='R'], 'gpsEphemerides': [e.data for e in nav_list if e.prn[0]=='G']}) + put_nonblocking(EPHEMERIS_CACHE, ephem_cache.to_bytes()) cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time @@ -157,6 +158,8 @@ class Laikad: if self.gps_week is None: return ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) + self.astro_dog.add_orbits({ephem.prn: [ephem]}) + else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) @@ -167,7 +170,7 @@ class Laikad: else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return - self.astro_dog.add_navs({ephem.prn: [ephem]}) + self.astro_dog.add_navs({ephem.prn: [ephem]}) self.cache_ephemeris() def process_report(self, new_meas, t): @@ -421,7 +424,6 @@ def main(sm=None, pm=None, qc=None): if sm.updated[raw_gnss_socket]: gnss_msg = sm[raw_gnss_socket] - msg = process_msg(laikad, gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) if msg is None: # TODO: beautify this, locationd needs a valid message diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index be79ff16bc..b22c9994b7 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -15,7 +15,7 @@ from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime from laika.helpers import ConstellationId, TimeRangeHolder -from laika.raw_gnss import GNSSMeasurement, read_raw_ublox +from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader @@ -70,14 +70,23 @@ def get_log(segs=range(0)): low_gnss.append(mb.as_reader()) else: low_gnss.append(m) - return all_logs, low_gnss +def get_log_qcom(segs=range(0)): + logs = [] + for i in segs: + logs.extend(LogReader(get_url("b0b3cba7abf862d1|2023-03-11--09-40-33", i))) + all_logs = [m for m in logs if m.which() == 'qcomGnss'] + return all_logs def verify_messages(lr, laikad, return_one_success=False): good_msgs = [] for m in lr: - msg = laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=True) + if m.which() == 'ubloxGnss': + gnss_msg = m.ubloxGnss + else: + gnss_msg = m.qcomGnss + msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=True) if msg is not None and len(msg.gnssMeasurements.correctedMeasurements) > 0: good_msgs.append(msg) if return_one_success: @@ -87,10 +96,16 @@ def verify_messages(lr, laikad, return_one_success=False): def get_first_gps_time(logs): for m in logs: - if m.ubloxGnss.which == 'measurementReport': - new_meas = read_raw_ublox(m.ubloxGnss.measurementReport) - if len(new_meas) > 0: - return new_meas[0].recv_time + if m.which() == 'ubloxGnss': + if m.ubloxGnss.which == 'measurementReport': + new_meas = read_raw_ublox(m.ubloxGnss.measurementReport) + if len(new_meas) > 0: + return new_meas[0].recv_time + else: + if m.qcomGnss.which == 'measurementReport': + new_meas = read_raw_qcom(m.qcomGnss.measurementReport) + if len(new_meas) > 0: + return new_meas[0].recv_time def get_measurement_mock(gpstime, sat_ephemeris): @@ -111,6 +126,7 @@ class TestLaikad(unittest.TestCase): logs, low_gnss = get_log(range(1)) cls.logs = logs cls.low_gnss = low_gnss + cls.logs_qcom = get_log_qcom(range(1)) first_gps_time = get_first_gps_time(logs) cls.first_gps_time = first_gps_time @@ -209,12 +225,13 @@ class TestLaikad(unittest.TestCase): self.assertTrue(kf_valid) def test_laika_online_nav_only(self): - laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV) - # Disable fetch_orbits to test NAV only - correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 559 - self.assertEqual(correct_msgs_expected, len(correct_msgs)) - self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV, use_qcom=use_qcom) + # Disable fetch_orbits to test NAV only + correct_msgs = verify_messages(logs, laikad) + correct_msgs_expected = 42 if use_qcom else 559 + self.assertEqual(correct_msgs_expected, len(correct_msgs)) + self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @mock.patch('laika.downloader.download_and_cache_file') def test_laika_offline(self, downloader_mock): @@ -247,65 +264,73 @@ class TestLaikad(unittest.TestCase): print(min(laikad.astro_dog.navs[prn], key=lambda e: e.epoch).epoch.as_datetime()) def test_get_navs_in_process(self): - laikad = Laikad(auto_update=False) - has_navs = False - for m in self.logs: - laikad.process_gnss_msg(m.ubloxGnss, m.logMonoTime, block=False) - if laikad.orbit_fetch_future is not None: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if has_navs: - break - self.assertTrue(has_navs) - self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom) + has_navs = False + has_fix = False + for m in logs: + gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss + out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) + if laikad.orbit_fetch_future is not None: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.orbits.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + if out_msg is not None: + has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): - laikad = Laikad(auto_update=True, save_ephemeris=True) + use_qcom = True + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=True, save_ephemeris=True, use_qcom=use_qcom) + def wait_for_cache(): + max_time = 2 + while Params().get(EPHEMERIS_CACHE) is None: + time.sleep(0.1) + max_time -= 0.1 + if max_time < 0: + self.fail("Cache has not been written after 2 seconds") - def wait_for_cache(): - max_time = 2 - while Params().get(EPHEMERIS_CACHE) is None: - time.sleep(0.1) - max_time -= 0.1 - if max_time < 0: - self.fail("Cache has not been written after 2 seconds") + # Test cache with no ephemeris + laikad.last_report_time = GPSTime(1,0) + laikad.cache_ephemeris() + wait_for_cache() + Params().remove(EPHEMERIS_CACHE) - # Test cache with no ephemeris - laikad.last_report_time = GPSTime(1,0) - laikad.cache_ephemeris() - wait_for_cache() - Params().remove(EPHEMERIS_CACHE) + #laikad.astro_dog.get_navs(self.first_gps_time) + laikad.last_report_time = GPSTime(2,0) + laikad.fetch_navs(self.first_gps_time, block=True) - #laikad.astro_dog.get_navs(self.first_gps_time) - laikad.last_report_time = GPSTime(2,0) - laikad.fetch_navs(self.first_gps_time, block=True) + # Wait for cache to save + wait_for_cache() - # Wait for cache to save - wait_for_cache() - - # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True) - # Verify navs are loaded from cache - self.dict_has_values(laikad.astro_dog.navs) - # Verify cache is working for only nav by running a segment - msg = verify_messages(self.logs, laikad, return_one_success=True) - self.assertIsNotNone(msg) - - with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: - # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently - laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() - laikad.fetch_navs(self.first_gps_time, block=False) - mock_method.assert_not_called() - - # Verify cache is working for only orbits by running a segment - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) - msg = verify_messages(self.logs, laikad, return_one_success=True) + # Check both nav and orbits separate + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) + # Verify navs are loaded from cache + self.dict_has_values(laikad.astro_dog.navs) + # Verify cache is working for only nav by running a segment + msg = verify_messages(logs, laikad, return_one_success=True) self.assertIsNotNone(msg) - # Verify orbit data is not downloaded - mock_method.assert_not_called() + with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: + # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently + laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() + laikad.fetch_navs(self.first_gps_time, block=False) + mock_method.assert_not_called() + + # Verify cache is working for only orbits by running a segment + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) + msg = verify_messages(self.logs, laikad, return_one_success=True) + self.assertIsNotNone(msg) + # Verify orbit data is not downloaded + mock_method.assert_not_called() + break def test_low_gnss_meas(self): cnt = 0 @@ -323,6 +348,5 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) - if __name__ == "__main__": unittest.main() From 896fa029f93501af7871e7e5edced2bc0885d53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 20:06:29 -0700 Subject: [PATCH 1098/1179] Laikad: cleanup time range holder (#27595) * cleanup time range holder * update * unused import * unused import * unused import * bump laika --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 4 +-- selfdrive/locationd/test/test_laikad.py | 41 +++++++++++++------------ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/laika_repo b/laika_repo index b896cdbbd1..354afd63f7 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit b896cdbbd1e8f85df25a1afa0c9a2ec150b72f92 +Subproject commit 354afd63f74cac63669637e3d5e33d416405c428 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 5b12c7a16a..3f96e4d9f3 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -35,7 +35,7 @@ POS_FIX_RESIDUAL_THRESHOLD = 100.0 class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, - valid_ephem_types=(EphemerisType.NAV,), + valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), save_ephemeris=False, use_qcom=False): """ valid_const: GNSS constellation which can be used @@ -158,7 +158,7 @@ class Laikad: if self.gps_week is None: return ephem = parse_qcom_ephem(gnss_msg.drSvPoly, self.gps_week) - self.astro_dog.add_orbits({ephem.prn: [ephem]}) + self.astro_dog.add_qcom_polys({ephem.prn: [ephem]}) else: if gnss_msg.which() == 'ephemeris': diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index b22c9994b7..2e03551f6e 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -6,7 +6,7 @@ import cereal.messaging as messaging from common.params import Params from datetime import datetime from unittest import mock -from unittest.mock import patch +#from unittest.mock import patch from tqdm import tqdm @@ -14,7 +14,7 @@ from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime -from laika.helpers import ConstellationId, TimeRangeHolder +from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url @@ -261,11 +261,10 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) prn = "R01" self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) - print(min(laikad.astro_dog.navs[prn], key=lambda e: e.epoch).epoch.as_datetime()) def test_get_navs_in_process(self): for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom) + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) has_navs = False has_fix = False for m in logs: @@ -275,14 +274,14 @@ class TestLaikad(unittest.TestCase): laikad.orbit_fetch_future.result() vals = laikad.astro_dog.navs.values() has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.orbits.values() + vals = laikad.astro_dog.qcom_polys.values() has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 if out_msg is not None: has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid - + self.assertTrue(has_navs or has_polys) self.assertTrue(has_fix) - self.assertGreater(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): @@ -318,19 +317,22 @@ class TestLaikad(unittest.TestCase): msg = verify_messages(logs, laikad, return_one_success=True) self.assertIsNotNone(msg) - with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: - # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently - laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() - laikad.fetch_navs(self.first_gps_time, block=False) - mock_method.assert_not_called() - # Verify cache is working for only orbits by running a segment - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) - msg = verify_messages(self.logs, laikad, return_one_success=True) - self.assertIsNotNone(msg) - # Verify orbit data is not downloaded - mock_method.assert_not_called() - break + + #TODO test cache with only orbits + #with patch('selfdrive.locationd.laikad.get_orbit_data', return_value=None) as mock_method: + # # Verify no orbit downloads even if orbit fetch times is reset since the cache has recently been saved and we don't want to download high frequently + # laikad.astro_dog.orbit_fetched_times = TimeRangeHolder() + # laikad.fetch_navs(self.first_gps_time, block=False) + # mock_method.assert_not_called() + + # # Verify cache is working for only orbits by running a segment + # laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT, save_ephemeris=True) + # msg = verify_messages(self.logs, laikad, return_one_success=True) + # self.assertIsNotNone(msg) + # # Verify orbit data is not downloaded + # mock_method.assert_not_called() + #break def test_low_gnss_meas(self): cnt = 0 @@ -348,5 +350,6 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) + if __name__ == "__main__": unittest.main() From 38cb42f76aa9fe21b0e71569934864d578499c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 15 Mar 2023 20:26:19 -0700 Subject: [PATCH 1099/1179] LaikaD new cache version (#27596) --- common/params.cc | 2 +- selfdrive/locationd/laikad.py | 2 +- system/loggerd/tests/test_loggerd.py | 8 ++++---- tools/gpstest/rpc_server.py | 2 +- tools/gpstest/test_laikad.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/params.cc b/common/params.cc index e74c63bf6a..e71f802d61 100644 --- a/common/params.cc +++ b/common/params.cc @@ -137,7 +137,7 @@ std::unordered_map keys = { {"IsReleaseBranch", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, - {"LaikadEphemerisV2", PERSISTENT | DONT_LOG}, + {"LaikadEphemerisV3", PERSISTENT | DONT_LOG}, {"LanguageSetting", PERSISTENT}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastGPSPosition", PERSISTENT}, diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 3f96e4d9f3..f43e68ceba 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -27,7 +27,7 @@ from selfdrive.locationd.models.gnss_kf import States as GStates from system.swaglog import cloudlog MAX_TIME_GAP = 10 -EPHEMERIS_CACHE = 'LaikadEphemerisV2' +EPHEMERIS_CACHE = 'LaikadEphemerisV3' DOWNLOADS_CACHE_FOLDER = "/tmp/comma_download_cache/" CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index 54098d13d0..f39b8bb9d6 100755 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -86,7 +86,7 @@ class TestLoggerd(unittest.TestCase): params.clear_all() for k, _, v in fake_params: params.put(k, v) - params.put("LaikadEphemerisV2", "abc") + params.put("LaikadEphemerisV3", "abc") lr = list(LogReader(str(self._gen_bootlog()))) initData = lr[0].initData @@ -103,14 +103,14 @@ class TestLoggerd(unittest.TestCase): # check params logged_params = {entry.key: entry.value for entry in initData.params.entries} - expected_params = set(k for k, _, __ in fake_params) | {'LaikadEphemerisV2'} + expected_params = set(k for k, _, __ in fake_params) | {'LaikadEphemerisV3'} assert set(logged_params.keys()) == expected_params, set(logged_params.keys()) ^ expected_params - assert logged_params['LaikadEphemerisV2'] == b'', f"DONT_LOG param value was logged: {repr(logged_params['LaikadEphemerisV2'])}" + assert logged_params['LaikadEphemerisV3'] == b'', f"DONT_LOG param value was logged: {repr(logged_params['LaikadEphemerisV3'])}" for param_key, initData_key, v in fake_params: self.assertEqual(getattr(initData, initData_key), v) self.assertEqual(logged_params[param_key].decode(), v) - params.put("LaikadEphemerisV2", "") + params.put("LaikadEphemerisV3", "") def test_rotation(self): os.environ["LOGGERD_TEST"] = "1" diff --git a/tools/gpstest/rpc_server.py b/tools/gpstest/rpc_server.py index a368566982..178e8b2c3c 100644 --- a/tools/gpstest/rpc_server.py +++ b/tools/gpstest/rpc_server.py @@ -17,7 +17,7 @@ ALT_DELTA = 30 MATCH_NUM = 10 REPORT_STATS = 10 -EPHEM_CACHE = "/data/params/d/LaikadEphemerisV2" +EPHEM_CACHE = "/data/params/d/LaikadEphemerisV3" DOWNLOAD_CACHE = "/tmp/comma_download_cache" SERVER_LOG_FILE = "/tmp/fuzzy_server.log" diff --git a/tools/gpstest/test_laikad.py b/tools/gpstest/test_laikad.py index 24ffa6c424..689b0f0b9f 100644 --- a/tools/gpstest/test_laikad.py +++ b/tools/gpstest/test_laikad.py @@ -39,7 +39,7 @@ class TestLaikad(unittest.TestCase): def setUp(self): # ensure laikad cold start - Params().remove("LaikadEphemerisV2") + Params().remove("LaikadEphemerisV3") os.environ["LAIKAD_NO_INTERNET"] = "1" managed_processes['laikad'].start() From 57d10a26e7f60e96134c7741716b5c6892f78fda Mon Sep 17 00:00:00 2001 From: Cameron Clough Date: Thu, 16 Mar 2023 03:58:08 +0000 Subject: [PATCH 1100/1179] fix tabulate types (#27598) fix types for tabulate --- poetry.lock | 11 +++++------ pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index ec4022c81f..521bf3c0c3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4357,9 +4357,9 @@ types-urllib3 = "<1.27" [[package]] name = "types-tabulate" -version = "0.9.0.1" +version = "0.8.11" description = "Typing stubs for tabulate" -category = "main" +category = "dev" optional = false python-versions = "*" @@ -4575,7 +4575,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "669485055bf8d77336509cb7a3878e06aa32431c520825948914d76b57347fde" +content-hash = "043d4bffddfddc2a5d6d20f51662a9992754831b387eb7e318c2420f3240049e" [metadata.files] adal = [ @@ -5618,7 +5618,6 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, - {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -8059,8 +8058,8 @@ types-requests = [ {file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"}, ] types-tabulate = [ - {file = "types-tabulate-0.9.0.1.tar.gz", hash = "sha256:e486292c279f19247865bdabe802419740a0e74b53444e7f7a8009e08129da5d"}, - {file = "types_tabulate-0.9.0.1-py3-none-any.whl", hash = "sha256:be2ea0de05f615ccfcbadf6206aa720e265955eb1de23e343aec9d8bf3fa9aaa"}, + {file = "types-tabulate-0.8.11.tar.gz", hash = "sha256:17a5fa3b5ca453815778fc9865e8ecd0118b07b2b9faff3e2b06fe448174dd5e"}, + {file = "types_tabulate-0.8.11-py3-none-any.whl", hash = "sha256:af811268241e8fb87b63c052c87d1e329898a93191309d5d42111372232b2e0e"}, ] types-urllib3 = [ {file = "types-urllib3-1.26.25.1.tar.gz", hash = "sha256:a948584944b2412c9a74b9cf64f6c48caf8652cb88b38361316f6d15d8a184cd"}, diff --git a/pyproject.toml b/pyproject.toml index b1ad273cd7..c53dcb5381 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,6 @@ urllib3 = "^1.26.10" utm = "^0.7.0" websocket_client = "^1.3.3" polyline = "^1.4.0" -types-tabulate = "^0.9.0.1" [tool.poetry.group.dev.dependencies] @@ -108,6 +107,7 @@ types-certifi = "^2021.10.8" types-pycurl = "^7.45.1" types-PyYAML = "^6.0" types-requests = "^2.28.11" +types-tabulate = "^0.8.10" [tool.poetry.group.xx] From d26d8b3ba9787dc02b9c116d7e750a3b36dd0846 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Thu, 16 Mar 2023 10:59:27 +0100 Subject: [PATCH 1101/1179] Improve OX frame timing jitter (#27582) * frame timing script * enable vsync output and improve fsin tracking * increase measurement time * fix python linting --------- Co-authored-by: Comma Device --- .../debug/internal/check_frame_frequencies.py | 43 +++++++++++++++++++ system/camerad/cameras/sensor2_i2c.h | 9 ++-- 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100755 selfdrive/debug/internal/check_frame_frequencies.py diff --git a/selfdrive/debug/internal/check_frame_frequencies.py b/selfdrive/debug/internal/check_frame_frequencies.py new file mode 100755 index 0000000000..9ac8bfc80e --- /dev/null +++ b/selfdrive/debug/internal/check_frame_frequencies.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import time +import statistics +import cereal.messaging as messaging + +from typing import Dict + +camera_states = [ + 'roadCameraState', + 'wideRoadCameraState', + 'driverCameraState' +] + +def fmt(val): + ref = 0.05 + return f"{val:.6f} ({100 * val / ref:.2f}%)" + +if __name__ == "__main__": + sm = messaging.SubMaster(camera_states) + + prev_sof = {state: None for state in camera_states} + diffs: Dict[str, list] = {state: [] for state in camera_states} + + st = time.monotonic() + while True: + sm.update() + + for state in camera_states: + if sm.updated[state]: + if prev_sof[state] is not None: + diffs[state].append((sm[state].timestampSof - prev_sof[state]) / 1e9) + prev_sof[state] = sm[state].timestampSof + + if time.monotonic() - st > 10: + for state in camera_states: + values = diffs[state] + ref = 0.05 + print(f"{state} \tMean: {fmt(statistics.mean(values))} \t Min: {fmt(min(values))} \t Max: {fmt(max(values))} \t Std: {statistics.stdev(values):.6f} \t Num frames: {len(values)}") + diffs[state] = [] + + print() + st = time.monotonic() diff --git a/system/camerad/cameras/sensor2_i2c.h b/system/camerad/cameras/sensor2_i2c.h index 83fcb8f7a9..4db4bfd4d8 100644 --- a/system/camerad/cameras/sensor2_i2c.h +++ b/system/camerad/cameras/sensor2_i2c.h @@ -58,7 +58,7 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { // SC ctrl {0x3001, 0x03}, // io_pad_oen - {0x3002, 0xf8}, // io_pad_oen + {0x3002, 0xfc}, // io_pad_oen {0x3005, 0x80}, // io_pad_out {0x3007, 0x01}, // io_pad_sel {0x3008, 0x80}, // io_pad_sel @@ -85,6 +85,9 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { {0x3882, 0x8}, {0x3883, 0x0D}, {0x3836, 0x1F}, {0x3837, 0x40}, + {0x3892, 0x44}, + {0x3823, 0x48}, + {0x3012, 0x41}, // SC_PHY_CTRL = 4 lane MIPI {0x3020, 0x05}, // SC_CTRL_20 @@ -179,8 +182,8 @@ struct i2c_random_wr_payload init_array_ox03c10[] = { {0x3820, 0x04}, {0x3821, 0x19}, - {0x3832, 0x00}, - {0x3834, 0x00}, + {0x3832, 0xF0}, + {0x3834, 0xF0}, {0x384c, 0x02}, {0x384d, 0x0d}, {0x3850, 0x00}, From c2ec18cb715766a7d83276f13cf26f1a86283f78 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 16 Mar 2023 10:43:22 -0700 Subject: [PATCH 1102/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index b231281c8b..c0aea3273a 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit b231281c8b2c79c46892576dee4c8a56d5e0b2d2 +Subproject commit c0aea3273a82a91f10554b1b3317727da99f4564 From 719901b57c1b21183c6208fa8142c56c7a18c61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 13:06:30 -0700 Subject: [PATCH 1103/1179] Bump laika (#27605) * bump laika * Update ref_commit --- laika_repo | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/laika_repo b/laika_repo index 354afd63f7..8463fe8fed 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 354afd63f74cac63669637e3d5e33d416405c428 +Subproject commit 8463fe8fed272f58093406a990532084bc060359 diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index dae7ceab1a..50288bfd03 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -b79fa775682401c25aa9ce38b5542b4206d0c56b +c8ba9450af16f9efc70eb76a5edc205aed53e779 From e6c514eb72f0c87186c637c8bbd9f19eabcaa140 Mon Sep 17 00:00:00 2001 From: kevinsdev <37430136+kevinsdev@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:24:22 -0700 Subject: [PATCH 1104/1179] Added firmware for 2021 Lexus NX Base (#27604) * Update values.py Added my 2021 Lexus NX 300 Base * Update values.py Added 2021 Lexus NX Base --- selfdrive/car/toyota/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index a8e143e80a..bd2228c3df 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1729,6 +1729,7 @@ FW_VERSIONS = { b'\x018966378B2100\x00\x00\x00\x00', b'\x018966378B3000\x00\x00\x00\x00', b'\x018966378B4100\x00\x00\x00\x00', + b'\x018966378G2000\x00\x00\x00\x00', b'\x018966378G3000\x00\x00\x00\x00', b'\x018966378B2000\x00\x00\x00\x00', ], From 5c383927859a20feccdccaf0102f8d0924d28134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 13:29:02 -0700 Subject: [PATCH 1105/1179] Laikad: always return msg (#27599) * always return msg * always return msg * Not all qcom constellations are understood * call error error --- selfdrive/locationd/laikad.py | 38 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index f43e68ceba..fe5126522c 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -125,8 +125,15 @@ class Laikad: def is_good_report(self, gnss_msg): if gnss_msg.which() == 'drMeasurementReport' and self.use_qcom: constellation_id = ConstellationId.from_qcom_source(gnss_msg.drMeasurementReport.source) - # TODO support GLONASS - return constellation_id in [ConstellationId.GPS, ConstellationId.SBAS] + # TODO: Understand and use remaining unknown constellations + try: + good_constellation = constellation_id in [ConstellationId.GPS, ConstellationId.SBAS] + except NotImplementedError: + good_constellation = False + # gpsWeek 65535 is received rarely from quectel, this cannot be + # passed to GnssMeasurements's gpsWeek (Int16) + good_week = not getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max + return good_constellation and good_week elif gnss_msg.which() == 'measurementReport' and not self.use_qcom: return True else: @@ -196,15 +203,15 @@ class Laikad: return position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, processed_measurements def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): + out_msg = messaging.new_message("gnssMeasurements") if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) - return None + return out_msg elif self.is_good_report(gnss_msg): - week, tow, new_meas = self.read_report(gnss_msg) self.gps_week = week if len(new_meas) == 0: - return None + return out_msg t = gnss_mono_time * 1e-9 if week > 0: @@ -215,17 +222,16 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: - return None + return out_msg position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) meas_msgs = [create_measurement_msg(m) for m in corrected_measurements] - msg = messaging.new_message("gnssMeasurements") measurement_msg = log.LiveLocationKalman.Measurement.new_message P_diag = self.gnss_kf.P.diagonal() kf_valid = all(self.kf_valid(t)) - msg.gnssMeasurements = { + out_msg.gnssMeasurements = { "gpsWeek": week, "gpsTimeOfWeek": tow, "kalmanPositionECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), @@ -240,7 +246,7 @@ class Laikad: "measTime": gnss_mono_time, "correctedMeasurements": meas_msgs } - return msg + return out_msg #elif gnss_msg.which() == 'ionoData': # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. @@ -377,15 +383,6 @@ class EphemerisSourceType(IntEnum): def process_msg(laikad, gnss_msg, mono_time, block=False): - # TODO: Understand and use remaining unknown constellations - if gnss_msg.which() == "drMeasurementReport": - if getattr(gnss_msg, gnss_msg.which()).source not in ['glonass', 'gps', 'beidou', 'sbas']: - return None - - if getattr(gnss_msg, gnss_msg.which()).gpsWeek > np.iinfo(np.int16).max: - # gpsWeek 65535 is received rarely from quectel, this cannot be - # passed to GnssMeasurements's gpsWeek (Int16) - return None return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) @@ -424,10 +421,7 @@ def main(sm=None, pm=None, qc=None): if sm.updated[raw_gnss_socket]: gnss_msg = sm[raw_gnss_socket] - msg = process_msg(laikad, gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) - if msg is None: - # TODO: beautify this, locationd needs a valid message - msg = messaging.new_message("gnssMeasurements") + msg = laikad.process_gnss_msg(gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) pm.send('gnssMeasurements', msg) if not laikad.got_first_gnss_msg and sm.updated['clocks']: From a11a5d6231c5d7e677dbd5d13a1ad3b0c21608bc Mon Sep 17 00:00:00 2001 From: freddiebd Date: Thu, 16 Mar 2023 20:34:52 +0000 Subject: [PATCH 1106/1179] VW MQB: Add FW for 2016 Golf Mk7 (#27581) --- selfdrive/car/volkswagen/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 694b4006f8..2b853f9d7d 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -394,6 +394,7 @@ FW_VERSIONS = { b'\xf1\x8704L906021DT\xf1\x895520', b'\xf1\x8704L906021DT\xf1\x898127', b'\xf1\x8704L906021N \xf1\x895518', + b'\xf1\x8704L906026BN\xf1\x891197', b'\xf1\x8704L906026BP\xf1\x897608', b'\xf1\x8704L906026NF\xf1\x899528', b'\xf1\x8704L906056CL\xf1\x893823', @@ -514,6 +515,7 @@ FW_VERSIONS = { b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\x0511A00403A0', b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\x0516A00604A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A00404A1', + b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A00504A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A00604A1', b'\xf1\x875Q0909144S \xf1\x891063\xf1\x82\x0516A07A02A1', b'\xf1\x875Q0909144T \xf1\x891072\xf1\x82\x0521A00507A1', From d5dfd3f1a69772c68a24a9069c50cc7fdb7b793c Mon Sep 17 00:00:00 2001 From: klaw73 <127580531+klaw73@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:38:02 -0400 Subject: [PATCH 1107/1179] Add missing FW for 2020 Lexus NX Hybrid (#27565) * Added fw for 2020LexusNXH * Added fw for 2020LexusNXH * Add fw to 2020Lexus NXH --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index bd2228c3df..326b07075b 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1752,6 +1752,7 @@ FW_VERSIONS = { CAR.LEXUS_NXH_TSS2: { (Ecu.engine, 0x7e0, None): [ b'\x0237887000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', + b'\x02378A0000\x00\x00\x00\x00\x00\x00\x00\x00A4701000\x00\x00\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'F152678210\x00\x00\x00\x00\x00\x00', @@ -1761,6 +1762,7 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F3301400\x00\x00\x00\x00', + b'\x018821F3301300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F78030A0\x00\x00\x00\x008646G2601200\x00\x00\x00\x00', From cb5573cbfd4b674d431be1fef04afe9928b58b83 Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Fri, 17 Mar 2023 05:25:31 +0800 Subject: [PATCH 1108/1179] VW MQB: Add FW for 2022 Skoda Kodiaq 1.5TSI (#27489) * VW MQB: Add FW for 2022 Skoda Kodiaq 1.5TSI carVin': 'TMBJB9NS3N8051692' * alphabetical order * add to docs --------- Co-authored-by: Cameron Clough Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 2b853f9d7d..5d8c6e13c5 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1075,6 +1075,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026DE\xf1\x895418', b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026HT\xf1\x893617', + b'\xf1\x8705E906018DJ\xf1\x890915', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', ], @@ -1084,6 +1085,7 @@ FW_VERSIONS = { b'\xf1\x870DL300012M \xf1\x892107', b'\xf1\x870DL300012N \xf1\x892110', b'\xf1\x870DL300013G \xf1\x892119', + b'\xf1\x870GC300046Q \xf1\x892802', ], (Ecu.srs, 0x715, None): [ b'\xf1\x873Q0959655AP\xf1\x890306\xf1\x82\r11110011110011421111314211', @@ -1091,11 +1093,13 @@ FW_VERSIONS = { b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1213001211001244212111442100', b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e1213001211001205212112052100', b'\xf1\x873Q0959655CQ\xf1\x890720\xf1\x82\x0e1213111211001205212112052111', + b'\xf1\x873Q0959655DJ\xf1\x890731\xf1\x82\x0e1513001511001205232113052J00', ], (Ecu.eps, 0x712, None): [ b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6050405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6060405', b'\xf1\x875Q0909143P \xf1\x892051\xf1\x820527T6070405', + b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G500', b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567T600G600', ], (Ecu.fwdRadar, 0x757, None): [ From fe358102f2df380c070b3cfaed28cd3c9d2ea91b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 16 Mar 2023 14:31:55 -0700 Subject: [PATCH 1109/1179] test: fix Honda and Hyundai tests (#27606) test honda and hyundai --- selfdrive/car/honda/tests/__init__.py | 0 selfdrive/car/hyundai/tests/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 selfdrive/car/honda/tests/__init__.py create mode 100644 selfdrive/car/hyundai/tests/__init__.py diff --git a/selfdrive/car/honda/tests/__init__.py b/selfdrive/car/honda/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/car/hyundai/tests/__init__.py b/selfdrive/car/hyundai/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 0d1e272b917b8c1a98453bbe78337a42cd8451fe Mon Sep 17 00:00:00 2001 From: martinl Date: Thu, 16 Mar 2023 23:32:22 +0200 Subject: [PATCH 1110/1179] Subaru: Add 2019 Forester FPv2 (#27500) * Subaru: Add 2019 Forester FPv2 * Update selfdrive/car/subaru/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/subaru/values.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py index 5c7d3f5e4d..9c4447631d 100644 --- a/selfdrive/car/subaru/values.py +++ b/selfdrive/car/subaru/values.py @@ -273,9 +273,11 @@ FW_VERSIONS = { b'\xa3 \031\024\000', b'\xa3 \x14\x01', b'\xf1\x00\xbb\r\x05', + b'\xa3 \x18&\x00', ], (Ecu.eps, 0x746, None): [ b'\x8d\xc0\x04\x00', + b'\x8d\xc0\x00\x00', ], (Ecu.fwdCamera, 0x787, None): [ b'\x00\x00e!\x1f@ \x11', @@ -292,6 +294,7 @@ FW_VERSIONS = { b'\xcb\"`p\a', b'\xf1\x00\xa2\x10\n', b'\xcf"`p\x07', + b'\xb6\xa2`A\x07', ], (Ecu.transmission, 0x7e1, None): [ b'\032\xf6B0\000', @@ -299,6 +302,7 @@ FW_VERSIONS = { b'\032\xf6b`\000', b'\x1a\xf6B`\x00', b'\x1a\xf6b0\x00', + b'\x1a\xe6B1\x00', ], }, CAR.FORESTER_PREGLOBAL: { From 61f25b5b958ec5f9d420fdd1c607d6665e9b48b1 Mon Sep 17 00:00:00 2001 From: Oxygen Date: Fri, 17 Mar 2023 05:48:29 +0800 Subject: [PATCH 1111/1179] Firmware version for TOYOTA Camry 2.0G, China built 2022.07 (#27558) Update values.py Firmware version for Carmy 2.0G, China Build 2022.07 Co-authored-by: Shane Smiskol --- selfdrive/car/toyota/values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 326b07075b..43f0593325 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -527,14 +527,17 @@ FW_VERSIONS = { CAR.CAMRY_TSS2: { (Ecu.eps, 0x7a1, None): [ b'8965B33630\x00\x00\x00\x00\x00\x00', + b'8965B33640\x00\x00\x00\x00\x00\x00', ], (Ecu.abs, 0x7b0, None): [ b'\x01F152606370\x00\x00\x00\x00\x00\x00', b'\x01F152606390\x00\x00\x00\x00\x00\x00', b'\x01F152606400\x00\x00\x00\x00\x00\x00', + b'\x01F152606431\x00\x00\x00\x00\x00\x00', ], (Ecu.engine, 0x700, None): [ b'\x018966306Q5000\x00\x00\x00\x00', + b'\x018966306Q9000\x00\x00\x00\x00', b'\x018966306T3100\x00\x00\x00\x00', b'\x018966306T3200\x00\x00\x00\x00', b'\x018966306T4000\x00\x00\x00\x00', @@ -542,11 +545,13 @@ FW_VERSIONS = { ], (Ecu.fwdRadar, 0x750, 0xf): [ b'\x018821F6201200\x00\x00\x00\x00', + b'\x018821F6201300\x00\x00\x00\x00', ], (Ecu.fwdCamera, 0x750, 0x6d): [ b'\x028646F0602100\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F0602200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', + b'\x028646F3305200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', ], }, From 87f3a658a7f3a52877136f141ef528d0864bf04b Mon Sep 17 00:00:00 2001 From: Saber422 <81108166+Saber422@users.noreply.github.com> Date: Fri, 17 Mar 2023 06:03:22 +0800 Subject: [PATCH 1112/1179] =?UTF-8?q?VW=20MQB:=20Add=20FW=20for=202022=20?= =?UTF-8?q?=C5=A0koda=20Kodiaq=20(#27602)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @jyoung8607 I try to do this joy better I setup my C3 on this car to get information to merge this FPV2 The route name is 0bbe367c98fa1538|2023-03-16--11-41-19--2 Co-authored-by: Shane Smiskol --- selfdrive/car/volkswagen/values.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index 5d8c6e13c5..e63975b0c0 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -1075,6 +1075,7 @@ FW_VERSIONS = { b'\xf1\x8704L906026DE\xf1\x895418', b'\xf1\x8704L906026EJ\xf1\x893661', b'\xf1\x8704L906026HT\xf1\x893617', + b'\xf1\x8783A907115E \xf1\x890001', b'\xf1\x8705E906018DJ\xf1\x890915', b'\xf1\x875NA907115E \xf1\x890003', b'\xf1\x875NA907115E \xf1\x890005', @@ -1085,6 +1086,7 @@ FW_VERSIONS = { b'\xf1\x870DL300012M \xf1\x892107', b'\xf1\x870DL300012N \xf1\x892110', b'\xf1\x870DL300013G \xf1\x892119', + b'\xf1\x870GC300014N \xf1\x892801', b'\xf1\x870GC300046Q \xf1\x892802', ], (Ecu.srs, 0x715, None): [ @@ -1107,6 +1109,7 @@ FW_VERSIONS = { b'\xf1\x872Q0907572R \xf1\x890372', b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x872Q0907572AA\xf1\x890396', + b'\xf1\x872Q0907572AB\xf1\x890397', ], }, CAR.SKODA_OCTAVIA_MK3: { From 95216de5910c62bf81a7bf6053b5917de98dc825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 17:00:54 -0700 Subject: [PATCH 1113/1179] LAIKAD: TTFF, and ephemeris statuses in logs (#27591) * ttff in logs * More meta info * cleanup * passess tests * unused import * fix linting * ttff of 0 is invalid * ref commit * bump cereal --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 116 ++++++++++++++--------- selfdrive/locationd/test/test_laikad.py | 95 ++++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 111 insertions(+), 106 deletions(-) diff --git a/cereal b/cereal index 80a8eb8459..7492dc3f45 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 +Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 diff --git a/laika_repo b/laika_repo index 8463fe8fed..719c79a156 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 8463fe8fed272f58093406a990532084bc060359 +Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index fe5126522c..695e9adc03 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime -from laika.helpers import ConstellationId +from laika.helpers import ConstellationId, get_sv_id from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind @@ -33,6 +33,44 @@ CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 +class LogEphemerisType(IntEnum): + nav = 0 + nasaUltraRapid = 1 + glonassIacUltraRapid = 2 + qcom = 3 + +class EphemerisSource(IntEnum): + gnssChip = 0 + internet = 1 + cache = 2 + unknown = 3 + +def get_log_eph_type(ephem): + if ephem.eph_type == EphemerisType.NAV: + source_type = LogEphemerisType.nav + elif ephem.eph_type == EphemerisType.QCOM_POLY: + source_type = LogEphemerisType.qcom + else: + assert ephem.file_epoch is not None + file_src = ephem.file_source + if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' + source_type = LogEphemerisType.nasaUltraRapid + elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' + source_type = LogEphemerisType.glonassIacUltraRapid + else: + raise Exception(f"Didn't expect file source {file_src}") + return source_type + +def get_log_eph_source(ephem): + if ephem.file_name == 'qcom' or ephem.file_name == 'ublox': + source = EphemerisSource.gnssChip + elif ephem.file_name == EPHEMERIS_CACHE: + source = EphemerisSource.cache + else: + source = EphemerisSource.internet + return source + + class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), @@ -64,6 +102,8 @@ class Laikad: self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom + self.first_log_time = None + self.ttff = -1 def load_cache(self): if not self.save_ephemeris: @@ -76,8 +116,8 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] - gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: nav_dict[e.prn] = [] @@ -99,6 +139,21 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time + def create_ephem_statuses(self): + ephemeris_statuses = [] + prns_to_check = self.astro_dog.get_all_ephem_prns() + for prn in prns_to_check: + eph = self.astro_dog.get_eph(prn, self.last_report_time) + if eph is not None: + status = log.GnssMeasurements.EphemerisStatus.new_message() + status.constellationId = ConstellationId.from_rinex_char(prn[0]).value + status.svId = get_sv_id(prn) + status.type = get_log_eph_type(eph).value + status.source = get_log_eph_source(eph).value + ephemeris_statuses.append(status) + return ephemeris_statuses + + def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -170,10 +225,10 @@ class Laikad: else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct) + ephem = GPSEphemeris(data_struct, file_name='ublox') elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct) + ephem = GLONASSEphemeris(data_struct, file_name='ublox') else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return @@ -204,6 +259,12 @@ class Laikad: def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") + out_msg.gnssMeasurements = { + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), + } + if self.first_log_time is None: + self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) return out_msg @@ -223,6 +284,8 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: return out_msg + if self.ttff <= 0: + self.ttff = max(1e-3, t - self.first_log_time) position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) @@ -244,14 +307,12 @@ class Laikad: "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs + "correctedMeasurements": meas_msgs, + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), } return out_msg - #elif gnss_msg.which() == 'ionoData': - # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. - - def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid valid = self.kf_valid(t) @@ -335,31 +396,8 @@ def create_measurement_msg(meas: GNSSMeasurement): c.satPos = meas.sat_pos_final.tolist() c.satVel = meas.sat_vel.tolist() c.satVel = meas.sat_vel.tolist() - ephem = meas.sat_ephemeris - assert ephem is not None - week, time_of_week = -1, -1 - if ephem.eph_type == EphemerisType.NAV: - source_type = EphemerisSourceType.nav - elif ephem.eph_type == EphemerisType.QCOM_POLY: - source_type = EphemerisSourceType.qcom - else: - assert ephem.file_epoch is not None - week = ephem.file_epoch.week - time_of_week = ephem.file_epoch.tow - file_src = ephem.file_source - if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' - source_type = EphemerisSourceType.nasaUltraRapid - elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' - source_type = EphemerisSourceType.glonassIacUltraRapid - else: - raise Exception(f"Didn't expect file source {file_src}") - - c.ephemerisSource.type = source_type.value - c.ephemerisSource.gpsWeek = week - c.ephemerisSource.gpsTimeOfWeek = int(time_of_week) return c - def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMeasurement]): ekf_data = defaultdict(list) for m in measurements: @@ -375,18 +413,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) -class EphemerisSourceType(IntEnum): - nav = 0 - nasaUltraRapid = 1 - glonassIacUltraRapid = 2 - qcom = 3 - - -def process_msg(laikad, gnss_msg, mono_time, block=False): - - return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) - - def clear_tmp_cache(): if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 2e03551f6e..265db50c6d 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -12,11 +12,11 @@ from tqdm import tqdm from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs +from laika.ephemeris import EphemerisType from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg +from selfdrive.locationd.laikad import EPHEMERIS_CACHE, Laikad from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader from selfdrive.manager.process_config import managed_processes @@ -138,9 +138,9 @@ class TestLaikad(unittest.TestCase): laikad = Laikad() laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) + # Get results and save orbits to laikad: laikad.fetch_navs(gpstime, block=False) - ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) @@ -153,6 +153,7 @@ class TestLaikad(unittest.TestCase): self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) + def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() @@ -175,35 +176,6 @@ class TestLaikad(unittest.TestCase): check_has_navs() self.assertEqual(laikad.last_fetch_navs_t, real_current_time) - def test_ephemeris_source_in_msg(self): - dicto = {'svId': 1} - data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) - - gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - # Verify gps satellite returns same source - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nasa source by using older date - gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nav source type - ephem = GPSEphemeris(data_mock) - meas = get_measurement_mock(gpstime, ephem) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - def test_laika_online(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) @@ -263,26 +235,34 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) def test_get_navs_in_process(self): - for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) - has_navs = False - has_fix = False - for m in logs: - gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss - out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) - if laikad.orbit_fetch_future is not None: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.qcom_polys.values() - has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if out_msg is not None: - has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid + for auto_fetch_navs in [True, False]: + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=auto_fetch_navs) + has_navs = False + has_fix = False + seen_chip_eph = False + seen_internet_eph = False - self.assertTrue(has_navs or has_polys) - self.assertTrue(has_fix) - self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + for m in logs: + gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss + out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) + if laikad.orbit_fetch_future is not None: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.qcom_polys.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid + if len(out_msg.gnssMeasurements.ephemerisStatuses): + seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertTrue(seen_chip_eph or auto_fetch_navs) + self.assertTrue(seen_internet_eph or not auto_fetch_navs) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): use_qcom = True @@ -303,18 +283,19 @@ class TestLaikad(unittest.TestCase): Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) - laikad.last_report_time = GPSTime(2,0) - laikad.fetch_navs(self.first_gps_time, block=True) - - # Wait for cache to save + msg = verify_messages(logs, laikad, return_one_success=True) + laikad.cache_ephemeris() wait_for_cache() # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, + save_ephemeris=True, use_qcom=use_qcom, auto_fetch_navs=False) # Verify navs are loaded from cache self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(logs, laikad, return_one_success=True) + self.assertTrue(len(msg.gnssMeasurements.ephemerisStatuses)) + self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) @@ -349,7 +330,5 @@ class TestLaikad(unittest.TestCase): def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) - - if __name__ == "__main__": unittest.main() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 50288bfd03..fbe02bda3a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c8ba9450af16f9efc70eb76a5edc205aed53e779 +3b127e8aa63d3e5d260e130631ebc2dd67347556 From 4cff94366f751e53363c811a129f0d2dd93b4655 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Thu, 16 Mar 2023 19:01:45 -0700 Subject: [PATCH 1114/1179] Revert "LAIKAD: TTFF, and ephemeris statuses in logs (#27591)" This reverts commit 95216de5910c62bf81a7bf6053b5917de98dc825. --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 116 +++++++++-------------- selfdrive/locationd/test/test_laikad.py | 95 +++++++++++-------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 106 insertions(+), 111 deletions(-) diff --git a/cereal b/cereal index 7492dc3f45..80a8eb8459 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 +Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 diff --git a/laika_repo b/laika_repo index 719c79a156..8463fe8fed 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed +Subproject commit 8463fe8fed272f58093406a990532084bc060359 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 695e9adc03..fe5126522c 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime -from laika.helpers import ConstellationId, get_sv_id +from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind @@ -33,44 +33,6 @@ CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 -class LogEphemerisType(IntEnum): - nav = 0 - nasaUltraRapid = 1 - glonassIacUltraRapid = 2 - qcom = 3 - -class EphemerisSource(IntEnum): - gnssChip = 0 - internet = 1 - cache = 2 - unknown = 3 - -def get_log_eph_type(ephem): - if ephem.eph_type == EphemerisType.NAV: - source_type = LogEphemerisType.nav - elif ephem.eph_type == EphemerisType.QCOM_POLY: - source_type = LogEphemerisType.qcom - else: - assert ephem.file_epoch is not None - file_src = ephem.file_source - if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' - source_type = LogEphemerisType.nasaUltraRapid - elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' - source_type = LogEphemerisType.glonassIacUltraRapid - else: - raise Exception(f"Didn't expect file source {file_src}") - return source_type - -def get_log_eph_source(ephem): - if ephem.file_name == 'qcom' or ephem.file_name == 'ublox': - source = EphemerisSource.gnssChip - elif ephem.file_name == EPHEMERIS_CACHE: - source = EphemerisSource.cache - else: - source = EphemerisSource.internet - return source - - class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), @@ -102,8 +64,6 @@ class Laikad: self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom - self.first_log_time = None - self.ttff = -1 def load_cache(self): if not self.save_ephemeris: @@ -116,8 +76,8 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] - gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: nav_dict[e.prn] = [] @@ -139,21 +99,6 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time - def create_ephem_statuses(self): - ephemeris_statuses = [] - prns_to_check = self.astro_dog.get_all_ephem_prns() - for prn in prns_to_check: - eph = self.astro_dog.get_eph(prn, self.last_report_time) - if eph is not None: - status = log.GnssMeasurements.EphemerisStatus.new_message() - status.constellationId = ConstellationId.from_rinex_char(prn[0]).value - status.svId = get_sv_id(prn) - status.type = get_log_eph_type(eph).value - status.source = get_log_eph_source(eph).value - ephemeris_statuses.append(status) - return ephemeris_statuses - - def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -225,10 +170,10 @@ class Laikad: else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct, file_name='ublox') + ephem = GPSEphemeris(data_struct) elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct, file_name='ublox') + ephem = GLONASSEphemeris(data_struct) else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return @@ -259,12 +204,6 @@ class Laikad: def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") - out_msg.gnssMeasurements = { - "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), - } - if self.first_log_time is None: - self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) return out_msg @@ -284,8 +223,6 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: return out_msg - if self.ttff <= 0: - self.ttff = max(1e-3, t - self.first_log_time) position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) @@ -307,12 +244,14 @@ class Laikad: "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs, - "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), + "correctedMeasurements": meas_msgs } return out_msg + #elif gnss_msg.which() == 'ionoData': + # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. + + def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid valid = self.kf_valid(t) @@ -396,8 +335,31 @@ def create_measurement_msg(meas: GNSSMeasurement): c.satPos = meas.sat_pos_final.tolist() c.satVel = meas.sat_vel.tolist() c.satVel = meas.sat_vel.tolist() + ephem = meas.sat_ephemeris + assert ephem is not None + week, time_of_week = -1, -1 + if ephem.eph_type == EphemerisType.NAV: + source_type = EphemerisSourceType.nav + elif ephem.eph_type == EphemerisType.QCOM_POLY: + source_type = EphemerisSourceType.qcom + else: + assert ephem.file_epoch is not None + week = ephem.file_epoch.week + time_of_week = ephem.file_epoch.tow + file_src = ephem.file_source + if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' + source_type = EphemerisSourceType.nasaUltraRapid + elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' + source_type = EphemerisSourceType.glonassIacUltraRapid + else: + raise Exception(f"Didn't expect file source {file_src}") + + c.ephemerisSource.type = source_type.value + c.ephemerisSource.gpsWeek = week + c.ephemerisSource.gpsTimeOfWeek = int(time_of_week) return c + def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMeasurement]): ekf_data = defaultdict(list) for m in measurements: @@ -413,6 +375,18 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) +class EphemerisSourceType(IntEnum): + nav = 0 + nasaUltraRapid = 1 + glonassIacUltraRapid = 2 + qcom = 3 + + +def process_msg(laikad, gnss_msg, mono_time, block=False): + + return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) + + def clear_tmp_cache(): if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 265db50c6d..2e03551f6e 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -12,11 +12,11 @@ from tqdm import tqdm from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType +from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad import EPHEMERIS_CACHE, Laikad +from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader from selfdrive.manager.process_config import managed_processes @@ -138,9 +138,9 @@ class TestLaikad(unittest.TestCase): laikad = Laikad() laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) - # Get results and save orbits to laikad: laikad.fetch_navs(gpstime, block=False) + ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) @@ -153,7 +153,6 @@ class TestLaikad(unittest.TestCase): self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) - def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() @@ -176,6 +175,35 @@ class TestLaikad(unittest.TestCase): check_has_navs() self.assertEqual(laikad.last_fetch_navs_t, real_current_time) + def test_ephemeris_source_in_msg(self): + dicto = {'svId': 1} + data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) + + gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC + laikad = Laikad() + laikad.fetch_navs(gpstime, block=True) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + # Verify gps satellite returns same source + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + + # Test nasa source by using older date + gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) + laikad = Laikad() + laikad.fetch_navs(gpstime, block=True) + meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + + # Test nav source type + ephem = GPSEphemeris(data_mock) + meas = get_measurement_mock(gpstime, ephem) + msg = create_measurement_msg(meas) + self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) + def test_laika_online(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) @@ -235,34 +263,26 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) def test_get_navs_in_process(self): - for auto_fetch_navs in [True, False]: - for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=auto_fetch_navs) - has_navs = False - has_fix = False - seen_chip_eph = False - seen_internet_eph = False - - for m in logs: - gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss - out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) - if laikad.orbit_fetch_future is not None: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.qcom_polys.values() - has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) + has_navs = False + has_fix = False + for m in logs: + gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss + out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) + if laikad.orbit_fetch_future is not None: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.qcom_polys.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + if out_msg is not None: has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid - if len(out_msg.gnssMeasurements.ephemerisStatuses): - seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) - seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) - - self.assertTrue(has_navs or has_polys) - self.assertTrue(has_fix) - self.assertTrue(seen_chip_eph or auto_fetch_navs) - self.assertTrue(seen_internet_eph or not auto_fetch_navs) - self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): use_qcom = True @@ -283,19 +303,18 @@ class TestLaikad(unittest.TestCase): Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) - msg = verify_messages(logs, laikad, return_one_success=True) - laikad.cache_ephemeris() + laikad.last_report_time = GPSTime(2,0) + laikad.fetch_navs(self.first_gps_time, block=True) + + # Wait for cache to save wait_for_cache() # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, - save_ephemeris=True, use_qcom=use_qcom, auto_fetch_navs=False) + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) # Verify navs are loaded from cache self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(logs, laikad, return_one_success=True) - self.assertTrue(len(msg.gnssMeasurements.ephemerisStatuses)) - self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) @@ -330,5 +349,7 @@ class TestLaikad(unittest.TestCase): def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) + + if __name__ == "__main__": unittest.main() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index fbe02bda3a..50288bfd03 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -3b127e8aa63d3e5d260e130631ebc2dd67347556 +c8ba9450af16f9efc70eb76a5edc205aed53e779 From 4208b74ed8dbabe884646f9de69caefb666b6b44 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 16 Mar 2023 19:04:04 -0700 Subject: [PATCH 1115/1179] update to torch 2.0 and cuda 11.8 (#27608) * wip: update to torch 2.0 * update opencv --- pyproject.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c53dcb5381..7506ee552d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,7 +83,7 @@ mypy = "^0.961" myst-parser = "^0.18.0" natsort = "^8.1.0" numpy = "^1.23.0" -opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl", platform = "linux" } +opencv-python-headless = { url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu118/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl", platform = "linux" } pandas = "^1.4.3" parameterized = "^0.8.1" paramiko = "^2.11.0" @@ -117,7 +117,7 @@ optional = true aenum = "^3.1.11" aiohttp = "^3.8.1" albumentations = "^1.2.1" -apex = { url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" } +apex = { url = "https://github.com/commaai/apex/releases/download/pytorch2.0.0%2Bcu11.8/apex-0.1-cp38-cp38-linux_x86_64.whl" } azure-cli-core = "^2.38.0" azure-common = "^1.1.28" azure-core = "^1.24.2" @@ -127,7 +127,7 @@ azure-storage-nspkg = "~3.1" blosc = "==1.9.2" cloudpickle = "^2.1.0" configargparse = "^1.5.3" -cupy-cuda113 = "^10.6.0" +cupy-cuda11x = "^11.6.0" datadog = "^0.44.0" dotmap = "^1.3.30" einops = "^0.5.0" @@ -166,10 +166,10 @@ scikit-learn = "^1.1.1" segmentation-models-pytorch = "==0.2.1" simplejson = "^3.17.6" SQLAlchemy = "^1.4.39" -torch = { url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } +torch = { url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl" } torchsummary = "^1.5.1" -torchvision = { url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" } -triton = "^1.1.1" +torchvision = { url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.1%2Bcu118-cp38-cp38-linux_x86_64.whl" } +triton = "^2.0.0" Werkzeug = "^2.1.2" zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } omegaconf = "^2.3.0" From b0ba79451e63d376dec436545f98f648b3a933db Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Thu, 16 Mar 2023 21:09:21 -0700 Subject: [PATCH 1116/1179] upgrade to torch 2.0 cuda 11.8 (#27611) forgot to lock --- poetry.lock | 133 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/poetry.lock b/poetry.lock index 521bf3c0c3..4abd6777ba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -113,10 +113,12 @@ category = "dev" optional = false python-versions = "*" +[package.dependencies] +packaging = ">20.6" + [package.source] type = "url" -url = "https://github.com/commaai/apex/releases/download/pytorch1.10.0%2Bcu11.1/apex-0.1-cp38-cp38-linux_x86_64.whl" - +url = "https://github.com/commaai/apex/releases/download/pytorch2.0.0%2Bcu11.8/apex-0.1-cp38-cp38-linux_x86_64.whl" [[package]] name = "appdirs" version = "1.4.4" @@ -600,6 +602,17 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "cmake" +version = "3.26.0" +description = "CMake is an open-source, cross-platform family of tools designed to build, test and package software" +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +test = ["codecov (>=2.0.5)", "coverage (>=4.2)", "flake8 (>=3.0.4)", "path.py (>=11.5.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.4.0)", "pytest-runner (>=2.9)", "pytest-virtualenv (>=1.7.0)", "scikit-build (>=0.10.0)", "setuptools (>=28.0.0)", "virtualenv (>=15.0.3)", "wheel"] + [[package]] name = "colorama" version = "0.4.5" @@ -716,8 +729,8 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] [[package]] -name = "cupy-cuda113" -version = "10.6.0" +name = "cupy-cuda11x" +version = "11.6.0" description = "CuPy: NumPy & SciPy for GPU" category = "dev" optional = false @@ -725,12 +738,12 @@ python-versions = ">=3.7" [package.dependencies] fastrlock = ">=0.5" -numpy = ">=1.18,<1.25" +numpy = ">=1.20,<1.27" [package.extras] -all = ["Cython (>=0.29.22,<3)", "optuna (>=2.0)", "scipy (>=1.4,<1.11)"] +all = ["Cython (>=0.29.22,<3)", "optuna (>=2.0)", "scipy (>=1.6,<1.12)"] stylecheck = ["autopep8 (==1.5.5)", "flake8 (==3.8.4)", "mypy (==0.950)", "pbr (==5.5.1)", "pycodestyle (==2.6.0)", "types-setuptools (==57.4.14)"] -test = ["hypothesis (>=6.37.2)", "pytest (>=6.2)"] +test = ["hypothesis (>=6.37.2,<6.55.0)", "pytest (>=7.2)"] [[package]] name = "cycler" @@ -1898,6 +1911,14 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "lit" +version = "15.0.7" +description = "A Software Testing Tool" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "lockfile" version = "0.12.2" @@ -2586,8 +2607,7 @@ numpy = [ [package.source] type = "url" -url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu113/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" - +url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu118/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" [[package]] name = "osmium" version = "3.4.1" @@ -4220,19 +4240,26 @@ python-versions = ">=3.6,<4.0" [[package]] name = "torch" -version = "1.11.0+cu113" +version = "2.0.0+cu118" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" category = "dev" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" [package.dependencies] +filelock = "*" +jinja2 = "*" +networkx = "*" +sympy = "*" +triton = {version = "2.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} typing-extensions = "*" +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] + [package.source] type = "url" -url = "https://download.pytorch.org/whl/cu113/torch-1.11.0%2Bcu113-cp38-cp38-linux_x86_64.whl" - +url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl" [[package]] name = "torchsummary" version = "1.5.1" @@ -4243,26 +4270,24 @@ python-versions = "*" [[package]] name = "torchvision" -version = "0.12.0+cu113" +version = "0.15.1+cu118" description = "image and video datasets and models for torch deep learning" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" [package.dependencies] numpy = "*" pillow = ">=5.3.0,<8.3.0 || >=8.4.0" requests = "*" -torch = "1.11.0" -typing-extensions = "*" +torch = "2.0.0" [package.extras] scipy = ["scipy"] [package.source] type = "url" -url = "https://download.pytorch.org/whl/cu113/torchvision-0.12.0%2Bcu113-cp38-cp38-linux_x86_64.whl" - +url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.1%2Bcu118-cp38-cp38-linux_x86_64.whl" [[package]] name = "tornado" version = "6.2" @@ -4302,16 +4327,22 @@ test = ["pre-commit", "pytest"] [[package]] name = "triton" -version = "1.1.1" +version = "2.0.0" description = "A language and compiler for custom Deep Learning operations" category = "dev" optional = false python-versions = "*" [package.dependencies] +cmake = "*" filelock = "*" +lit = "*" torch = "*" +[package.extras] +tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] + [[package]] name = "types-atomicwrites" version = "1.4.5.1" @@ -4575,7 +4606,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "043d4bffddfddc2a5d6d20f51662a9992754831b387eb7e318c2420f3240049e" +content-hash = "a16ec604c5251dc860a44f7133289d0b7b16120757f8c903f3917329753c52d1" [metadata.files] adal = [ @@ -5040,6 +5071,25 @@ cloudpickle = [ {file = "cloudpickle-2.2.0-py3-none-any.whl", hash = "sha256:7428798d5926d8fcbfd092d18d01a2a03daf8237d8fcdc8095d256b8490796f0"}, {file = "cloudpickle-2.2.0.tar.gz", hash = "sha256:3f4219469c55453cfe4737e564b67c2a149109dabf7f242478948b895f61106f"}, ] +cmake = [ + {file = "cmake-3.26.0-py2.py3-none-macosx_10_10_universal2.macosx_10_10_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:4881727389325af84e39f1ec646b7249d8910b4ed637205bee6d589cb2b2ebd2"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2010_i686.manylinux_2_12_i686.whl", hash = "sha256:babd1e38c85d38a4bf4164c3126ec8cf4cd8d374072e2a4a181e52e953007f8c"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:1851be29d79bb39505954165e934d31994268d49f566ead6fff840a5092e444d"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:483aaaeb9535deaa2657c928af5d9f0da9329f89bc249f494923495745a03677"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2f78c6194f224d462333e08d3acd571c553b58d04935971b87efbe76f241353c"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:cf129c8b71f1344975f179f30287baa8804c4c61ff1b13003244b4157b676e13"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fabb82c69223eda27e673c5c6bb02985d60cf0baa631a2e4932eed87e8229928"}, + {file = "cmake-3.26.0-py2.py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502cbed2335557920b88687c6f3ff4ce433bd416204c928ad489e399e76149f5"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:b81c7775b125786c1696232078e9ceb0c9c66d26fb0a2259f40e33983170f924"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:f4cc1dde7613cc813d15fd840a33e18cd07a443aa67205d74b9b05f55f08a459"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:ac6ca9d9ff58900138bbbebc55857647fb99f1c40b84d8a232f23b0d27d7f48a"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:85e0bad5aeb3a82919ed7d78b76a0462eafe2f918076a1823a09c6f37910f3e0"}, + {file = "cmake-3.26.0-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:5523b9701be367572155e77294bf8aa3ac9aa0d73c50dcd6c57903d12bcb308e"}, + {file = "cmake-3.26.0-py2.py3-none-win32.whl", hash = "sha256:96f0e887260255eeb83bcf3465d51bc6c94078251c9312fa142dce6d3e80acac"}, + {file = "cmake-3.26.0-py2.py3-none-win_amd64.whl", hash = "sha256:a0719a6f79cdc4d7b16caf757b8ae13eae1c6ce5a08d594cc09774afe129515d"}, + {file = "cmake-3.26.0-py2.py3-none-win_arm64.whl", hash = "sha256:11159c9b64c6473d84361ab44ef2c85e1bd2db7a2b1b798ce8bf5988f32adf43"}, + {file = "cmake-3.26.0.tar.gz", hash = "sha256:c18185c9cc147d0fa1e9228962aa37901b37866bd5d617e9efa23dfe706f7321"}, +] colorama = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, @@ -5209,15 +5259,17 @@ cryptography = [ {file = "cryptography-37.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4c590ec31550a724ef893c50f9a97a0c14e9c851c85621c5650d699a7b88f7ab"}, {file = "cryptography-37.0.4.tar.gz", hash = "sha256:63f9c17c0e2474ccbebc9302ce2f07b55b3b3fcb211ded18a42d5764f5c10a82"}, ] -cupy-cuda113 = [ - {file = "cupy_cuda113-10.6.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:27e5efe2c3afa80ff48654cb27f9e0eddb36f8b26ef0d32d3ba0a233e1359b51"}, - {file = "cupy_cuda113-10.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:8b96076d1ddd33fdb2c908ed0f8109caf69d37d36f839a8a8cdae1312508336f"}, - {file = "cupy_cuda113-10.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:22363c2863727cae5154aa4bab9e8a648d7fe66c9e2195d81dd4e8693c2e61ce"}, - {file = "cupy_cuda113-10.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8cc69b9d5735372477a7af3822c8f8e996ffe6de05cfc917500af9dc0117ca3e"}, - {file = "cupy_cuda113-10.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:10dc6899577e445426d81f0960ba9059d9aaa750426997c61fad882d6345264c"}, - {file = "cupy_cuda113-10.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:c6893ac9040a11610e63973063dfd715dbda8bd07ef99951bab7a09c7f335e1e"}, - {file = "cupy_cuda113-10.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4bf4bc06d991c06b95f6fe558d117cafd93bd4eeaf80606f18dd31d20d2eff25"}, - {file = "cupy_cuda113-10.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:3745fc42dca86ba8a1109ddc7964aed8e1efc0ce8085cb2f140dcd6429f26354"}, +cupy-cuda11x = [ + {file = "cupy_cuda11x-11.6.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:1b9914f57868a1559e9bfabfbae8c724585914e8e1f277acb9cdb6aa0756eaa4"}, + {file = "cupy_cuda11x-11.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:ac8dd082ddb00996bc4d37cc5765907048f467aadb61bcbff25f3c2a88c50583"}, + {file = "cupy_cuda11x-11.6.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:bf7496340dfbc2eaa3e0ebfd03c4ab8b1fc36d7d14f68718c33eeb395aaa6eed"}, + {file = "cupy_cuda11x-11.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:e3bbd55c26d60069d7e5af2200fb47e7c42ca6437acac297637a2d3c00f6fe46"}, + {file = "cupy_cuda11x-11.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0d7ebcfd7234946719ad28890593d9fc78fad5753ef4b073e0d7bdb7da2f5640"}, + {file = "cupy_cuda11x-11.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3bc3f81fbc5a86c7155c6036809f2ada4023fc0870dce158d3d9f6d0b575727f"}, + {file = "cupy_cuda11x-11.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1d6810568e683cb153972b3019ddb5efc369036511122117d9eda09cf84d1042"}, + {file = "cupy_cuda11x-11.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:31c1ec72ffe9ad6fda9fb0a2aff1fcca38da66a8e521e333bae0d67ebc80ead0"}, + {file = "cupy_cuda11x-11.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6a4822daadfce0464cb619099eb82c7ba30ae7755d6869ba5eba1c675a9eed67"}, + {file = "cupy_cuda11x-11.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:3d0f44d747b38ce2b213d64270265f953b68cf29860ec5fa65848b9faaea3fc1"}, ] cycler = [ {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, @@ -5618,6 +5670,7 @@ gevent = [ {file = "gevent-22.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2ea4ce36c09355379bc038be2bd50118f97d2eb6381b7096de4d05aa4c3e241"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e73c9f71aa2a6795ecbec9b57282b002375e863e283558feb87b62840c8c1ac"}, {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc3758f0dc95007c1780d28a9fd2150416a79c50f308f62a674d78a845ea1b9"}, + {file = "gevent-22.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03c10ca0beeab0c6be516030471ea630447ddd1f649d3335e5b162097cd4130a"}, {file = "gevent-22.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fe2c0ff095171c49f78f1d4e6dc89fa58253783c7b6dccab9f1d76e2ee391f10"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d18fcc324f39a3b21795022eb47c7752d6e4f4ed89d8cca41f1cc604553265b3"}, {file = "gevent-22.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ea39c70ce166c4a1d4386c7fae96cb8d84ad799527b3378406051104d15443"}, @@ -6044,6 +6097,9 @@ libusb1 = [ {file = "libusb1-3.0.0-py3-none-win_amd64.whl", hash = "sha256:6f6bb010632ada35c661d17a65e135077beef0fbb2434d5ffdb3a4a911fd9490"}, {file = "libusb1-3.0.0.tar.gz", hash = "sha256:5792a9defee40f15d330a40d9b1800545c32e47ba7fc66b6f28f133c9fcc8538"}, ] +lit = [ + {file = "lit-15.0.7.tar.gz", hash = "sha256:ed08ac55afe714a193653df293ae8a6ee6c45d6fb11eeca72ce347d99b88ecc8"}, +] lockfile = [ {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, @@ -7008,6 +7064,7 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c9ed8aa31c146bef65d89a1b655f5f4eab5e1120f55fc297713c89c9e56ff0b"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:5099c9ca345b2f252f0c28e96904643153bae9258647585e5e6f649bb7a1844a"}, {file = "pycryptodome-3.15.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2ec709b0a58b539a4f9d33fb8508264c3678d7edb33a68b8906ba914f71e8c13"}, + {file = "pycryptodome-3.15.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:2ae53125de5b0d2c95194d957db9bb2681da8c24d0fb0fe3b056de2bcaf5d837"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win32.whl", hash = "sha256:fd2184aae6ee2a944aaa49113e6f5787cdc5e4db1eb8edb1aea914bd75f33a0c"}, {file = "pycryptodome-3.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:7e3a8f6ee405b3bd1c4da371b93c31f7027944b2bcce0697022801db93120d83"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:b9c5b1a1977491533dfd31e01550ee36ae0249d78aae7f632590db833a5012b8"}, @@ -7015,12 +7072,14 @@ pycryptodome = [ {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa55aae81f935a08d5a3c2042eb81741a43e044bd8a81ea7239448ad751f763"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:c3640deff4197fa064295aaac10ab49a0d55ef3d6a54ae1499c40d646655c89f"}, {file = "pycryptodome-3.15.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:045d75527241d17e6ef13636d845a12e54660aa82e823b3b3341bcf5af03fa79"}, + {file = "pycryptodome-3.15.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:eb6fce570869e70cc8ebe68eaa1c26bed56d40ad0f93431ee61d400525433c54"}, {file = "pycryptodome-3.15.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ee40e2168f1348ae476676a2e938ca80a2f57b14a249d8fe0d3cdf803e5a676"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4c3ccad74eeb7b001f3538643c4225eac398c77d617ebb3e57571a897943c667"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:1b22bcd9ec55e9c74927f6b1f69843cb256fb5a465088ce62837f793d9ffea88"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:57f565acd2f0cf6fb3e1ba553d0cb1f33405ec1f9c5ded9b9a0a5320f2c0bd3d"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:4b52cb18b0ad46087caeb37a15e08040f3b4c2d444d58371b6f5d786d95534c2"}, {file = "pycryptodome-3.15.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:092a26e78b73f2530b8bd6b3898e7453ab2f36e42fd85097d705d6aba2ec3e5e"}, + {file = "pycryptodome-3.15.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:50ca7e587b8e541eb6c192acf92449d95377d1f88908c0a32ac5ac2703ebe28b"}, {file = "pycryptodome-3.15.0-cp35-abi3-win32.whl", hash = "sha256:e244ab85c422260de91cda6379e8e986405b4f13dc97d2876497178707f87fc1"}, {file = "pycryptodome-3.15.0-cp35-abi3-win_amd64.whl", hash = "sha256:c77126899c4b9c9827ddf50565e93955cb3996813c18900c16b2ea0474e130e9"}, {file = "pycryptodome-3.15.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:9eaadc058106344a566dc51d3d3a758ab07f8edde013712bc8d22032a86b264f"}, @@ -8031,11 +8090,15 @@ traitlets = [ {file = "traitlets-5.5.0.tar.gz", hash = "sha256:b122f9ff2f2f6c1709dab289a05555be011c87828e911c0cf4074b85cb780a79"}, ] triton = [ - {file = "triton-1.1.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8441e6f44517aef8f6345f621c003926cbe970892802411a949ccda516cbd5ba"}, - {file = "triton-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840776bc1f4757fb2d6af974694c5e5313220ceec238ee6118b9728bc2aa9ade"}, - {file = "triton-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d42cdaa7d56de463d762c18cc876bfd0828a2b6a706263393fe7e10d1c83ca"}, - {file = "triton-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc19c0e902bbf7d29de4d444455608065a2c56e3524f4bc94e724511ca518f3"}, - {file = "triton-1.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02f798cd2dd922228082ce1a4e9d81badb9a6217a9aac6d783e95bf7055974d"}, + {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"}, + {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"}, + {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"}, + {file = "triton-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fedce6a381901b1547e0e7e1f2546e4f65dca6d91e2d8a7305a2d1f5551895be"}, + {file = "triton-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75834f27926eab6c7f00ce73aaf1ab5bfb9bec6eb57ab7c0bfc0a23fac803b4c"}, + {file = "triton-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0117722f8c2b579cd429e0bee80f7731ae05f63fe8e9414acd9a679885fcbf42"}, + {file = "triton-2.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcd9be5d0c2e45d2b7e6ddc6da20112b6862d69741576f9c3dbaf941d745ecae"}, + {file = "triton-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42a0d2c3fc2eab4ba71384f2e785fbfd47aa41ae05fa58bf12cb31dcbd0aeceb"}, + {file = "triton-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c47b72c72693198163ece9d90a721299e4fb3b8e24fd13141e384ad952724f"}, ] types-atomicwrites = [ {file = "types-atomicwrites-1.4.5.1.tar.gz", hash = "sha256:9e9f0923ebf93524b28bcece5a23ac8c3820f39b060df29f671936d2e4bc04bc"}, From 204f7d862390d86ab958275cd887b8cbc3e66f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Thu, 16 Mar 2023 22:09:05 -0700 Subject: [PATCH 1117/1179] Ttff logs (#27610) * ttff in logs * More meta info * cleanup * passess tests * unused import * fix linting * ttff of 0 is invalid * ref commit * bump cereal * Update ref_commit * sort ephem status list * sort ephem status list * update ref --- cereal | 2 +- laika_repo | 2 +- selfdrive/locationd/laikad.py | 117 ++++++++++++++--------- selfdrive/locationd/test/test_laikad.py | 95 +++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 5 files changed, 112 insertions(+), 106 deletions(-) diff --git a/cereal b/cereal index 80a8eb8459..7492dc3f45 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 80a8eb84593feb08dfc0bd47e5c04e586ea4b7a6 +Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 diff --git a/laika_repo b/laika_repo index 8463fe8fed..719c79a156 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 8463fe8fed272f58093406a990532084bc060359 +Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index fe5126522c..3698867ec9 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -18,7 +18,7 @@ from laika.constants import SECS_IN_HR, SECS_IN_MIN from laika.downloader import DownloadFailed from laika.ephemeris import EphemerisType, GPSEphemeris, GLONASSEphemeris, ephemeris_structs, parse_qcom_ephem from laika.gps_time import GPSTime -from laika.helpers import ConstellationId +from laika.helpers import ConstellationId, get_sv_id from laika.raw_gnss import GNSSMeasurement, correct_measurements, process_measurements, read_raw_ublox, read_raw_qcom from laika.opt import calc_pos_fix, get_posfix_sympy_fun, calc_vel_fix, get_velfix_sympy_func from selfdrive.locationd.models.constants import GENERATED_DIR, ObservationKind @@ -33,6 +33,44 @@ CACHE_VERSION = 0.2 POS_FIX_RESIDUAL_THRESHOLD = 100.0 +class LogEphemerisType(IntEnum): + nav = 0 + nasaUltraRapid = 1 + glonassIacUltraRapid = 2 + qcom = 3 + +class EphemerisSource(IntEnum): + gnssChip = 0 + internet = 1 + cache = 2 + unknown = 3 + +def get_log_eph_type(ephem): + if ephem.eph_type == EphemerisType.NAV: + source_type = LogEphemerisType.nav + elif ephem.eph_type == EphemerisType.QCOM_POLY: + source_type = LogEphemerisType.qcom + else: + assert ephem.file_epoch is not None + file_src = ephem.file_source + if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' + source_type = LogEphemerisType.nasaUltraRapid + elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' + source_type = LogEphemerisType.glonassIacUltraRapid + else: + raise Exception(f"Didn't expect file source {file_src}") + return source_type + +def get_log_eph_source(ephem): + if ephem.file_name == 'qcom' or ephem.file_name == 'ublox': + source = EphemerisSource.gnssChip + elif ephem.file_name == EPHEMERIS_CACHE: + source = EphemerisSource.cache + else: + source = EphemerisSource.internet + return source + + class Laikad: def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), @@ -64,6 +102,8 @@ class Laikad: self.last_fix_t = None self.gps_week = None self.use_qcom = use_qcom + self.first_log_time = None + self.ttff = -1 def load_cache(self): if not self.save_ephemeris: @@ -76,8 +116,8 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct) for data_struct in ephem_cache.glonassEphemerides] - gps_navs = [GPSEphemeris(data_struct) for data_struct in ephem_cache.gpsEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] + gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: nav_dict[e.prn] = [] @@ -99,6 +139,22 @@ class Laikad: cloudlog.debug("Cache saved") self.last_cached_t = self.last_report_time + def create_ephem_statuses(self): + ephemeris_statuses = [] + prns_to_check = list(self.astro_dog.get_all_ephem_prns()) + prns_to_check.sort() + for prn in prns_to_check: + eph = self.astro_dog.get_eph(prn, self.last_report_time) + if eph is not None: + status = log.GnssMeasurements.EphemerisStatus.new_message() + status.constellationId = ConstellationId.from_rinex_char(prn[0]).value + status.svId = get_sv_id(prn) + status.type = get_log_eph_type(eph).value + status.source = get_log_eph_source(eph).value + ephemeris_statuses.append(status) + return ephemeris_statuses + + def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -170,10 +226,10 @@ class Laikad: else: if gnss_msg.which() == 'ephemeris': data_struct = ephemeris_structs.Ephemeris.new_message(**gnss_msg.ephemeris.to_dict()) - ephem = GPSEphemeris(data_struct) + ephem = GPSEphemeris(data_struct, file_name='ublox') elif gnss_msg.which() == 'glonassEphemeris': data_struct = ephemeris_structs.GlonassEphemeris.new_message(**gnss_msg.glonassEphemeris.to_dict()) - ephem = GLONASSEphemeris(data_struct) + ephem = GLONASSEphemeris(data_struct, file_name='ublox') else: cloudlog.error(f"Unsupported ephemeris type: {gnss_msg.which()}") return @@ -204,6 +260,12 @@ class Laikad: def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") + out_msg.gnssMeasurements = { + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), + } + if self.first_log_time is None: + self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) return out_msg @@ -223,6 +285,8 @@ class Laikad: output = self.process_report(new_meas, t) if output is None: return out_msg + if self.ttff <= 0: + self.ttff = max(1e-3, t - self.first_log_time) position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output self.update_localizer(position_estimate, t, corrected_measurements) @@ -244,14 +308,12 @@ class Laikad: "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs + "correctedMeasurements": meas_msgs, + "timeToFirstFix": self.ttff, + "ephemerisStatuses" : self.create_ephem_statuses(), } return out_msg - #elif gnss_msg.which() == 'ionoData': - # TODO: add this, Needed to better correct messages offline. First fix ublox_msg.cc to sent them. - - def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): # Check time and outputs are valid valid = self.kf_valid(t) @@ -335,31 +397,8 @@ def create_measurement_msg(meas: GNSSMeasurement): c.satPos = meas.sat_pos_final.tolist() c.satVel = meas.sat_vel.tolist() c.satVel = meas.sat_vel.tolist() - ephem = meas.sat_ephemeris - assert ephem is not None - week, time_of_week = -1, -1 - if ephem.eph_type == EphemerisType.NAV: - source_type = EphemerisSourceType.nav - elif ephem.eph_type == EphemerisType.QCOM_POLY: - source_type = EphemerisSourceType.qcom - else: - assert ephem.file_epoch is not None - week = ephem.file_epoch.week - time_of_week = ephem.file_epoch.tow - file_src = ephem.file_source - if file_src == 'igu': # example nasa: '2214/igu22144_00.sp3.Z' - source_type = EphemerisSourceType.nasaUltraRapid - elif file_src == 'Sta': # example nasa: '22166/ultra/Stark_1D_22061518.sp3' - source_type = EphemerisSourceType.glonassIacUltraRapid - else: - raise Exception(f"Didn't expect file source {file_src}") - - c.ephemerisSource.type = source_type.value - c.ephemerisSource.gpsWeek = week - c.ephemerisSource.gpsTimeOfWeek = int(time_of_week) return c - def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMeasurement]): ekf_data = defaultdict(list) for m in measurements: @@ -375,18 +414,6 @@ def kf_add_observations(gnss_kf: GNSSKalman, t: float, measurements: List[GNSSMe gnss_kf.predict_and_observe(t, kind, data) -class EphemerisSourceType(IntEnum): - nav = 0 - nasaUltraRapid = 1 - glonassIacUltraRapid = 2 - qcom = 3 - - -def process_msg(laikad, gnss_msg, mono_time, block=False): - - return laikad.process_gnss_msg(gnss_msg, mono_time, block=block) - - def clear_tmp_cache(): if os.path.exists(DOWNLOADS_CACHE_FOLDER): shutil.rmtree(DOWNLOADS_CACHE_FOLDER) diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 2e03551f6e..265db50c6d 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -12,11 +12,11 @@ from tqdm import tqdm from laika.constants import SECS_IN_DAY from laika.downloader import DownloadFailed -from laika.ephemeris import EphemerisType, GPSEphemeris, ephemeris_structs +from laika.ephemeris import EphemerisType from laika.gps_time import GPSTime from laika.helpers import ConstellationId from laika.raw_gnss import GNSSMeasurement, read_raw_ublox, read_raw_qcom -from selfdrive.locationd.laikad import EPHEMERIS_CACHE, EphemerisSourceType, Laikad, create_measurement_msg +from selfdrive.locationd.laikad import EPHEMERIS_CACHE, Laikad from selfdrive.test.openpilotci import get_url from tools.lib.logreader import LogReader from selfdrive.manager.process_config import managed_processes @@ -138,9 +138,9 @@ class TestLaikad(unittest.TestCase): laikad = Laikad() laikad.fetch_navs(gpstime, block=False) laikad.orbit_fetch_future.result(30) + # Get results and save orbits to laikad: laikad.fetch_navs(gpstime, block=False) - ephem = laikad.astro_dog.navs['G01'][0] self.assertIsNotNone(ephem) @@ -153,6 +153,7 @@ class TestLaikad(unittest.TestCase): self.assertIsNotNone(ephem) self.assertNotEqual(ephem, ephem2) + def test_fetch_navs_with_wrong_clocks(self): laikad = Laikad() @@ -175,35 +176,6 @@ class TestLaikad(unittest.TestCase): check_has_navs() self.assertEqual(laikad.last_fetch_navs_t, real_current_time) - def test_ephemeris_source_in_msg(self): - dicto = {'svId': 1} - data_mock = ephemeris_structs.Ephemeris.new_message(**dicto) - - gpstime = GPS_TIME_PREDICTION_ORBITS_RUSSIAN_SRC - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - # Verify gps satellite returns same source - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['R01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nasa source by using older date - gpstime = GPSTime.from_datetime(datetime(2021, month=3, day=1)) - laikad = Laikad() - laikad.fetch_navs(gpstime, block=True) - meas = get_measurement_mock(gpstime, laikad.astro_dog.navs['G01'][0]) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - - # Test nav source type - ephem = GPSEphemeris(data_mock) - meas = get_measurement_mock(gpstime, ephem) - msg = create_measurement_msg(meas) - self.assertEqual(msg.ephemerisSource.type.raw, EphemerisSourceType.nav) - def test_laika_online(self): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) @@ -263,26 +235,34 @@ class TestLaikad(unittest.TestCase): self.assertGreater(len(laikad.astro_dog.navs[prn]), 0) def test_get_navs_in_process(self): - for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): - laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=False) - has_navs = False - has_fix = False - for m in logs: - gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss - out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) - if laikad.orbit_fetch_future is not None: - laikad.orbit_fetch_future.result() - vals = laikad.astro_dog.navs.values() - has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 - vals = laikad.astro_dog.qcom_polys.values() - has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 - if out_msg is not None: - has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid + for auto_fetch_navs in [True, False]: + for use_qcom, logs in zip([True, False], [self.logs_qcom, self.logs]): + laikad = Laikad(auto_update=False, use_qcom=use_qcom, auto_fetch_navs=auto_fetch_navs) + has_navs = False + has_fix = False + seen_chip_eph = False + seen_internet_eph = False - self.assertTrue(has_navs or has_polys) - self.assertTrue(has_fix) - self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) - self.assertEqual(None, laikad.orbit_fetch_future) + for m in logs: + gnss_msg = m.qcomGnss if use_qcom else m.ubloxGnss + out_msg = laikad.process_gnss_msg(gnss_msg, m.logMonoTime, block=False) + if laikad.orbit_fetch_future is not None: + laikad.orbit_fetch_future.result() + vals = laikad.astro_dog.navs.values() + has_navs = len(vals) > 0 and max([len(v) for v in vals]) > 0 + vals = laikad.astro_dog.qcom_polys.values() + has_polys = len(vals) > 0 and max([len(v) for v in vals]) > 0 + has_fix = has_fix or out_msg.gnssMeasurements.positionECEF.valid + if len(out_msg.gnssMeasurements.ephemerisStatuses): + seen_chip_eph = seen_chip_eph or any([x.source == 'gnssChip' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + seen_internet_eph = seen_internet_eph or any([x.source == 'internet' for x in out_msg.gnssMeasurements.ephemerisStatuses]) + + self.assertTrue(has_navs or has_polys) + self.assertTrue(has_fix) + self.assertTrue(seen_chip_eph or auto_fetch_navs) + self.assertTrue(seen_internet_eph or not auto_fetch_navs) + self.assertEqual(len(laikad.astro_dog.navs_fetched_times._ranges), 0) + self.assertEqual(None, laikad.orbit_fetch_future) def test_cache(self): use_qcom = True @@ -303,18 +283,19 @@ class TestLaikad(unittest.TestCase): Params().remove(EPHEMERIS_CACHE) #laikad.astro_dog.get_navs(self.first_gps_time) - laikad.last_report_time = GPSTime(2,0) - laikad.fetch_navs(self.first_gps_time, block=True) - - # Wait for cache to save + msg = verify_messages(logs, laikad, return_one_success=True) + laikad.cache_ephemeris() wait_for_cache() # Check both nav and orbits separate - laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, save_ephemeris=True, use_qcom=use_qcom) + laikad = Laikad(auto_update=False, valid_ephem_types=EphemerisType.NAV, + save_ephemeris=True, use_qcom=use_qcom, auto_fetch_navs=False) # Verify navs are loaded from cache self.dict_has_values(laikad.astro_dog.navs) # Verify cache is working for only nav by running a segment msg = verify_messages(logs, laikad, return_one_success=True) + self.assertTrue(len(msg.gnssMeasurements.ephemerisStatuses)) + self.assertTrue(any([x.source=='cache' for x in msg.gnssMeasurements.ephemerisStatuses])) self.assertIsNotNone(msg) @@ -349,7 +330,5 @@ class TestLaikad(unittest.TestCase): def dict_has_values(self, dct): self.assertGreater(len(dct), 0) self.assertGreater(min([len(v) for v in dct.values()]), 0) - - if __name__ == "__main__": unittest.main() diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 50288bfd03..cbe2a016ce 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -c8ba9450af16f9efc70eb76a5edc205aed53e779 +5775220ec2e62dcdedb92d96270f1380bbd88c39 From b5198f99ea66c68aab87f4d9e525d306ebe97b72 Mon Sep 17 00:00:00 2001 From: Kay Oh Date: Fri, 17 Mar 2023 15:08:51 +0900 Subject: [PATCH 1118/1179] Add missing FW for 2022 (2023MY) Hyundai IONIQ 5 (#27590) Update values.py Korean Ver. --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index cf0143543a..f7cedf550e 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1562,6 +1562,7 @@ FW_VERSIONS = { b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206', b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614', + b'\xf1\x00NE1 MFC AT KOR LHD 1.00 1.05 99211-GI010 220614', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007', b'\xf1\x00NE1 MFC AT EUR RHD 1.00 1.02 99211-GI010 211206', From 2f95148a67bce42dc8ba9954d7bc87197e5adbd2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 16 Mar 2023 23:16:11 -0700 Subject: [PATCH 1119/1179] bump panda (#27612) --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index c0aea3273a..e4cc97d882 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c0aea3273a82a91f10554b1b3317727da99f4564 +Subproject commit e4cc97d8826dc95a7833b859c36948302445a499 From 57c4d78869ad197189427ab68c45ac8cc7bbd9d0 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 17 Mar 2023 00:03:21 -0700 Subject: [PATCH 1120/1179] Toyota: add 2023 RAV4/RAV4 Hybrid as dashcam (#27609) * test out lta message * correctly send * percentage is percentage driver isn't overriding * closer to stock system * should be able to send LTA at 100hz, counter is the same as LKA * small amount of torque towards desired * Offset commanded torque correctly * Too little torque * use car's SETME's * Revert "use car's SETME's" This reverts commit c88856969995f97cc5ec4e2b24a5cc4e3ef4721a. * try cutting steer every second * Didn't seem to matter This reverts commit 6923498b2a9eed8beb3998f441899f1df4948f6f. * steer to 0 * let packer set counter * add for camry * log steer faults * comments * bump opendbc * add opParams * add lta safety * set safety param * fix torque control bug * bump panda * fix missing signal * [experiment] apply some rate limiting and anti-windup * no faults, clip to 90 deg, decent torque blending * clean up blending * toyota angle rate limits * use std angle limits * assert we only add angle control to TSS2 cars * clean up carcontroller a bit * space space * bump opendbc * clean up toyotacan from opendbc change * bump panda * will tests run? * steer at zero * refactor angle to use LatControlPID with zero gains * stop some faults and tuning * possibly fix integral wind up at max torque * Add 2023 rav4 * limit torque inside EPS when overriding (no huge windup in edge cases when overriding) * fix wind up issue after turns (or prolonged saturation) * this doesn't work that well * try these limits * try this * log the angle! * global variable * Apply suggestions from code review * clip angle to 3 m/s/s * some tolerance for roll * raise limits a bit * bumppanda * fix faults * still not good * offsetting causing hugging? * Revert "offsetting causing hugging?" This reverts commit a42ec0b772ed74a1fd54b7fef2e7c275a3e8333b. * reduce kp * class var not needed * limit up angle delta * fix saturation check * feedforward includes offset * some threshold for roll * bump panda * surely we don't need this * test stuff * Toyota: Add FW for 2023 RAV4 Hybrid (#27494) * Toyota: Add FW for 2023 RAV4 Hybrid * Set RAVH_TSS2_2022 to use angle SteerControlType * bump panda * remove extras * Revert "remove extras" This reverts commit 87378e734915c107f57f99a5feef4dcb2b2a9a37. * no max angle limit for now * add as separate platforms * remove debug scripts * revert to master * remove these FW versions from 2022 * dashcam these cars :( * fix test * interface * add to untested routes * never send torque with LTA cars * fix values * clean up controlsd * reset lat control files * use the car param * add to params * bump panda to master * Update selfdrive/car/toyota/carcontroller.py * don't set torque params if angle control (fixes controlsd bug) * reset controlsd * keyword * in another pr * simplify test * rm line * Update selfdrive/car/toyota/tests/test_toyota.py --------- Co-authored-by: crispbee <84819466+crispbee@users.noreply.github.com> --- selfdrive/car/tests/routes.py | 2 + selfdrive/car/torque_data/override.yaml | 4 ++ selfdrive/car/toyota/carcontroller.py | 5 +++ selfdrive/car/toyota/interface.py | 18 +++++--- selfdrive/car/toyota/tests/__init__.py | 0 selfdrive/car/toyota/tests/test_toyota.py | 13 ++++++ selfdrive/car/toyota/values.py | 51 +++++++++++++++++++++-- 7 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 selfdrive/car/toyota/tests/__init__.py create mode 100755 selfdrive/car/toyota/tests/test_toyota.py diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 4ca7c0a16c..2c4ec84e86 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -27,6 +27,8 @@ non_tested_cars = [ HYUNDAI.KIA_OPTIMA_H, HONDA.ODYSSEY_CHN, VOLKSWAGEN.CRAFTER_MK2, # need a route from an ACC-equipped Crafter + TOYOTA.RAV4_TSS2_2023, + TOYOTA.RAV4H_TSS2_2023, ] CarTestRoute = namedtuple('CarTestRoute', ['route', 'car_model', 'segment'], defaults=(None,)) diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index cc1681bce1..75051316fa 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -7,6 +7,10 @@ NISSAN LEAF 2018 Instrument Cluster: [.nan, 1.5, .nan] NISSAN LEAF 2018: [.nan, 1.5, .nan] NISSAN ROGUE 2019: [.nan, 1.5, .nan] +# Toyota LTA also has torque +TOYOTA RAV4 2023: [.nan, 3.0, .nan] +TOYOTA RAV4 HYBRID 2023: [.nan, 3.0, .nan] + # Tesla has high torque TESLA AP1 MODEL S: [.nan, 2.5, .nan] TESLA AP2 MODEL S: [.nan, 2.5, .nan] diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py index 8004ea9dca..66a7b57f01 100644 --- a/selfdrive/car/toyota/carcontroller.py +++ b/selfdrive/car/toyota/carcontroller.py @@ -76,6 +76,11 @@ class CarController: apply_steer_req = 0 self.steer_rate_counter = 0 + # Never actuate with LKA on cars that only support LTA + if self.CP.steerControlType == car.CarParams.SteerControlType.angle: + apply_steer = 0 + apply_steer_req = 0 + # TODO: probably can delete this. CS.pcm_acc_status uses a different signal # than CS.cruiseState.enabled. confirm they're not meaningfully different if not CC.enabled and CS.pcm_acc_status: diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 8b3fd048d9..e6476863c3 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,8 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, CarControllerParams, NO_STOP_TIMER_CAR +from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ + MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -23,13 +24,18 @@ class CarInterface(CarInterfaceBase): if candidate in (CAR.RAV4, CAR.PRIUS_V, CAR.COROLLA, CAR.LEXUS_ESH, CAR.LEXUS_CTH): ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_ALT_BRAKE + if candidate in ANGLE_CONTROL_CAR: + ret.dashcamOnly = True + ret.steerControlType = car.CarParams.SteerControlType.angle + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_LTA + else: + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + ret.steerActuatorDelay = 0.12 # Default delay, Prius has larger delay ret.steerLimitTimer = 0.4 ret.stoppingControl = False # Toyota starts braking more when it thinks you want to stop stop_and_go = False - steering_angle_deadzone_deg = 0.0 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg) if candidate == CAR.PRIUS: stop_and_go = True @@ -40,9 +46,8 @@ class CarInterface(CarInterfaceBase): # Only give steer angle deadzone to for bad angle sensor prius for fw in car_fw: if fw.ecu == "eps" and not fw.fwVersion == b'8965B47060\x00\x00\x00\x00\x00\x00': - steering_angle_deadzone_deg = 0.2 ret.steerActuatorDelay = 0.25 - CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg) + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning, steering_angle_deadzone_deg=0.2) elif candidate == CAR.PRIUS_V: stop_and_go = True @@ -102,7 +107,8 @@ class CarInterface(CarInterfaceBase): tire_stiffness_factor = 0.7983 ret.mass = 3505. * CV.LB_TO_KG + STD_CARGO_KG # mean between normal and hybrid - elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022): + elif candidate in (CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, + CAR.RAV4_TSS2_2023, CAR.RAV4H_TSS2_2023): stop_and_go = True ret.wheelbase = 2.68986 ret.steerRatio = 14.3 diff --git a/selfdrive/car/toyota/tests/__init__.py b/selfdrive/car/toyota/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/car/toyota/tests/test_toyota.py b/selfdrive/car/toyota/tests/test_toyota.py new file mode 100755 index 0000000000..5648f75fe7 --- /dev/null +++ b/selfdrive/car/toyota/tests/test_toyota.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +import unittest + +from selfdrive.car.toyota.values import TSS2_CAR, ANGLE_CONTROL_CAR + + +class TestToyotaInterfaces(unittest.TestCase): + def test_angle_car_set(self): + self.assertTrue(len(ANGLE_CONTROL_CAR - TSS2_CAR) == 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 43f0593325..965a9e6506 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -67,8 +67,10 @@ class CAR: RAV4H = "TOYOTA RAV4 HYBRID 2017" RAV4_TSS2 = "TOYOTA RAV4 2019" RAV4_TSS2_2022 = "TOYOTA RAV4 2022" + RAV4_TSS2_2023 = "TOYOTA RAV4 2023" RAV4H_TSS2 = "TOYOTA RAV4 HYBRID 2019" RAV4H_TSS2_2022 = "TOYOTA RAV4 HYBRID 2022" + RAV4H_TSS2_2023 = "TOYOTA RAV4 HYBRID 2023" MIRAI = "TOYOTA MIRAI 2021" # TSS 2.5 SIENNA = "TOYOTA SIENNA 2018" @@ -157,8 +159,10 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { ], CAR.RAV4_TSS2: ToyotaCarInfo("Toyota RAV4 2019-21", video_link="https://www.youtube.com/watch?v=wJxjDd42gGA"), CAR.RAV4_TSS2_2022: ToyotaCarInfo("Toyota RAV4 2022"), + CAR.RAV4_TSS2_2023: ToyotaCarInfo("Toyota RAV4 2023"), CAR.RAV4H_TSS2: ToyotaCarInfo("Toyota RAV4 Hybrid 2019-21"), CAR.RAV4H_TSS2_2022: ToyotaCarInfo("Toyota RAV4 Hybrid 2022", video_link="https://youtu.be/U0nH9cnrFB0"), + CAR.RAV4H_TSS2_2023: ToyotaCarInfo("Toyota RAV4 Hybrid 2023"), CAR.MIRAI: ToyotaCarInfo("Toyota Mirai 2021"), CAR.SIENNA: ToyotaCarInfo("Toyota Sienna 2018-20", video_link="https://www.youtube.com/watch?v=q1UPOo4Sh68", min_enable_speed=MIN_ACC_SPEED), @@ -1459,6 +1463,23 @@ FW_VERSIONS = { b'\x028646F0R02100\x00\x00\x00\x008646G0R01100\x00\x00\x00\x00', ], }, + CAR.RAV4_TSS2_2023: { + (Ecu.abs, 0x7b0, None): [ + b'\x01F15260R450\x00\x00\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'\x028965B0R11000\x00\x00\x00\x008965B0R12000\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x01896634AJ2000\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F0R03100\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0R05100\x00\x00\x00\x008646G0R02100\x00\x00\x00\x00', + ], + }, CAR.RAV4H_TSS2: { (Ecu.engine, 0x700, None): [ b'\x01896634A15000\x00\x00\x00\x00', @@ -1546,6 +1567,23 @@ FW_VERSIONS = { b'\x028646F0R02100\x00\x00\x00\x008646G0R01100\x00\x00\x00\x00', ], }, + CAR.RAV4H_TSS2_2023: { + (Ecu.abs, 0x7b0, None): [ + b'\x01F15264283200\x00\x00\x00\x00', + ], + (Ecu.eps, 0x7a1, None): [ + b'\x028965B0R11000\x00\x00\x00\x008965B0R12000\x00\x00\x00\x00', + ], + (Ecu.engine, 0x700, None): [ + b'\x01896634AE1001\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x750, 0xf): [ + b'\x018821F0R03100\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x750, 0x6d): [ + b'\x028646F0R05100\x00\x00\x00\x008646G0R02100\x00\x00\x00\x00', + ], + }, CAR.SIENNA: { (Ecu.engine, 0x700, None): [ b'\x01896630832100\x00\x00\x00\x00', @@ -2104,6 +2142,7 @@ DBC = { CAR.AVALONH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.RAV4_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.RAV4_TSS2_2022: dbc_dict('toyota_nodsu_pt_generated', None), + CAR.RAV4_TSS2_2023: dbc_dict('toyota_nodsu_pt_generated', None), CAR.COROLLA_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.COROLLAH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.LEXUS_ES_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), @@ -2114,6 +2153,7 @@ DBC = { CAR.LEXUS_CTH: dbc_dict('toyota_new_mc_pt_generated', 'toyota_adas'), CAR.RAV4H_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), CAR.RAV4H_TSS2_2022: dbc_dict('toyota_nodsu_pt_generated', None), + CAR.RAV4H_TSS2_2023: dbc_dict('toyota_nodsu_pt_generated', None), CAR.LEXUS_NXH: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), CAR.LEXUS_NX: dbc_dict('toyota_tnga_k_pt_generated', 'toyota_adas'), CAR.LEXUS_NX_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'), @@ -2128,8 +2168,8 @@ DBC = { EPS_SCALE = defaultdict(lambda: 73, {CAR.PRIUS: 66, CAR.COROLLA: 88, CAR.LEXUS_IS: 77, CAR.LEXUS_RC: 77, CAR.LEXUS_CTH: 100, CAR.PRIUS_V: 100}) # Toyota/Lexus Safety Sense 2.0 and 2.5 -TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, - CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, +TSS2_CAR = {CAR.RAV4_TSS2, CAR.RAV4_TSS2_2022, CAR.RAV4_TSS2_2023, CAR.COROLLA_TSS2, CAR.COROLLAH_TSS2, CAR.LEXUS_ES_TSS2, CAR.LEXUS_ESH_TSS2, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, + CAR.RAV4H_TSS2_2023, CAR.LEXUS_RX_TSS2, CAR.LEXUS_RXH_TSS2, CAR.HIGHLANDER_TSS2, CAR.HIGHLANDERH_TSS2, CAR.PRIUS_TSS2, CAR.CAMRY_TSS2, CAR.CAMRYH_TSS2, CAR.MIRAI, CAR.LEXUS_NX_TSS2, CAR.LEXUS_NXH_TSS2, CAR.ALPHARD_TSS2, CAR.AVALON_TSS2, CAR.AVALONH_TSS2, CAR.ALPHARDH_TSS2, CAR.CHR_TSS2, CAR.CHRH_TSS2} NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} @@ -2138,10 +2178,13 @@ NO_DSU_CAR = TSS2_CAR | {CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH} UNSUPPORTED_DSU_CAR = {CAR.LEXUS_IS, CAR.LEXUS_RC} # these cars have a radar which sends ACC messages instead of the camera -RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.CHR_TSS2, CAR.CHRH_TSS2} +RADAR_ACC_CAR = {CAR.RAV4H_TSS2_2022, CAR.RAV4_TSS2_2022, CAR.RAV4H_TSS2_2023, CAR.RAV4_TSS2_2023, CAR.CHR_TSS2, CAR.CHRH_TSS2} + +# these cars use the Lane Tracing Assist (LTA) message for lateral control +ANGLE_CONTROL_CAR = {CAR.RAV4H_TSS2_2023, CAR.RAV4_TSS2_2023} EV_HYBRID_CAR = {CAR.AVALONH_2019, CAR.AVALONH_TSS2, CAR.CAMRYH, CAR.CAMRYH_TSS2, CAR.CHRH, CAR.CHRH_TSS2, CAR.COROLLAH_TSS2, CAR.HIGHLANDERH, CAR.HIGHLANDERH_TSS2, CAR.PRIUS, - CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, + CAR.PRIUS_V, CAR.RAV4H, CAR.RAV4H_TSS2, CAR.RAV4H_TSS2_2022, CAR.RAV4H_TSS2_2023, CAR.LEXUS_CTH, CAR.MIRAI, CAR.LEXUS_ESH, CAR.LEXUS_ESH_TSS2, CAR.LEXUS_NXH, CAR.LEXUS_RXH, CAR.LEXUS_RXH_TSS2, CAR.LEXUS_NXH_TSS2, CAR.PRIUS_TSS2, CAR.ALPHARDH_TSS2} # no resume button press required From 74db5a4b421c822065677b12c4493c4e20aa2a9b Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Mar 2023 01:16:14 +0800 Subject: [PATCH 1121/1179] cabana: group CAN events by message id to reduce the time complex from O(N) to O(1) (#27601) * refactor streams * helper function xLessThan * fix fill gaps --- tools/cabana/binaryview.cc | 2 +- tools/cabana/chartswidget.cc | 84 +++++++------------- tools/cabana/dbc.cc | 2 +- tools/cabana/dbc.h | 6 +- tools/cabana/dbcmanager.cc | 1 - tools/cabana/historylog.cc | 43 ++++------- tools/cabana/mainwin.cc | 10 +-- tools/cabana/messageswidget.cc | 6 +- tools/cabana/streams/abstractstream.cc | 103 +++++++++++++------------ tools/cabana/streams/abstractstream.h | 20 ++++- tools/cabana/streams/livestream.cc | 9 +-- tools/cabana/streams/livestream.h | 8 +- tools/cabana/streams/replaystream.cc | 13 +++- tools/cabana/streams/replaystream.h | 3 +- tools/cabana/tools/findsimilarbits.cc | 39 ++++------ tools/replay/replay.h | 1 + 16 files changed, 162 insertions(+), 188 deletions(-) diff --git a/tools/cabana/binaryview.cc b/tools/cabana/binaryview.cc index b81f7d5e79..0a4f6fc999 100644 --- a/tools/cabana/binaryview.cc +++ b/tools/cabana/binaryview.cc @@ -422,7 +422,7 @@ void BinaryItemDelegate::drawBorder(QPainter* painter, const QStyleOptionViewIte painter->setClipRegion(QRegion(rc).subtracted(subtract)); if (!subtract.isEmpty()) { // fill gaps inside corners. - painter->setPen(QPen(border_color, 2)); + painter->setPen(QPen(border_color, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); for (auto &r : subtract) { painter->drawRect(r); } diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 61afb871ae..04734e6749 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -16,6 +16,8 @@ #include const int MAX_COLUMN_COUNT = 4; +static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; } + // ChartsWidget ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { @@ -135,13 +137,11 @@ void ChartsWidget::updateState() { const double cur_sec = can->currentSec(); if (!is_zoomed) { - double pos = (cur_sec - display_range.first) / std::max(1.0, (display_range.second - display_range.first)); + double pos = (cur_sec - display_range.first) / std::max(1.0, max_chart_range); if (pos < 0 || pos > 0.8) { display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1); } - auto events = can->events(); - double max_event_sec = events->empty() ? 0 : (events->back()->mono_time / 1e9 - can->routeStartTime()); - double max_sec = std::min(std::floor(display_range.first + max_chart_range), max_event_sec); + double max_sec = std::min(std::floor(display_range.first + max_chart_range), can->lastEventSecond()); display_range.first = std::max(0.0, max_sec - max_chart_range); display_range.second = display_range.first + max_chart_range; } else if (cur_sec < zoomed_range.first || cur_sec >= zoomed_range.second) { @@ -326,6 +326,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { setRenderHint(QPainter::Antialiasing); // TODO: enable zoomIn/seekTo in live streaming mode. setRubberBand(can->liveStreaming() ? QChartView::NoRubberBand : QChartView::HorizontalRubberBand); + setMouseTracking(true); QObject::connect(dbc(), &DBCManager::signalRemoved, this, &ChartView::signalRemoved); QObject::connect(dbc(), &DBCManager::signalUpdated, this, &ChartView::signalUpdated); @@ -481,8 +482,8 @@ void ChartView::updatePlot(double cur, double min, double max) { void ChartView::updateSeriesPoints() { // Show points when zoomed in enough 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; }); - auto end = std::lower_bound(begin, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto begin = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); + auto end = std::lower_bound(begin, s.vals.end(), axis_x->max(), xLessThan); int num_points = std::max(end - begin, 1); int pixels_per_point = width() / num_points; @@ -496,64 +497,33 @@ void ChartView::updateSeriesPoints() { } void ChartView::updateSeries(const cabana::Signal *sig) { - const auto events = can->events(); for (auto &s : sigs) { if (!sig || s.sig == sig) { if (!can->liveStreaming()) { s.vals.clear(); s.step_vals.clear(); - s.vals.reserve(settings.max_cached_minutes * 60 * 100); // [n]seconds * 100hz - s.step_vals.reserve(settings.max_cached_minutes * 60 * 100 * 2); s.last_value_mono_time = 0; } s.series->setColor(getColor(s.sig)); - struct Chunk { - std::vector::const_iterator first, second; - QVector vals; - QVector step_vals; - }; - // split into one minitue chunks - QVector chunks; - Event begin_event(cereal::Event::Which::INIT_DATA, s.last_value_mono_time); - auto begin = std::upper_bound(events->begin(), events->end(), &begin_event, Event::lessThan()); - for (auto it = begin, second = begin; it != events->end(); it = second) { - second = std::lower_bound(it, events->end(), (*it)->mono_time + 1e9 * 60, [](auto &e, uint64_t ts) { return e->mono_time < ts; }); - chunks.push_back({it, second}); + auto msgs = can->events().at(s.msg_id); + auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time=s.last_value_mono_time}); + int new_size = std::max(s.vals.size() + std::distance(first, msgs.cend()), settings.max_cached_minutes * 60 * 100); + if (s.vals.capacity() <= new_size) { + s.vals.reserve(new_size * 2); + s.step_vals.reserve(new_size * 4); } - QtConcurrent::blockingMap(chunks, [&](Chunk &chunk) { - chunk.vals.reserve(60 * 100); // 100 hz - chunk.step_vals.reserve(60 * 100 * 2); // 100 hz - double route_start_time = can->routeStartTime(); - for (auto it = chunk.first; it != chunk.second; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - if (s.msg_id.address == c.getAddress() && s.msg_id.source == c.getSrc()) { - 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 - chunk.vals.push_back({ts, value}); - if (!chunk.step_vals.empty()) { - chunk.step_vals.push_back({ts, chunk.step_vals.back().y()}); - } - chunk.step_vals.push_back({ts,value}); - } - } - } + const double route_start_time = can->routeStartTime(); + for (auto end = msgs.cend(); first != end; ++first) { + double value = get_raw_value(first->dat, first->size, *s.sig); + double ts = first->mono_time / 1e9 - route_start_time; // seconds + s.vals.append({ts, value}); + if (!s.step_vals.empty()) { + s.step_vals.append({ts, s.step_vals.back().y()}); } - }); - for (auto &c : chunks) { - s.vals.append(c.vals); - if (!c.step_vals.empty()) { - if (!s.step_vals.empty()) { - s.step_vals.append({c.step_vals.first().x(), s.step_vals.back().y()}); - } - s.step_vals.append(c.step_vals); - } - } - if (events->size()) { - s.last_value_mono_time = events->back()->mono_time; + s.step_vals.append({ts, value}); + s.last_value_mono_time = first->mono_time; } if (!can->liveStreaming()) { s.segment_tree.build(s.vals); @@ -580,8 +550,8 @@ void ChartView::updateAxisY() { unit.clear(); } - auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); + auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), xLessThan); if (can->liveStreaming()) { for (auto it = first; it != last; ++it) { if (it->y() < min) min = it->y(); @@ -826,8 +796,8 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { painter->setPen(Qt::NoPen); for (auto &s : sigs) { if (s.series->useOpenGL() && s.series->isVisible() && s.series->pointsVisible()) { - auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), [](auto &p, double x) { return p.x() < x; }); - auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), [](auto &p, double x) { return p.x() < x; }); + auto first = std::lower_bound(s.vals.begin(), s.vals.end(), axis_x->min(), xLessThan); + auto last = std::lower_bound(first, s.vals.end(), axis_x->max(), xLessThan); for (auto it = first; it != last; ++it) { painter->setBrush(s.series->color()); painter->drawEllipse(chart()->mapToPosition(*it), 4, 4); @@ -929,7 +899,7 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); main_layout->addWidget(buttonBox, 3, 2); - for (auto it = can->can_msgs.cbegin(); it != can->can_msgs.cend(); ++it) { + for (auto it = can->last_msgs.cbegin(); it != can->last_msgs.cend(); ++it) { if (auto m = dbc()->msg(it.key())) { msgs_combo->addItem(QString("%1 (%2)").arg(m->name).arg(it.key().toString()), QVariant::fromValue(it.key())); } diff --git a/tools/cabana/dbc.cc b/tools/cabana/dbc.cc index ff100e01f7..38002af06c 100644 --- a/tools/cabana/dbc.cc +++ b/tools/cabana/dbc.cc @@ -27,7 +27,7 @@ static QVector BIG_ENDIAN_START_BITS = []() { return ret; }(); -double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig) { +double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig) { int64_t val = 0; int i = sig.msb / 8; diff --git a/tools/cabana/dbc.h b/tools/cabana/dbc.h index a2ebbc16cc..701908112f 100644 --- a/tools/cabana/dbc.h +++ b/tools/cabana/dbc.h @@ -38,6 +38,10 @@ struct MessageId { uint qHash(const MessageId &item); Q_DECLARE_METATYPE(MessageId); +template <> +struct std::hash { + std::size_t operator()(const MessageId &k) const noexcept { return qHash(k); } +}; typedef QList> ValueDescription; @@ -72,7 +76,7 @@ namespace cabana { } // Helper functions -double get_raw_value(uint8_t *data, size_t data_size, const cabana::Signal &sig); +double get_raw_value(const uint8_t *data, size_t data_size, const cabana::Signal &sig); int bigEndianStartBitsIndex(int start_bit); int bigEndianBitIndex(int index); void updateSigSizeParamsFromRange(cabana::Signal &s, int start_bit, int size); diff --git a/tools/cabana/dbcmanager.cc b/tools/cabana/dbcmanager.cc index 651367ba57..49aac5c18b 100644 --- a/tools/cabana/dbcmanager.cc +++ b/tools/cabana/dbcmanager.cc @@ -212,4 +212,3 @@ DBCManager *dbc() { static DBCManager dbc_manager(nullptr); return &dbc_manager; } - diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 830fd30d49..3e80a6a697 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -119,40 +119,31 @@ template std::deque HistoryLogModel::fetchData(InputIt first, InputIt last, uint64_t min_time) { std::deque msgs; QVector values(sigs.size()); - for (auto it = first; it != last && (*it)->mono_time > min_time; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - if (msg_id.address == c.getAddress() && msg_id.source == c.getSrc()) { - const auto dat = c.getDat(); - for (int i = 0; i < sigs.size(); ++i) { - values[i] = get_raw_value((uint8_t *)dat.begin(), dat.size(), *sigs[i]); - } - if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { - auto &m = msgs.emplace_back(); - m.mono_time = (*it)->mono_time; - m.data = QByteArray((char *)dat.begin(), dat.size()); - m.sig_values = values; - if (msgs.size() >= batch_size && min_time == 0) - return msgs; - } - } + for (; first != last && first->mono_time > min_time; ++first) { + for (int i = 0; i < sigs.size(); ++i) { + values[i] = get_raw_value(first->dat, first->size, *sigs[i]); + } + if (!filter_cmp || filter_cmp(values[filter_sig_idx], filter_value)) { + auto &m = msgs.emplace_back(); + m.mono_time = first->mono_time; + m.data = QByteArray((const char *)first->dat, first->size); + m.sig_values = values; + if (msgs.size() >= batch_size && min_time == 0) { + return msgs; } } } return msgs; } -template std::deque HistoryLogModel::fetchData<>(std::vector::iterator first, std::vector::iterator last, uint64_t min_time); -template std::deque HistoryLogModel::fetchData<>(std::vector::reverse_iterator first, std::vector::reverse_iterator last, uint64_t min_time); - std::deque HistoryLogModel::fetchData(uint64_t from_time, uint64_t min_time) { - auto events = can->events(); + const auto &events = can->events().at(msg_id); const auto freq = can->lastMessage(msg_id).freq; const bool update_colors = !display_signals_mode || sigs.empty(); if (dynamic_mode) { - auto first = std::upper_bound(events->rbegin(), events->rend(), from_time, [=](uint64_t ts, auto &e) { return e->mono_time < ts; }); - auto msgs = fetchData(first, events->rend(), min_time); + auto first = std::upper_bound(events.rbegin(), events.rend(), CanEvent{.mono_time=from_time}, std::greater()); + auto msgs = fetchData(first, events.rend(), min_time); if (update_colors && (min_time > 0 || messages.empty())) { for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); @@ -162,10 +153,10 @@ std::deque HistoryLogModel::fetchData(uint64_t from_ti return msgs; } else { assert(min_time == 0); - auto first = std::upper_bound(events->begin(), events->end(), from_time, [=](uint64_t ts, auto &e) { return ts < e->mono_time; }); - auto msgs = fetchData(first, events->end(), 0); + auto first = std::upper_bound(events.begin(), events.end(), CanEvent{.mono_time=from_time}); + auto msgs = fetchData(first, events.end(), 0); if (update_colors) { - for (auto it = msgs.rbegin(); it != msgs.rend(); ++it) { + for (auto it = msgs.begin(); it != msgs.end(); ++it) { hex_colors.compute(it->data, it->mono_time / (double)1e9, freq); it->colors = hex_colors.colors; } diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index 56ffe872d6..befbf270c6 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -446,15 +446,7 @@ void MainWindow::updateDownloadProgress(uint64_t cur, uint64_t total, bool succe } void MainWindow::updateStatus() { - float cached_minutes = 0; - if (!can->liveStreaming()) { - if (auto events = can->events(); !events->empty()) { - cached_minutes = (events->back()->mono_time - events->front()->mono_time) / (1e9 * 60); - } - } else { - settings.max_cached_minutes = settings.max_cached_minutes; - } - status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(cached_minutes, 0, 'f', 1).arg(settings.fps)); + status_label->setText(tr("Cached Minutes:%1 FPS:%2").arg(settings.max_cached_minutes).arg(settings.fps)); } void MainWindow::dockCharts(bool dock) { diff --git a/tools/cabana/messageswidget.cc b/tools/cabana/messageswidget.cc index b4a7ed7b34..8dd0bac820 100644 --- a/tools/cabana/messageswidget.cc +++ b/tools/cabana/messageswidget.cc @@ -160,7 +160,7 @@ void MessageListModel::setFilterString(const QString &string) { filter_str = string; msgs.clear(); - for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { if (filter_str.isEmpty() || contains(it.key(), filter_str)) { msgs.push_back(it.key()); } @@ -206,8 +206,8 @@ void MessageListModel::sortMessages() { void MessageListModel::msgsReceived(const QHash *new_msgs) { int prev_row_count = msgs.size(); - if (filter_str.isEmpty() && msgs.size() != can->can_msgs.size()) { - msgs = can->can_msgs.keys(); + if (filter_str.isEmpty() && msgs.size() != can->last_msgs.size()) { + msgs = can->last_msgs.keys(); } if (msgs.size() != prev_row_count) { sortMessages(); diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc index c8ff449098..d60beed0c8 100644 --- a/tools/cabana/streams/abstractstream.cc +++ b/tools/cabana/streams/abstractstream.cc @@ -1,6 +1,5 @@ #include "tools/cabana/streams/abstractstream.h" #include -#include AbstractStream *can = nullptr; @@ -13,7 +12,7 @@ AbstractStream::AbstractStream(QObject *parent, bool is_live_streaming) : is_liv void AbstractStream::process(QHash *messages) { for (auto it = messages->begin(); it != messages->end(); ++it) { - can_msgs[it.key()] = it.value(); + last_msgs[it.key()] = it.value(); } emit updated(); emit msgsReceived(messages); @@ -62,66 +61,68 @@ bool AbstractStream::updateEvent(const Event *event) { const CanData &AbstractStream::lastMessage(const MessageId &id) { static CanData empty_data; - auto it = can_msgs.find(id); - return it != can_msgs.end() ? it.value() : empty_data; + auto it = last_msgs.find(id); + return it != last_msgs.end() ? it.value() : empty_data; } -static QHash parseEvents(std::vector::const_reverse_iterator first, - std::vector::const_reverse_iterator last, double route_start_time) { - QHash msgs; - msgs.reserve(500); - for (auto it = first; it != last; ++it) { - if ((*it)->which == cereal::Event::Which::CAN) { - for (const auto &c : (*it)->event.getCan()) { - auto &m = msgs[{.source = c.getSrc(), .address = c.getAddress()}]; - if (++m.count == 1) { - m.ts = ((*it)->mono_time / 1e9) - route_start_time; - m.dat = QByteArray((char *)c.getDat().begin(), c.getDat().size()); - m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); - m.last_change_t = QVector(m.dat.size(), m.ts); - m.bit_change_counts.resize(m.dat.size()); - } - } - } - } - return msgs; -}; - // it is thread safe to update data in updateLastMsgsTo. // updateEvent will not be called before replayStream::seekedTo return. void AbstractStream::updateLastMsgsTo(double sec) { - uint64_t ts = (sec + routeStartTime()) * 1e9; - const uint64_t delta = std::max(std::ceil(sec / std::thread::hardware_concurrency()), 30.0) * 1e9; - const auto evs = events(); - auto first = std::upper_bound(evs->crbegin(), evs->crend(), ts, [](uint64_t ts, auto &e) { return ts > e->mono_time; }); - QFutureSynchronizer> synchronizer; - while(first != evs->crend()) { - ts = (*first)->mono_time > delta ? (*first)->mono_time - delta : 0; - auto last = std::lower_bound(first, evs->crend(), ts, [](auto &e, uint64_t ts) { return e->mono_time > ts; }); - synchronizer.addFuture(QtConcurrent::run(parseEvents, first, last, routeStartTime())); - first = last; - } - synchronizer.waitForFinished(); - new_msgs->clear(); change_trackers.clear(); - can_msgs.clear(); + last_msgs.clear(); counters.clear(); - for (const auto &f : synchronizer.futures()) { - auto msgs = f.result(); - for (auto it = msgs.cbegin(); it != msgs.cend(); ++it) { - counters[it.key()] += it.value().count; - auto m = can_msgs.find(it.key()); - if (m == can_msgs.end()) { - m = can_msgs.insert(it.key(), it.value()); - } else { - m.value().count += it.value().count; - } - m.value().freq = m.value().count / std::max(1.0, m.value().ts); + + CanEvent last_event = {.mono_time = uint64_t((sec + routeStartTime()) * 1e9)}; + for (auto &[id, e] : events_) { + auto it = std::lower_bound(e.crbegin(), e.crend(), last_event, std::greater()); + if (it != e.crend()) { + auto &m = last_msgs[id]; + m.dat = QByteArray((const char *)it->dat, it->size); + m.ts = it->mono_time / 1e9 - routeStartTime(); + m.count = std::distance(it, e.crend()); + m.freq = m.count / std::max(1.0, m.ts); + m.last_change_t = QVector(m.dat.size(), m.ts); + m.colors = QVector(m.dat.size(), QColor(0, 0, 0, 0)); + m.bit_change_counts = QVector>(m.dat.size()); + counters[id] = m.count; } } QTimer::singleShot(0, [this]() { emit updated(); - emit msgsReceived(&can_msgs); + emit msgsReceived(&last_msgs); }); } + +void AbstractStream::parseEvents(std::unordered_map> &msgs, + std::vector::const_iterator first, std::vector::const_iterator last) { + for (; first != last; ++first) { + if ((*first)->which == cereal::Event::Which::CAN) { + for (const auto &c : (*first)->event.getCan()) { + auto dat = c.getDat(); + auto &m = msgs[{.source = c.getSrc(), .address = c.getAddress()}].emplace_back(); + m.size = std::min(dat.size(), std::size(m.dat)); + memcpy(m.dat, (uint8_t *)dat.begin(), m.size); + m.mono_time = (*first)->mono_time; + } + last_event_ts = std::max(last_event_ts, (*first)->mono_time); + } + } +} + +void AbstractStream::mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append) { + if (first == last) return; + + if (append) { + parseEvents(events_, first, last); + } else { + std::unordered_map> new_events; + parseEvents(new_events, first, last); + for (auto &[id, new_e] : new_events) { + auto &e = events_[id]; + auto it = std::upper_bound(e.cbegin(), e.cend(), new_e.front()); + e.insert(it, new_e.cbegin(), new_e.cend()); + } + } + emit eventsMerged(); +} diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index d1cf9d8037..3c7bdd6132 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -1,7 +1,8 @@ #pragma once #include - +#include +#include #include #include @@ -20,6 +21,14 @@ struct CanData { QVector> bit_change_counts; }; +struct CanEvent { + uint64_t mono_time; + uint8_t size; + uint8_t dat[64]; + inline bool operator<(const CanEvent &r) const { return mono_time < r.mono_time; } + inline bool operator>(const CanEvent &r) const { return mono_time > r.mono_time; } +}; + class AbstractStream : public QObject { Q_OBJECT @@ -27,6 +36,7 @@ public: AbstractStream(QObject *parent, bool is_live_streaming); virtual ~AbstractStream() {}; inline bool liveStreaming() const { return is_live_streaming; } + inline double lastEventSecond() const { return last_event_ts / 1e9 - routeStartTime(); } virtual void seekTo(double ts) {} virtual QString routeName() const = 0; virtual QString carFingerprint() const { return ""; } @@ -37,11 +47,12 @@ public: virtual const CanData &lastMessage(const MessageId &id); virtual VisionStreamType visionStreamType() const { return VISION_STREAM_ROAD; } virtual const Route *route() const { return nullptr; } - virtual const std::vector *events() const = 0; virtual void setSpeed(float speed) {} virtual bool isPaused() const { return false; } virtual void pause(bool pause) {} + const std::unordered_map> &events() const { return events_; } virtual const std::vector> getTimeline() { return {}; } + void mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append); signals: void paused(); @@ -55,19 +66,22 @@ signals: void sourcesUpdated(const QSet &s); public: - QHash can_msgs; + QHash last_msgs; QSet sources; protected: virtual void process(QHash *); bool updateEvent(const Event *event); void updateLastMsgsTo(double sec); + void parseEvents(std::unordered_map> &msgs, std::vector::const_iterator first, std::vector::const_iterator last); bool is_live_streaming = false; std::atomic processing = false; QHash counters; std::unique_ptr> new_msgs; QHash change_trackers; + std::unordered_map> events_; + uint64_t last_event_ts = 0; }; // A global pointer referring to the unique AbstractStream object diff --git a/tools/cabana/streams/livestream.cc b/tools/cabana/streams/livestream.cc index 256cfc5a3e..62ad635152 100644 --- a/tools/cabana/streams/livestream.cc +++ b/tools/cabana/streams/livestream.cc @@ -52,7 +52,7 @@ void LiveStream::handleEvent(Event *evt) { auto it = std::upper_bound(received.cbegin(), received.cend(), current_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); - if (it != can_events.cend()) { + if (it != received.cend()) { bool skip = (nanos_since_boot() - last_update_ts) < ((*it)->mono_time - current_ts) / speed_; if (skip) return; @@ -68,16 +68,15 @@ void LiveStream::handleEvent(Event *evt) { void LiveStream::process(QHash *last_messages) { { std::lock_guard lk(lock); - uint64_t last_ts = can_events.empty() ? 0 : can_events.back()->mono_time; - auto first = std::upper_bound(received.cbegin(), received.cend(), last_ts, [](uint64_t ts, auto &e) { + auto first = std::upper_bound(received.cbegin(), received.cend(), last_event_ts, [](uint64_t ts, auto &e) { return ts < e->mono_time; }); - can_events.insert(can_events.end(), first, received.cend()); + mergeEvents(first, received.cend(), true); if (speed_ == 1) { received.clear(); + messages.clear(); } } - emit eventsMerged(); AbstractStream::process(last_messages); } diff --git a/tools/cabana/streams/livestream.h b/tools/cabana/streams/livestream.h index 657d7e407f..598c0b9365 100644 --- a/tools/cabana/streams/livestream.h +++ b/tools/cabana/streams/livestream.h @@ -16,27 +16,23 @@ public: void setSpeed(float speed) override { speed_ = std::min(1.0, speed); } bool isPaused() const override { return pause_; } void pause(bool pause) override; - const std::vector *events() const override { return &can_events; } protected: - void process(QHash *) override; virtual void handleEvent(Event *evt); virtual void streamThread(); + void process(QHash *) override; struct Msg { Msg(Message *m) { event = ::new Event(aligned_buf.align(m)); delete m; } - ~Msg() { - ::delete event; - } + ~Msg() { ::delete event; } Event *event; AlignedBuffer aligned_buf; }; mutable std::mutex lock; - std::vector can_events; std::vector received; std::deque messages; std::atomic start_ts = 0; diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index ebd969be61..140a795d3a 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -14,13 +14,24 @@ static bool event_filter(const Event *e, void *opaque) { return ((ReplayStream *)opaque)->eventFilter(e); } +void ReplayStream::mergeSegments() { + for (auto &[n, seg] : replay->segments()) { + if (seg && seg->isLoaded() && !processed_segments.count(n)) { + const auto &events = seg->log->events; + bool append = processed_segments.empty() || *processed_segments.rbegin() < n; + processed_segments.insert(n); + mergeEvents(events.cbegin(), events.cend(), append); + } + } +} + bool ReplayStream::loadRoute(const QString &route, const QString &data_dir) { replay.reset(new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this)); replay->setSegmentCacheLimit(settings.max_cached_minutes); replay->installEventFilter(event_filter, this); QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo); - QObject::connect(replay.get(), &Replay::segmentsMerged, this, &AbstractStream::eventsMerged); QObject::connect(replay.get(), &Replay::streamStarted, this, &AbstractStream::streamStarted); + QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments); if (replay->load()) { const auto &segments = replay->route()->segments(); if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 3505f6abf4..6fc61f7f36 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -20,13 +20,14 @@ public: inline double currentSec() const override { return replay->currentSeconds(); } inline QDateTime currentDateTime() const override { return replay->currentDateTime(); } inline const Route *route() const override { return replay->route(); } - inline const std::vector *events() const override { return replay->events(); } inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; inline const std::vector> getTimeline() override { return replay->getTimeline(); } private: + void mergeSegments(); std::unique_ptr replay = nullptr; uint32_t replay_flags = REPLAY_FLAG_NONE; + std::set processed_segments; }; diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index 7768359df4..ffd0df0501 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -19,7 +19,7 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi QHBoxLayout *form_layout = new QHBoxLayout(); bus_combo = new QComboBox(this); QSet bus_set; - for (auto it = can->can_msgs.begin(); it != can->can_msgs.end(); ++it) { + for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { bus_set << it.key().source; } for (uint8_t bus : bus_set) { @@ -102,29 +102,24 @@ void FindSimilarBitsDlg::find() { QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt) { QHash> mismatches; QHash msg_count; - auto events = can->events(); int bit_to_find = -1; - for (auto e : *events) { - if (e->which == cereal::Event::Which::CAN) { - for (const auto &c : e->event.getCan()) { - if (c.getSrc() == bus) { - const auto dat = c.getDat(); - uint32_t address = c.getAddress(); - if (address == selected_address && dat.size() > byte_idx) { - bit_to_find = ((dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; - } - ++msg_count[address]; - if (bit_to_find == -1) continue; + for (const auto &[id, msg] : can->events()) { + if (id.source == bus) { + for (const auto &c : msg) { + if (id.address == selected_address && c.size > byte_idx) { + bit_to_find = ((c.dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + } + ++msg_count[id.address]; + if (bit_to_find == -1) continue; - auto &mismatched = mismatches[address]; - if (mismatched.size() < dat.size() * 8) { - mismatched.resize(dat.size() * 8); - } - for (int i = 0; i < dat.size(); ++i) { - for (int j = 0; j < 8; ++j) { - int bit = ((dat[i] >> (7 - j)) & 1) != 0; - mismatched[i * 8 + j] += (bit != bit_to_find); - } + auto &mismatched = mismatches[id.address]; + if (mismatched.size() < c.size * 8) { + mismatched.resize(c.size * 8); + } + for (int i = 0; i < c.size; ++i) { + for (int j = 0; j < 8; ++j) { + int bit = ((c.dat[i] >> (7 - j)) & 1) != 0; + mismatched[i * 8 + j] += (bit != bit_to_find); } } } diff --git a/tools/replay/replay.h b/tools/replay/replay.h index 6788a97d03..2bb426361b 100644 --- a/tools/replay/replay.h +++ b/tools/replay/replay.h @@ -71,6 +71,7 @@ public: inline void setSpeed(float speed) { speed_ = speed; } inline float getSpeed() const { return speed_; } inline const std::vector *events() const { return events_.get(); } + inline const std::map> &segments() const { return segments_; }; inline const std::string &carFingerprint() const { return car_fingerprint_; } inline const std::vector> getTimeline() { std::lock_guard lk(timeline_lock); From d8a55de1669704e7a847c346f715d0659d54e9ca Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Mar 2023 07:14:43 +0800 Subject: [PATCH 1122/1179] ui: remove lupdate warnings: "Qualifying with unknown namespace" (#27616) --- selfdrive/ui/update_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/ui/update_translations.py b/selfdrive/ui/update_translations.py index e15d4c3433..5964eb49dc 100755 --- a/selfdrive/ui/update_translations.py +++ b/selfdrive/ui/update_translations.py @@ -19,7 +19,7 @@ def update_translations(vanish=False, plural_only=None, translations_dir=TRANSLA for file in translation_files.values(): tr_file = os.path.join(translations_dir, f"{file}.ts") - args = f"lupdate -locations none -recursive {UI_DIR} -ts {tr_file}" + args = f"lupdate -locations none -recursive {UI_DIR} -ts {tr_file} -I {BASEDIR}" if vanish: args += " -no-obsolete" if file in plural_only: From 455d76cdb6d06d85171bc252a06517d5432b6c68 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 17 Mar 2023 16:17:42 -0700 Subject: [PATCH 1123/1179] manager: log time with exit param (#27615) * manager: log time with exit param * fix double brackets --- selfdrive/manager/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 1128097251..1b10cee806 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -153,7 +153,7 @@ def manager_thread() -> None: for param in ("DoUninstall", "DoShutdown", "DoReboot"): if params.get_bool(param): shutdown = True - params.put("LastManagerExitReason", param) + params.put("LastManagerExitReason", f"{param} {datetime.datetime.now()}") cloudlog.warning(f"Shutting down manager - {param} set") if shutdown: From 741d26b0255b806fce545b987b52e7a21c5a5d14 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 18 Mar 2023 07:18:38 +0800 Subject: [PATCH 1124/1179] cabana: set min-max values from size when creating a new signal. (#27589) --- tools/cabana/signaledit.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 673a68a50b..d91f6c1401 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -245,7 +245,7 @@ void SignalModel::addSignal(int start_bit, int size, bool little_endian) { } } - cabana::Signal sig = {.is_little_endian = little_endian, .factor = 1}; + cabana::Signal sig = {.is_little_endian = little_endian, .factor = 1, .min = "0", .max = QString::number(std::pow(2, size) - 1)}; for (int i = 1; /**/; ++i) { sig.name = QString("NEW_SIGNAL_%1").arg(i); if (msg->sig(sig.name) == nullptr) break; From 4718fa574813b966557e453f25ab65a56fbce8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Fri, 17 Mar 2023 16:39:44 -0700 Subject: [PATCH 1125/1179] Bump laika (#27618) * Laika on master * use constellation id --- laika_repo | 2 +- selfdrive/locationd/laikad.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/laika_repo b/laika_repo index 719c79a156..6fadabd860 160000 --- a/laika_repo +++ b/laika_repo @@ -1 +1 @@ -Subproject commit 719c79a156cd254fa8ebde101c2f48583f91afed +Subproject commit 6fadabd86043ee19e06c6ed59aa4e688c14fa8e4 diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 3698867ec9..87b0cf9291 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -72,7 +72,7 @@ def get_log_eph_source(ephem): class Laikad: - def __init__(self, valid_const=("GPS", "GLONASS"), auto_fetch_navs=True, auto_update=False, + def __init__(self, valid_const=(ConstellationId.GPS, ConstellationId.GLONASS), auto_fetch_navs=True, auto_update=False, valid_ephem_types=(EphemerisType.NAV, EphemerisType.QCOM_POLY), save_ephemeris=False, use_qcom=False): """ From 529ba41825c3d47ee6f322ddecc8471d8e0cdd3a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 19 Mar 2023 05:34:11 +0800 Subject: [PATCH 1126/1179] cabana: display zoom range while dragging rubber-band selection (#27620) --- tools/cabana/chartswidget.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 04734e6749..09fcbf2ee2 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -666,6 +666,8 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } else if ((max_rounded - min_rounded) >= 0.5) { // zoom in if selected range is greater than 0.5s emit zoomIn(min_rounded, max_rounded); + } else { + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } event->accept(); } else if (!can->liveStreaming() && event->button() == Qt::RightButton) { @@ -738,6 +740,7 @@ void ChartView::mouseMoveEvent(QMouseEvent *ev) { if (rubber_rect != rubber->geometry()) { rubber->setGeometry(rubber_rect); } + scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } } @@ -804,6 +807,21 @@ void ChartView::drawForeground(QPainter *painter, const QRectF &rect) { } } } + + // paint zoom range + auto rubber = findChild(); + if (rubber && rubber->isVisible() && rubber->width() > 1) { + painter->setPen(Qt::white); + auto rubber_rect = rubber->geometry().normalized(); + for (const auto &pt : {rubber_rect.bottomLeft(), rubber_rect.bottomRight()}) { + QString sec = QString::number(chart()->mapToValue(pt).x(), 'f', 1); + // ChartAxisElement's padding is 4 (https://codebrowser.dev/qt5/qtcharts/src/charts/axis/chartaxiselement_p.h.html) + auto r = painter->fontMetrics().boundingRect(sec).adjusted(-6, -4, 6, 4); + pt == rubber_rect.bottomLeft() ? r.moveTopRight(pt + QPoint{0, 2}) : r.moveTopLeft(pt + QPoint{0, 2}); + painter->fillRect(r, Qt::gray); + painter->drawText(r, Qt::AlignCenter, sec); + } + } } QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { From 5e269b25c470b73cd4a413d10d89c1f74584b41f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sat, 18 Mar 2023 20:03:00 -0700 Subject: [PATCH 1127/1179] plotjuggler: update controls mismatch layout --- .../layouts/controls_mismatch_debug.xml | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/tools/plotjuggler/layouts/controls_mismatch_debug.xml b/tools/plotjuggler/layouts/controls_mismatch_debug.xml index adca3eed29..54586d6e7b 100644 --- a/tools/plotjuggler/layouts/controls_mismatch_debug.xml +++ b/tools/plotjuggler/layouts/controls_mismatch_debug.xml @@ -1,37 +1,44 @@ - + - + - - + + - - + + - - + + - + - - + + - + - - + + - - + + + + + + + + + @@ -46,8 +53,8 @@ - - + + From ae423a68686ca258c40fa679b931011e99f5f780 Mon Sep 17 00:00:00 2001 From: koch-cf <62287055+koch-cf@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:10:19 -0400 Subject: [PATCH 1128/1179] GM: Buick LaCrosse 2017-19 support (#27332) * Added Buick LaCrosse 2017 * Added Buick LaCrosse as candidate * Added Buick LaCrosse CAR_INFO and Fingerprint * Added Buick LaCrosse to non_tested_cars * Added Buick LaCrosse * Updated number of supported cars to 237 * Added ACC and LKAS description to Buick LaCrosse * Updated CAR_INFO for Buick LaCrosse * Added the Escalade which was recently updated * Update selfdrive/car/gm/values.py Suggested fingerprint by @sshane Co-authored-by: Shane Smiskol * Premium is a trim with ACC. Use package name instead * lacrosse custom FF; fit info: describe(steer_offsets) = DescribeResult(nobs=1649402, minmax=(-0.7127894163131714, 5.3997602462768555), mean=3.3090523060153645, variance=0.3130325564084465, skewness=-1.5986155151533736, kurtosis=8.18810418298873) Samples: 1357787 Regularizing... Regularized samples: 1140 speed: DescribeResult(nobs=1140, minmax=(8.478170424241286, 35.837870224662446), mean=27.888804767013475, variance=34.16742353763829, skewness=-1.068587303119431, kurtosis=0.6193071765927134) angle: DescribeResult(nobs=1140, minmax=(-21.057768565637094, 28.516874490999708), mean=-0.4328602593886506, variance=43.19046813273241, skewness=0.001966426701503317, kurtosis=0.20547357649038434) steer: DescribeResult(nobs=1140, minmax=(-0.8432471203007578, 0.9634959333674695), mean=-0.021981142946747863, variance=0.20152217060233915, skewness=0.03202313890158864, kurtosis=-1.2318826088567174) Performing fit... Fit: [5.85397825e-01 3.27650818e-01 4.60531117e-03 1.32307599e+01 1.37194709e-01 1.33099557e-01 6.14782304e-02] ANGLE_COEF = 0.58539783 ANGLE_COEF2 = 0.32765082 ANGLE_OFFSET = 0.00460531 SPEED_OFFSET = 13.23075991 SIGMOID_COEF_RIGHT = 0.13719471 SIGMOID_COEF_LEFT = 0.13309956 SPEED_COEF = 0.06147823 MAE old 0.2098, new 0.0309 STD old 0.1021, new 0.0273 deg 00-03:457, deg 03-06:258, deg 06-09:218, deg 09-12:132, deg 12-15:62 deg 15-18:6, deg 18-21:4, deg 21-24:1, deg 24-27:0, deg 27-30:2 deg 30-33:0, deg 33-36:0, deg 36-39:0, deg 39-42:0, deg 42-45:0 mph 10-15:0, mph 15-20:1, mph 20-25:18, mph 25-30:12, mph 30-35:30 mph 35-40:26, mph 40-45:52, mph 45-50:54, mph 50-55:73, mph 55-60:86 mph 60-65:204, mph 65-70:228, mph 70-75:179, mph 75-80:176, mph 80-85:1 mph 85-90:0, * Update routes.py * remove from non tested routes * use torque controller * update docs * update releases --------- Co-authored-by: Shane Smiskol Co-authored-by: Tim Wilson --- RELEASES.md | 1 + docs/CARS.md | 3 ++- selfdrive/car/gm/interface.py | 7 +++++++ selfdrive/car/gm/values.py | 7 +++++++ selfdrive/car/tests/routes.py | 1 + selfdrive/car/torque_data/substitute.yaml | 1 + 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 9cfcbafea1..55b0dbad7e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,7 @@ Version 0.9.2 (2023-03-XX) ======================== * Draw MPC path instead of model predicted path, this is a more accurate representation of what the car will do. +* Buick LaCrosse 2017-19 support thanks to koch-cf! * Škoda Fabia 2022-23 support thanks to jyoung8607! Version 0.9.1 (2023-02-28) diff --git a/docs/CARS.md b/docs/CARS.md index 070d068cab..c4a3cedfe0 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system. -# 238 Supported Cars +# 239 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -17,6 +17,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| +|Buick|LaCrosse 2017-19[3](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Cadillac|Escalade 2017[3](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Cadillac|Escalade ESV 2016[3](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|| diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 7e6e71c642..602d7e31b6 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -150,6 +150,13 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia() ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking + elif candidate == CAR.BUICK_LACROSSE: + ret.mass = 1712. + STD_CARGO_KG + ret.wheelbase = 2.91 + ret.steerRatio = 15.8 + ret.centerToFront = ret.wheelbase * 0.4 # wild guess + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.BUICK_REGAL: ret.mass = 3779. * CV.LB_TO_KG + STD_CARGO_KG # (3849+3708)/2 ret.wheelbase = 2.83 # 111.4 inches in meters diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 2ac418b629..0d13cb9827 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -66,6 +66,7 @@ class CAR: CADILLAC_ATS = "CADILLAC ATS Premium Performance 2018" MALIBU = "CHEVROLET MALIBU PREMIER 2017" ACADIA = "GMC ACADIA DENALI 2018" + BUICK_LACROSSE = "BUICK LACROSSE 2017" BUICK_REGAL = "BUICK REGAL ESSENCE 2018" ESCALADE = "CADILLAC ESCALADE 2017" ESCALADE_ESV = "CADILLAC ESCALADE ESV 2016" @@ -99,6 +100,7 @@ CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"), CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), + CAR.BUICK_LACROSSE: GMCarInfo("Buick LaCrosse 2017-19", "Driver Confidence Package 2"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.ESCALADE: GMCarInfo("Cadillac Escalade 2017", "Driver Assist Package"), CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), @@ -156,6 +158,11 @@ FINGERPRINTS = { { 170: 8, 171: 8, 189: 7, 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 209: 7, 211: 2, 241: 6, 288: 5, 289: 1, 290: 1, 298: 2, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 368: 8, 381: 2, 384: 8, 386: 5, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 458: 8, 479: 3, 481: 7, 485: 8, 489: 5, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 3, 508: 8, 512: 3, 528: 4, 530: 8, 532: 6, 537: 5, 539: 8, 542: 7, 546: 7, 550: 8, 554: 3, 558: 8, 560: 6, 562: 4, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 821: 4, 823: 7, 832: 8, 840: 5, 842: 5, 844: 8, 853: 8, 866: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 5, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7 }], + CAR.BUICK_LACROSSE: [ + # LaCrosse Premium AWD 2017 + { + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 + }], CAR.BUICK_REGAL : [ # Regal TourX Essence w/ ACC 2018 { diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 2c4ec84e86..4dd19d24e3 100644 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -52,6 +52,7 @@ routes = [ CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA), CarTestRoute("aa20e335f61ba898|2019-02-05--16-59-04", GM.BUICK_REGAL), + CarTestRoute("75a6bcb9b8b40373|2023-03-11--22-47-33", GM.BUICK_LACROSSE), CarTestRoute("ef8f2185104d862e|2023-02-09--18-37-13", GM.ESCALADE), CarTestRoute("46460f0da08e621e|2021-10-26--07-21-46", GM.ESCALADE_ESV), CarTestRoute("c950e28c26b5b168|2018-05-30--22-03-41", GM.VOLT), diff --git a/selfdrive/car/torque_data/substitute.yaml b/selfdrive/car/torque_data/substitute.yaml index 696d9829d1..5feef12206 100644 --- a/selfdrive/car/torque_data/substitute.yaml +++ b/selfdrive/car/torque_data/substitute.yaml @@ -50,6 +50,7 @@ HONDA CIVIC SEDAN 1.6 DIESEL 2019: HONDA CIVIC (BOSCH) 2019 HONDA E 2020: HONDA CIVIC (BOSCH) 2019 HONDA ODYSSEY CHN 2019: HONDA ODYSSEY 2018 +BUICK LACROSSE 2017: CHEVROLET VOLT PREMIER 2017 BUICK REGAL ESSENCE 2018: CHEVROLET VOLT PREMIER 2017 CADILLAC ESCALADE ESV 2016: CHEVROLET VOLT PREMIER 2017 CADILLAC ATS Premium Performance 2018: CHEVROLET VOLT PREMIER 2017 From bfbfdb28519a6da890569d30dfa325df53a7ef22 Mon Sep 17 00:00:00 2001 From: tonzy74 <69013596+tonzy74@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:18:07 -0400 Subject: [PATCH 1129/1179] Kia: Sorento 2021 support (#27623) * Update values.py * Update selfdrive/car/hyundai/values.py * update docs --------- Co-authored-by: Shane Smiskol --- docs/CARS.md | 2 +- selfdrive/car/hyundai/values.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index c4a3cedfe0..a7b6764f0c 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -117,7 +117,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|| |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|| -|Kia|Sorento 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| +|Kia|Sorento 2021-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|| |Kia|Sorento Plug-in Hybrid 2022-23[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|| |Kia|Sportage 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| |Kia|Sportage Hybrid 2023[5](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|| diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index f7cedf550e..09114512b0 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -224,7 +224,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = { HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control", "https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", harness=Harness.hyundai_e), ], - CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2022-23", harness=Harness.hyundai_k), + CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", harness=Harness.hyundai_k), CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", harness=Harness.hyundai_a), CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", harness=Harness.hyundai_n), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), @@ -1637,9 +1637,11 @@ FW_VERSIONS = { CAR.KIA_SORENTO_4TH_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.05 99210-R5000 210623', + b'\xf1\x00MQ4 MFC AT USA LHD 1.00 1.03 99210-R5000 200903', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00MQ4_ SCC FHCUP 1.00 1.06 99110-P2000 ', + b'\xf1\x00MQ4_ SCC F-CUP 1.00 1.06 99110-P2000 ', ], }, CAR.KIA_NIRO_HEV_2ND_GEN: { From e5069058f0291c1a285ae530d57f4cf0a9813b84 Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Tue, 21 Mar 2023 05:21:59 +0900 Subject: [PATCH 1130/1179] Kia: add missing Korean EV6 fwdCamera FW (#27621) * add EV6 kor camera fw * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 09114512b0..06f2e27876 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1552,6 +1552,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630', + b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823', ], }, CAR.IONIQ_5: { From 744f1e4f5764146927b830c34cd11ef9b67ecc2c Mon Sep 17 00:00:00 2001 From: Erich Moraga <33645296+ErichMoraga@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:22:50 -0500 Subject: [PATCH 1131/1179] Add missing CAMRY_TSS2 engine & fwdCamera f/w (#27619) `ChromeNinja#0001` 2023 Camry ICE DongleID/route a9c072de54f9194d|2023-03-17--17-24-56 --- selfdrive/car/toyota/values.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 965a9e6506..4edafc0c28 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -542,6 +542,7 @@ FW_VERSIONS = { (Ecu.engine, 0x700, None): [ b'\x018966306Q5000\x00\x00\x00\x00', b'\x018966306Q9000\x00\x00\x00\x00', + b'\x018966306R3000\x00\x00\x00\x00', b'\x018966306T3100\x00\x00\x00\x00', b'\x018966306T3200\x00\x00\x00\x00', b'\x018966306T4000\x00\x00\x00\x00', @@ -557,6 +558,7 @@ FW_VERSIONS = { b'\x028646F3305200\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', b'\x028646F3305200\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', b'\x028646F3305300\x00\x00\x00\x008646G5301200\x00\x00\x00\x00', + b'\x028646F3305500\x00\x00\x00\x008646G3304000\x00\x00\x00\x00', ], }, CAR.CAMRYH_TSS2: { From fa01a8e6b37aa76636fa314670657b7258f272d7 Mon Sep 17 00:00:00 2001 From: Luqi Pan Date: Mon, 20 Mar 2023 13:24:41 -0700 Subject: [PATCH 1132/1179] Add fwd camera value for 2023 GV60 Advanced (#27617) --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 06f2e27876..88e952567c 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1630,6 +1630,7 @@ FW_VERSIONS = { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU100 211215', b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.02 99211-CU000 211215', + b'\xf1\x00JW1 MFC AT USA LHD 1.00 1.03 99211-CU000 221118', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00JW1_ RDR ----- 1.00 1.00 99110-CU000 ', From 285204c5d1e83944d69dc7126c7c1d7e7921f9a2 Mon Sep 17 00:00:00 2001 From: cpaioletti <65311022+cpaioletti@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:28:52 -0400 Subject: [PATCH 1133/1179] Kia: add missing fwdCamera for Niro HEV 2023 (#27557) * Update values.py for 2023 Kia Niro HEV {'carParams': {'alternativeExperience': 0, 'autoResumeSng': True, 'carFingerprint': 'mock', 'carFw': [{'address': 2004, 'brand': 'hyundai', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'\xf1\x00SG2 MDPS C 1.00 1.06 56310AT050\x00 4SG2C106', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2012, 'subAddress': 0}, {'address': 2000, 'brand': 'hyundai', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2008, 'subAddress': 0}, {'address': 2017, 'brand': 'hyundai', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'\xf1\x00PSBG2552 D121049\x00\x00\x00DSG2G16XXH049NS6MC\xe3x', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 1988, 'brand': 'hyundai', 'bus': 1, 'ecu': 'fwdCamera', 'fwVersion': b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 1996, 'subAddress': 0}, {'address': 2016, 'brand': 'hyundai', 'bus': 1, 'ecu': 'engine', 'fwVersion': b'\xf1\x87391S3-08AF0\xf1\x81HM6M7_0a0_D00', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2024, 'subAddress': 0}, {'address': 2000, 'brand': 'hyundai', 'bus': 1, 'ecu': 'fwdRadar', 'fwVersion': b'\xf1\x8799110AT000\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2008, 'subAddress': 0}, {'address': 2004, 'brand': 'hyundai', 'bus': 1, 'ecu': 'eps', 'fwVersion': b'\xf1\x8756310AT050\x00\xf1\x00SG2 MDPS C 1.00 1.06 56310AT050\x00 4SG2C106', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2012, 'subAddress': 0}, {'address': 2017, 'brand': 'hyundai', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'\xf1\x8795441-2BGJ0\x00\xf1\x81D121049\x00\x00\x00\xf1\x00PSBG2552 D121049\x00\x00\x00DSG2G16XXH049NS6' b'MC\xe3x', 'logging': False, 'request': [b'"\xf1\x87\xf1\x81\xf1\x00'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 2000, 'brand': 'hyundai', 'bus': 4, 'ecu': 'fwdRadar', 'fwVersion': b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 2008, 'subAddress': 0}, {'address': 1975, 'brand': 'hyundai', 'bus': 4, 'ecu': 'cornerRadar', 'fwVersion': b'\xf1\x00SG2 BCW RR 1.01 , 1.04 (wQ\x83"\x02\x01\x03@', 'logging': True, 'request': [b'"\xf1\x00'], 'responseAddress': 1983, 'subAddress': 0}, {'address': 1988, 'brand': 'hyundai', 'bus': 4, 'ecu': 'fwdCamera', 'fwVersion': b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801', 'logging': False, 'request': [b'"\xf1\x00'], 'responseAddress': 1996, 'subAddress': 0}, {'address': 2017, 'brand': 'mazda', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'D121049\x00\x00\x00', 'logging': False, 'request': [b'"\xf1\x88'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 2016, 'brand': 'subaru', 'bus': 1, 'ecu': 'engine', 'fwVersion': b'0TD23N6HGXD00\x00', 'logging': False, 'request': [b'>\x00', b'"\xf1\x82'], 'responseAddress': 2024, 'subAddress': 0}, {'address': 2017, 'brand': 'subaru', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'DSG2G16XXH049NS6', 'logging': False, 'request': [b'>\x00', b'"\xf1\x82'], 'responseAddress': 2025, 'subAddress': 0}, {'address': 2016, 'brand': 'volkswagen', 'bus': 1, 'ecu': 'engine', 'fwVersion': b'\xf1\x87391S3-08AF0\xf1\x820TD23N6HGXD00\x00', 'logging': False, 'request': [b'"\xf1\x87\xf1\x89\xf1\x82'], 'responseAddress': 2024, 'subAddress': 0}, {'address': 2017, 'brand': 'volkswagen', 'bus': 1, 'ecu': 'transmission', 'fwVersion': b'\xf1\x8795441-2BGJ0\x00\xf1\x89D121049\x00\x00\x00\xf1\x82DSG2G16XXH049NS6', 'logging': False, 'request': [b'"\xf1\x87\xf1\x89\xf1\x82'], 'responseAddress': 2025, 'subAddress': 0}], * Update values.py to add missing comma Added missing comma to Line 1659 to fix previous new firmware additions for 2023 Kia Niro Hybrid * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 88e952567c..49e4ce033d 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1649,6 +1649,7 @@ FW_VERSIONS = { CAR.KIA_NIRO_HEV_2ND_GEN: { (Ecu.fwdCamera, 0x7c4, None): [ b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.08 99211-AT000 220531', + b'\xf1\x00SG2HMFC AT USA LHD 1.01 1.09 99211-AT000 220801', ], (Ecu.fwdRadar, 0x7d0, None): [ b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ', From f9c112e9b87530c463e2b10cac7bf7440d7c32d9 Mon Sep 17 00:00:00 2001 From: Jason Wen <47793918+sunnyhaibin@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:31:50 -0400 Subject: [PATCH 1134/1179] Hyundai: add Sonata FW version to enable radar tracks (#27463) --- selfdrive/debug/hyundai_enable_radar_points.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/selfdrive/debug/hyundai_enable_radar_points.py b/selfdrive/debug/hyundai_enable_radar_points.py index 07ce5ebddb..3a0ff33cb6 100755 --- a/selfdrive/debug/hyundai_enable_radar_points.py +++ b/selfdrive/debug/hyundai_enable_radar_points.py @@ -32,6 +32,9 @@ SUPPORTED_FW_VERSIONS = { b"DN8_ SCC FHCUP 1.00 1.00 99110-L0000\x19\x08)\x15T ": ConfigValues( default_config=b"\x00\x00\x00\x01\x00\x00", tracks_enabled=b"\x00\x00\x00\x01\x00\x01"), + b"DN8_ SCC F-CUP 1.00 1.00 99110-L0000\x19\x08)\x15T ": ConfigValues( + default_config=b"\x00\x00\x00\x01\x00\x00", + tracks_enabled=b"\x00\x00\x00\x01\x00\x01"), # 2021 SONATA HYBRID b"DNhe SCC FHCUP 1.00 1.02 99110-L5000 \x01#\x15# ": ConfigValues( default_config=b"\x00\x00\x00\x01\x00\x00", From aa0421ffd7dd73976b45635cb62182d66c4f1613 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Mar 2023 21:20:35 -0700 Subject: [PATCH 1135/1179] Chrysler: add FW for 2023 Ram 1500 (#27634) add FW for 2023 Ram 1500 --- docs/CARS.md | 2 +- selfdrive/car/chrysler/values.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a7b6764f0c..1f668dbe8b 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -149,7 +149,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|| -|Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|| +|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|| |SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|| |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|| diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 9f00484f34..951e5d7347 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -73,7 +73,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { ], CAR.JEEP_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"), CAR.JEEP_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"), - CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-22", harness=Harness.ram), + CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", harness=Harness.ram), CAR.RAM_HD: [ ChryslerCarInfo("Ram 2500 2020-22", harness=Harness.ram), ChryslerCarInfo("Ram 3500 2020-22", harness=Harness.ram), @@ -187,12 +187,14 @@ FW_VERSIONS = { b'68434860AC', b'68527375AD', b'68453503AC', + b'68510283AG', ], (Ecu.srs, 0x744, None): [ b'68441329AB', b'68490898AA', b'68428609AB', b'68500728AA', + b'68615033AA', ], (Ecu.abs, 0x747, None): [ b'68432418AD', @@ -202,6 +204,7 @@ FW_VERSIONS = { b'68436004AD', b'68535469AB', b'68438454AC', + b'68586307AB', ], (Ecu.fwdRadar, 0x753, None): [ b'68320950AL', @@ -210,17 +213,20 @@ FW_VERSIONS = { b'68475160AG', b'04672892AB', b'68475160AE', + b'04672932AB', ], (Ecu.eps, 0x75A, None): [ b'68273275AG', b'68469901AA', b'68552788AA', + b'68585112AB', ], (Ecu.engine, 0x7e0, None): [ b'68448163AJ', b'68500630AD', b'68539650AD', b'68378758AM ', + b'05036066AE ', ], (Ecu.transmission, 0x7e1, None): [ b'68360078AL', From 4a844078cd675ca2c75d822f5d776ca8b0b71dbf Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 20 Mar 2023 21:39:06 -0700 Subject: [PATCH 1136/1179] Chrysler: add FW for 2019 Ram 3500 (#27636) * Add 2019 Ram 3500 * wrong ones * missing EPS --- selfdrive/car/chrysler/values.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 951e5d7347..b2fb1e83bc 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -76,7 +76,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-23", harness=Harness.ram), CAR.RAM_HD: [ ChryslerCarInfo("Ram 2500 2020-22", harness=Harness.ram), - ChryslerCarInfo("Ram 3500 2020-22", harness=Harness.ram), + ChryslerCarInfo("Ram 3500 2019-22", harness=Harness.ram), ], } @@ -260,6 +260,7 @@ FW_VERSIONS = { b'04672895AB', b'56029827AG', b'68484694AE', + b'56029827AH', ], (Ecu.eps, 0x761, None): [ b'68421036AC', From aa4286153a2fb2a003307a15fbcb91ffd05d6ec2 Mon Sep 17 00:00:00 2001 From: realfast Date: Tue, 21 Mar 2023 00:54:55 -0500 Subject: [PATCH 1137/1179] Ram: FW version dump (#27083) * Add extra firmwares and sort for rams * Added another ECU * Update selfdrive/car/chrysler/values.py Co-authored-by: Shane Smiskol * Apply suggestions from code review * sort * formatting --------- Co-authored-by: Shane Smiskol --- selfdrive/car/chrysler/values.py | 97 ++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index b2fb1e83bc..984f92b5aa 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -50,6 +50,7 @@ class CarControllerParams: self.STEER_DELTA_DOWN = 3 self.STEER_MAX = 261 # higher than this faults the EPS + STEER_THRESHOLD = 120 RAM_DT = {CAR.RAM_1500, } @@ -62,6 +63,7 @@ class ChryslerCarInfo(CarInfo): package: str = "Adaptive Cruise Control (ACC)" harness: Enum = Harness.fca + CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = { CAR.PACIFICA_2017_HYBRID: ChryslerCarInfo("Chrysler Pacifica Hybrid 2017-18"), CAR.PACIFICA_2018_HYBRID: None, # same platforms @@ -182,92 +184,141 @@ FW_QUERY_CONFIG = FwQueryConfig( FW_VERSIONS = { CAR.RAM_1500: { (Ecu.combinationMeter, 0x742, None): [ - b'68294063AH', + b'68294051AG', + b'68294051AI', + b'68294052AG', b'68294063AG', + b'68294063AH', + b'68294063AI', + b'68434846AC', + b'68434858AC', b'68434860AC', - b'68527375AD', b'68453503AC', + b'68453505AC', + b'68453511AC', + b'68453513AD', + b'68453514AD', b'68510283AG', + b'68527375AD', ], (Ecu.srs, 0x744, None): [ - b'68441329AB', - b'68490898AA', b'68428609AB', + b'68441329AB', + b'68473844AB', + b'68490898AA', b'68500728AA', b'68615033AA', ], (Ecu.abs, 0x747, None): [ - b'68432418AD', + b'68292406AH', b'68432418AB', - b'68436004AE', - b'68438454AD', + b'68432418AD', b'68436004AD', - b'68535469AB', + b'68436004AE', b'68438454AC', + b'68438454AD', + b'68438456AE', + b'68438456AF', + b'68535469AB', + b'68535470AC', b'68586307AB', ], (Ecu.fwdRadar, 0x753, None): [ - b'68320950AL', - b'68320950AJ', - b'68454268AB', - b'68475160AG', b'04672892AB', - b'68475160AE', b'04672932AB', + b'68320950AH', + b'68320950AI', + b'68320950AJ', + b'68320950AL', + b'68320950AM', + b'68454268AB', + b'68475160AE', + b'68475160AF', + b'68475160AG', ], (Ecu.eps, 0x75A, None): [ + b'68273275AF', b'68273275AG', + b'68312176AE', + b'68312176AG', + b'68440789AC', + b'68466110AB', b'68469901AA', + b'68522583AB', + b'68522585AB', b'68552788AA', + b'68552790AA', b'68585112AB', ], (Ecu.engine, 0x7e0, None): [ - b'68448163AJ', - b'68500630AD', - b'68539650AD', - b'68378758AM ', + b'05036065AE ', b'05036066AE ', + b'68378701AI ', + b'68378758AM ', + b'68448163AJ', + b'68448165AK', + b'68500630AD', + b'68500630AE', + b'68539650AD', ], (Ecu.transmission, 0x7e1, None): [ b'68360078AL', - b'68384328AD', - b'68360085AL', + b'68360080AM', b'68360081AM', - b'68502994AD', + b'68360085AL', + b'68384328AD', + b'68384332AD', b'68445533AB', - b'68540431AB', b'68484467AC', + b'68502994AD', + b'68540431AB', ], }, CAR.RAM_HD: { (Ecu.combinationMeter, 0x742, None): [ b'68361606AH', + b'68437735AC', b'68492693AD', + b'68525485AB', + b'68525487AB', + b'68525498AB', ], (Ecu.srs, 0x744, None): [ b'68399794AC', b'68428503AA', b'68428505AA', + b'68428507AA', ], (Ecu.abs, 0x747, None): [ b'68334977AH', + b'68455481AC', + b'68504022AA', b'68504022AB', - b'68530686AB', b'68504022AC', + b'68530686AB', + b'68530686AC', ], (Ecu.fwdRadar, 0x753, None): [ b'04672895AB', b'56029827AG', - b'68484694AE', b'56029827AH', + b'68462657AE', + b'68484694AD', + b'68484694AE', ], (Ecu.eps, 0x761, None): [ b'68421036AC', b'68507906AB', ], (Ecu.engine, 0x7e0, None): [ + b'52370131AF', + b'52370231AF', + b'52370231AG', + b'52370931CT', + b'52401032AE', b'52421132AF', + b'68527616AD ', b'M2370131MB', b'M2421132MB', ], From e0ac5a940e8a57d140478d11e66b3485cddee3ab Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 11:25:36 -0700 Subject: [PATCH 1138/1179] bump panda --- panda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda b/panda index e4cc97d882..d70fa4e120 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit e4cc97d8826dc95a7833b859c36948302445a499 +Subproject commit d70fa4e1200ad47c66587c78fd90030a3be1cc43 From ee36c106af73b34819764ac7d23721981d387d88 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 16:14:22 -0700 Subject: [PATCH 1139/1179] process replay: update after laika publish policy change (#27647) * laika pubs all * lr for locationd * fix locationd qcom * update refs --- .../test/process_replay/process_replay.py | 30 ++++++++----------- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 971ddb3fe2..f547fce0bc 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -248,15 +248,6 @@ def ublox_rcv_callback(msg): return [] -def laika_rcv_callback(msg, CP, cfg, fsm): - if msg.which() == 'ubloxGnss' and msg.ubloxGnss.which() == "measurementReport": - return ["gnssMeasurements"], True - elif msg.which() == 'qcomGnss' and msg.qcomGnss.which() == "drMeasurementReport": - return ["gnssMeasurements"], True - else: - return [], False - - CONFIGS = [ ProcessConfig( proc_name="controlsd", @@ -331,7 +322,7 @@ CONFIGS = [ pub_sub={ "cameraOdometry": ["liveLocationKalman"], "accelerometer": [], "gyroscope": [], - "gpsLocationExternal": [], "liveCalibration": [], "carState": [], + "gpsLocationExternal": [], "liveCalibration": [], "carState": [], "gpsLocation": [], }, ignore=["logMonoTime", "valid"], init_callback=get_car_params, @@ -371,7 +362,7 @@ CONFIGS = [ }, ignore=["logMonoTime"], init_callback=get_car_params, - should_recv_callback=laika_rcv_callback, + should_recv_callback=None, tolerance=NUMPY_TOLERANCE, fake_pubsubmaster=True, ), @@ -398,7 +389,7 @@ def replay_process(cfg, lr, fingerprint=None): return cpp_replay_process(cfg, lr, fingerprint) -def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): +def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): params = Params() params.clear_all() params.put_bool("OpenpilotEnabledToggle", True) @@ -406,7 +397,6 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): params.put_bool("DisengageOnAccelerator", True) params.put_bool("WideCameraOnly", False) params.put_bool("DisableLogging", False) - params.put_bool("UbloxAvailable", True) params.put_bool("ObdMultiplexingDisabled", True) os.environ["NO_RADAR_SLEEP"] = "1" @@ -414,6 +404,10 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None): os.environ['SKIP_FW_QUERY'] = "" os.environ['FINGERPRINT'] = "" + if lr is not None: + services = {m.which() for m in lr} + params.put_bool("UbloxAvailable", "ubloxGnss" in services) + if cfg is not None: # Clear all custom processConfig environment variables for config in CONFIGS: @@ -485,10 +479,10 @@ def python_replay_process(cfg, lr, fingerprint=None): if fingerprint is not None: os.environ['SKIP_FW_QUERY'] = "1" os.environ['FINGERPRINT'] = fingerprint - setup_env(cfg=cfg, controlsState=controlsState) + setup_env(cfg=cfg, controlsState=controlsState, lr=lr) else: CP = [m for m in lr if m.which() == 'carParams'][0].carParams - setup_env(CP=CP, cfg=cfg, controlsState=controlsState) + setup_env(CP=CP, cfg=cfg, controlsState=controlsState, lr=lr) assert(type(managed_processes[cfg.proc_name]) is PythonProcess) managed_processes[cfg.proc_name].prepare() @@ -517,7 +511,7 @@ def python_replay_process(cfg, lr, fingerprint=None): recv_socks, should_recv = cfg.should_recv_callback(msg, CP, cfg, fsm) else: recv_socks = [s for s in cfg.pub_sub[msg.which()] if - (fsm.frame + 1) % int(service_list[msg.which()].frequency / service_list[s].frequency) == 0] + (fsm.frame + 1) % max(1, int(service_list[msg.which()].frequency / service_list[s].frequency)) == 0] should_recv = bool(len(recv_socks)) if msg.which() == 'can': @@ -549,14 +543,14 @@ def cpp_replay_process(cfg, lr, fingerprint=None): log_msgs = [] # We need to fake SubMaster alive since we can't inject a fake clock - setup_env(simulation=True, cfg=cfg) + setup_env(simulation=True, cfg=cfg, lr=lr) managed_processes[cfg.proc_name].prepare() managed_processes[cfg.proc_name].start() try: with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}"): - while not all(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): + while not any(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): time.sleep(0) # Make sure all subscribers are connected diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index cbe2a016ce..cf19e9cb07 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -5775220ec2e62dcdedb92d96270f1380bbd88c39 +30128f043985c8a793cdca2ad9ea1039c5086d72 \ No newline at end of file From 7319afbd516ea1b32736d67d8c5be7663dce9ae3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 16:43:40 -0700 Subject: [PATCH 1140/1179] process replay: prep for laikad subsock + QCOM GPS (#27632) * process replay: prep for laikad subsock * cleanup * fix for qcomGnss * detect ublox * more debug info in err * wip * cleanup --- selfdrive/locationd/laikad.py | 4 +- .../test/process_replay/process_replay.py | 78 ++++++++++--------- .../test/process_replay/test_processes.py | 11 ++- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 87b0cf9291..be272f1774 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -420,11 +420,11 @@ def clear_tmp_cache(): os.mkdir(DOWNLOADS_CACHE_FOLDER) -def main(sm=None, pm=None, qc=None): +def main(sm=None, pm=None): #clear_tmp_cache() use_qcom = not Params().get_bool("UbloxAvailable", block=True) - if use_qcom or (qc is not None and qc): + if use_qcom: raw_gnss_socket = "qcomGnss" else: raw_gnss_socket = "ubloxGnss" diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index f547fce0bc..9c0225796d 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -238,14 +238,14 @@ def torqued_rcv_callback(msg, CP, cfg, fsm): return recv_socks, fsm.frame == 0 or msg.which() == 'liveLocationKalman' -def ublox_rcv_callback(msg): +def ublox_rcv_callback(msg, CP, cfg, fsm): msg_class, msg_id = msg.ubloxRaw[2:4] if (msg_class, msg_id) in {(1, 7 * 16)}: - return ["gpsLocationExternal"] + return ["gpsLocationExternal"], True elif (msg_class, msg_id) in {(2, 1 * 16 + 5), (10, 9)}: - return ["ubloxGnss"] + return ["ubloxGnss"], True else: - return [] + return [], False CONFIGS = [ @@ -364,7 +364,7 @@ CONFIGS = [ init_callback=get_car_params, should_recv_callback=None, tolerance=NUMPY_TOLERANCE, - fake_pubsubmaster=True, + fake_pubsubmaster=False, ), ProcessConfig( proc_name="torqued", @@ -386,7 +386,7 @@ def replay_process(cfg, lr, fingerprint=None): if cfg.fake_pubsubmaster: return python_replay_process(cfg, lr, fingerprint) else: - return cpp_replay_process(cfg, lr, fingerprint) + return replay_process_with_sockets(cfg, lr, fingerprint) def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): @@ -401,8 +401,12 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): os.environ["NO_RADAR_SLEEP"] = "1" os.environ["REPLAY"] = "1" - os.environ['SKIP_FW_QUERY'] = "" - os.environ['FINGERPRINT'] = "" + os.environ["SKIP_FW_QUERY"] = "" + os.environ["FINGERPRINT"] = "" + + if lr is not None: + services = {m.which() for m in lr} + params.put_bool("UbloxAvailable", "ubloxGnss" in services) if lr is not None: services = {m.which() for m in lr} @@ -458,12 +462,6 @@ def python_replay_process(cfg, lr, fingerprint=None): all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) pub_msgs = [msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())] - # laikad needs decision between submaster ubloxGnss and qcomGnss, prio given to ubloxGnss - if cfg.proc_name == "laikad": - args = (*args, not any(m.which() == "ubloxGnss" for m in pub_msgs)) - service = "qcomGnss" if args[2] else "ubloxGnss" - pub_msgs = [m for m in pub_msgs if m.which() == service or m.which() == 'clocks'] - controlsState = None initialized = False for msg in lr: @@ -534,49 +532,53 @@ def python_replay_process(cfg, lr, fingerprint=None): return log_msgs -def cpp_replay_process(cfg, lr, fingerprint=None): - sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] # We get responses here +def replay_process_with_sockets(cfg, lr, fingerprint=None): + sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub] pm = messaging.PubMaster(cfg.pub_sub.keys()) all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) pub_msgs = [msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())] - log_msgs = [] # We need to fake SubMaster alive since we can't inject a fake clock setup_env(simulation=True, cfg=cfg, lr=lr) + if cfg.proc_name == "laikad": + ublox = Params().get_bool("UbloxAvailable") + keys = set(cfg.pub_sub.keys()) - ({"qcomGnss", } if ublox else {"ubloxGnss", }) + pub_msgs = [msg for msg in pub_msgs if msg.which() in keys] + managed_processes[cfg.proc_name].prepare() managed_processes[cfg.proc_name].start() + log_msgs = [] try: - with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}"): + # Wait for process to startup + with Timeout(10, error_msg=f"timed out waiting for process to start: {repr(cfg.proc_name)}"): while not any(pm.all_readers_updated(s) for s in cfg.pub_sub.keys()): time.sleep(0) - # Make sure all subscribers are connected - sockets = {s: messaging.sub_sock(s, timeout=2000) for s in sub_sockets} - for s in sub_sockets: - messaging.recv_one_or_none(sockets[s]) + # Make sure all subscribers are connected + sockets = {s: messaging.sub_sock(s, timeout=2000) for s in sub_sockets} + for s in sub_sockets: + messaging.recv_one_or_none(sockets[s]) - for i, msg in enumerate(pub_msgs): + # Do the replay + cnt = 0 + for msg in pub_msgs: + with Timeout(TIMEOUT, error_msg=f"timed out testing process {repr(cfg.proc_name)}, {cnt}/{len(pub_msgs)} msgs done"): pm.send(msg.which(), msg.as_builder()) + while not pm.all_readers_updated(msg.which()): + time.sleep(0) - resp_sockets = cfg.pub_sub[msg.which()] if cfg.should_recv_callback is None else cfg.should_recv_callback(msg) + resp_sockets = cfg.pub_sub[msg.which()] + if cfg.should_recv_callback is not None: + resp_sockets, _ = cfg.should_recv_callback(msg, None, None, None) for s in resp_sockets: - response = messaging.recv_one_retry(sockets[s]) - - if response is None: - print(f"Warning, no response received {i}") - else: - - response = response.as_builder() - response.logMonoTime = msg.logMonoTime - response = response.as_reader() - log_msgs.append(response) - - if not len(resp_sockets): # We only need to wait if we didn't already wait for a response - while not pm.all_readers_updated(msg.which()): - time.sleep(0) + m = messaging.recv_one_retry(sockets[s]) + m = m.as_builder() + m.logMonoTime = msg.logMonoTime + log_msgs.append(m.as_reader()) + cnt += 1 finally: managed_processes[cfg.proc_name].signal(signal.SIGKILL) managed_processes[cfg.proc_name].stop() diff --git a/selfdrive/test/process_replay/test_processes.py b/selfdrive/test/process_replay/test_processes.py index 07117c2e7f..a2dd938e2f 100755 --- a/selfdrive/test/process_replay/test_processes.py +++ b/selfdrive/test/process_replay/test_processes.py @@ -18,7 +18,7 @@ from tools.lib.logreader import LogReader source_segments = [ ("BODY", "937ccb7243511b65|2022-05-24--16-03-09--1"), # COMMA.BODY ("HYUNDAI", "02c45f73a2e5c6e9|2021-01-01--19-08-22--1"), # HYUNDAI.SONATA - ("HYUNDAI2", "d545129f3ca90f28|2022-11-07--20-43-08--3"), # HYUNDAI.KIA_EV6 + ("HYUNDAI2", "d545129f3ca90f28|2022-11-07--20-43-08--3"), # HYUNDAI.KIA_EV6 (+ QCOM GPS) ("TOYOTA", "0982d79ebb0de295|2021-01-04--17-13-21--13"), # TOYOTA.PRIUS (INDI) ("TOYOTA2", "0982d79ebb0de295|2021-01-03--20-03-36--6"), # TOYOTA.RAV4 (LQR) ("TOYOTA3", "f7d7e3538cda1a2a|2021-08-16--08-55-34--6"), # TOYOTA.COROLLA_TSS2 @@ -70,7 +70,7 @@ def run_test_process(data): res = None if not args.upload_only: lr = LogReader.from_bytes(lr_dat) - res, log_msgs = test_process(cfg, lr, ref_log_path, cur_log_fn, args.ignore_fields, args.ignore_msgs) + res, log_msgs = test_process(cfg, lr, segment, ref_log_path, cur_log_fn, args.ignore_fields, args.ignore_msgs) # save logs so we can upload when updating refs save_log(cur_log_fn, log_msgs) @@ -88,7 +88,7 @@ def get_log_data(segment): return (segment, f.read()) -def test_process(cfg, lr, ref_log_path, new_log_path, ignore_fields=None, ignore_msgs=None): +def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=None, ignore_msgs=None): if ignore_fields is None: ignore_fields = [] if ignore_msgs is None: @@ -96,7 +96,10 @@ def test_process(cfg, lr, ref_log_path, new_log_path, ignore_fields=None, ignore ref_log_msgs = list(LogReader(ref_log_path)) - log_msgs = replay_process(cfg, lr) + try: + log_msgs = replay_process(cfg, lr) + except Exception as e: + raise Exception("failed on segment: " + segment) from e # check to make sure openpilot is engaged in the route if cfg.proc_name == "controlsd": From a86730a2c601188c480285c45999efa00c3b3d4a Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Wed, 22 Mar 2023 07:55:06 +0800 Subject: [PATCH 1141/1179] camerad: remove deprecated focus parameters from FrameMetadata (#27638) --- system/camerad/cameras/camera_common.cc | 3 --- system/camerad/cameras/camera_common.h | 5 ----- 2 files changed, 8 deletions(-) diff --git a/system/camerad/cameras/camera_common.cc b/system/camerad/cameras/camera_common.cc index 7ee3738057..9ef5d89a4e 100644 --- a/system/camerad/cameras/camera_common.cc +++ b/system/camerad/cameras/camera_common.cc @@ -157,9 +157,6 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr framed.setHighConversionGain(frame_data.high_conversion_gain); framed.setMeasuredGreyFraction(frame_data.measured_grey_fraction); framed.setTargetGreyFraction(frame_data.target_grey_fraction); - framed.setLensPos(frame_data.lens_pos); - framed.setLensErr(frame_data.lens_err); - framed.setLensTruePos(frame_data.lens_true_pos); framed.setProcessingTime(frame_data.processing_time); const float ev = c->cur_ev[frame_data.frame_id % 3]; diff --git a/system/camerad/cameras/camera_common.h b/system/camerad/cameras/camera_common.h index 088b9f7939..07d1291a2a 100644 --- a/system/camerad/cameras/camera_common.h +++ b/system/camerad/cameras/camera_common.h @@ -66,11 +66,6 @@ typedef struct FrameMetadata { float measured_grey_fraction; float target_grey_fraction; - // Focus - unsigned int lens_pos; - float lens_err; - float lens_true_pos; - float processing_time; } FrameMetadata; From fc5a575ba3aef8fd4b3b7bac93bbc557c3bee11a Mon Sep 17 00:00:00 2001 From: Gijs Koning Date: Wed, 22 Mar 2023 01:07:19 +0100 Subject: [PATCH 1142/1179] laikad: use non-conflating socket for gnss msgs (#24888) * Use subsock * wait for one * wrong name * try cpp proc replay * fix recv pattern --------- Co-authored-by: Bruce Wayne Co-authored-by: Adeeb Shihadeh --- selfdrive/locationd/laikad.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index be272f1774..2e3ee1b7f0 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -116,7 +116,7 @@ class Laikad: nav_dict = {} try: ephem_cache = ephemeris_structs.EphemerisCache.from_bytes(cache_bytes) - glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] + glonass_navs = [GLONASSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.glonassEphemerides] gps_navs = [GPSEphemeris(data_struct, file_name=EPHEMERIS_CACHE) for data_struct in ephem_cache.gpsEphemerides] for e in sum([glonass_navs, gps_navs], []): if e.prn not in nav_dict: @@ -154,7 +154,7 @@ class Laikad: ephemeris_statuses.append(status) return ephemeris_statuses - + def get_lsq_fix(self, t, measurements): if self.last_fix_t is None or abs(self.last_fix_t - t) > 0: min_measurements = 5 if any(p.constellation_id == ConstellationId.GLONASS for p in measurements) else 4 @@ -262,7 +262,7 @@ class Laikad: out_msg = messaging.new_message("gnssMeasurements") out_msg.gnssMeasurements = { "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), + "ephemerisStatuses": self.create_ephem_statuses(), } if self.first_log_time is None: self.first_log_time = 1e-9 * gnss_mono_time @@ -310,7 +310,7 @@ class Laikad: "measTime": gnss_mono_time, "correctedMeasurements": meas_msgs, "timeToFirstFix": self.ttff, - "ephemerisStatuses" : self.create_ephem_statuses(), + "ephemerisStatuses": self.create_ephem_statuses(), } return out_msg @@ -425,17 +425,18 @@ def main(sm=None, pm=None): use_qcom = not Params().get_bool("UbloxAvailable", block=True) if use_qcom: - raw_gnss_socket = "qcomGnss" + raw_name = "qcomGnss" else: - raw_gnss_socket = "ubloxGnss" + raw_name = "ubloxGnss" + raw_gnss_sock = messaging.sub_sock(raw_name, conflate=False, timeout=1000) if sm is None: - sm = messaging.SubMaster([raw_gnss_socket, 'clocks']) + sm = messaging.SubMaster(['clocks',]) if pm is None: pm = messaging.PubMaster(['gnssMeasurements']) # disable until set as main gps source, to better analyze startup time - use_internet = False #"LAIKAD_NO_INTERNET" not in os.environ + use_internet = False # "LAIKAD_NO_INTERNET" not in os.environ replay = "REPLAY" in os.environ if replay or "CI" in os.environ: @@ -444,18 +445,17 @@ def main(sm=None, pm=None): laikad = Laikad(save_ephemeris=not replay, auto_fetch_navs=use_internet, use_qcom=use_qcom) while True: - sm.update() - - if sm.updated[raw_gnss_socket]: - gnss_msg = sm[raw_gnss_socket] - msg = laikad.process_gnss_msg(gnss_msg, sm.logMonoTime[raw_gnss_socket], replay) - pm.send('gnssMeasurements', msg) + for in_msg in messaging.drain_sock(raw_gnss_sock): + out_msg = laikad.process_gnss_msg(getattr(in_msg, raw_name), in_msg.logMonoTime, replay) + pm.send('gnssMeasurements', out_msg) + sm.update(0) if not laikad.got_first_gnss_msg and sm.updated['clocks']: clocks_msg = sm['clocks'] t = GPSTime.from_datetime(datetime.utcfromtimestamp(clocks_msg.wallTimeNanos * 1E-9)) if laikad.auto_fetch_navs: laikad.fetch_navs(t, block=replay) + if __name__ == "__main__": main() From be659c976c633876a58ee282550f9ccf52a1e504 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 21 Mar 2023 17:28:38 -0700 Subject: [PATCH 1143/1179] log current bootlog (#27645) * log current bootlog * rm path * mv that --------- Co-authored-by: Comma Device --- common/params.cc | 1 + system/loggerd/bootlog.cc | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/common/params.cc b/common/params.cc index e71f802d61..c084e03d38 100644 --- a/common/params.cc +++ b/common/params.cc @@ -98,6 +98,7 @@ std::unordered_map keys = { {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CompletedTrainingVersion", PERSISTENT}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"CurrentBootlog", PERSISTENT}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"DisablePowerDown", PERSISTENT}, diff --git a/system/loggerd/bootlog.cc b/system/loggerd/bootlog.cc index 4deb5b41f3..becd293c02 100644 --- a/system/loggerd/bootlog.cc +++ b/system/loggerd/bootlog.cc @@ -2,6 +2,7 @@ #include #include "cereal/messaging/messaging.h" +#include "common/params.h" #include "common/swaglog.h" #include "system/loggerd/logger.h" @@ -48,7 +49,8 @@ static kj::Array build_boot_log() { } int main(int argc, char** argv) { - const std::string path = LOG_ROOT + "/boot/" + logger_get_route_name(); + const std::string timestr = logger_get_route_name(); + const std::string path = LOG_ROOT + "/boot/" + timestr; LOGW("bootlog to %s", path.c_str()); // Open bootlog @@ -61,5 +63,8 @@ int main(int argc, char** argv) { // Write bootlog file.write(build_boot_log().asBytes()); + // Write out bootlog param to match routes with bootlog + Params().put("CurrentBootlog", timestr.c_str()); + return 0; } From 114b1e4a143acd1d20c2513035873c15228cef8c Mon Sep 17 00:00:00 2001 From: Lee Jong Mun <43285072+crwusiz@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:41:31 +0900 Subject: [PATCH 1144/1179] Kia: add missing Korean EV6 fwdCamera FW (#27641) * Kia: add missing Korean EV6 fwdCamera FW * Apply suggestions from code review * Update selfdrive/car/hyundai/values.py --------- Co-authored-by: Shane Smiskol --- selfdrive/car/hyundai/values.py | 1 + 1 file changed, 1 insertion(+) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 49e4ce033d..fc0469ffed 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -1553,6 +1553,7 @@ FW_VERSIONS = { b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823', + b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.06 99210-CV000 220328', ], }, CAR.IONIQ_5: { From 660b9e9718129d80afc0cb3d235fcefb22ba0fc6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 Mar 2023 19:16:05 -0700 Subject: [PATCH 1145/1179] Chrysler: add FW versions for 2019 Jeep Grand Cherokee (#27649) add FW versions for Jeep 2019 --- selfdrive/car/chrysler/values.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/selfdrive/car/chrysler/values.py b/selfdrive/car/chrysler/values.py index 984f92b5aa..8799f073c9 100644 --- a/selfdrive/car/chrysler/values.py +++ b/selfdrive/car/chrysler/values.py @@ -182,6 +182,30 @@ FW_QUERY_CONFIG = FwQueryConfig( ) FW_VERSIONS = { + CAR.JEEP_CHEROKEE_2019: { + (Ecu.combinationMeter, 0x742, None): [ + b'68402971AD', + ], + (Ecu.srs, 0x744, None): [ + b'68355363AB', + ], + (Ecu.abs, 0x747, None): [ + b'68408639AD', + ], + (Ecu.fwdRadar, 0x753, None): [ + b'68456722AC', + ], + (Ecu.eps, 0x75A, None): [ + b'68453431AA', + ], + (Ecu.engine, 0x7e0, None): [ + b'05035674AB ', + ], + (Ecu.transmission, 0x7e1, None): [ + b'05035707AA', + ], + }, + CAR.RAM_1500: { (Ecu.combinationMeter, 0x742, None): [ b'68294051AG', From aeb905a2bf64475d3d33b70da6e8a60e4b0985c9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 21 Mar 2023 19:21:11 -0700 Subject: [PATCH 1146/1179] Toyota LTA: allow no torque (#27646) * no torque * Update ref_commit * Update ref_commit --- selfdrive/car/toyota/toyotacan.py | 2 +- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/toyota/toyotacan.py b/selfdrive/car/toyota/toyotacan.py index 7e360cc4e1..a78b70608c 100644 --- a/selfdrive/car/toyota/toyotacan.py +++ b/selfdrive/car/toyota/toyotacan.py @@ -17,7 +17,7 @@ def create_lta_steer_command(packer, steer, steer_req, raw_cnt): "SETME_X1": 1, "SETME_X3": 3, "PERCENTAGE": 100, - "SETME_X64": 0x64, + "SETME_X64": 0, "ANGLE": 0, "STEER_ANGLE_CMD": steer, "STEER_REQUEST": steer_req, diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index cf19e9cb07..5f3db2fa88 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -30128f043985c8a793cdca2ad9ea1039c5086d72 \ No newline at end of file +ad3192c5ab1743bc1671c5c29816b360747cc3e0 From aefe636cc1b415f4ebf63f71ae9ae298461e37ac Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Mar 2023 00:23:51 -0700 Subject: [PATCH 1147/1179] GM: common longitudinal actuator delay (#27357) * common longitudinal actuator delay * comment * remove dup * move * clean up * Update ref_commit --- selfdrive/car/gm/interface.py | 4 +--- selfdrive/test/process_replay/ref_commit | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 602d7e31b6..f501c8c7dd 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -78,7 +78,6 @@ class CarInterface(CarInterfaceBase): ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling ret.vEgoStopping = 0.25 ret.vEgoStarting = 0.25 - ret.longitudinalActuatorDelayUpperBound = 0.5 if experimental_long: ret.pcmCruise = False @@ -113,6 +112,7 @@ class CarInterface(CarInterfaceBase): ret.steerLimitTimer = 0.4 ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz + ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking if candidate == CAR.VOLT: ret.mass = 1607. + STD_CARGO_KG @@ -148,7 +148,6 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 14.4 # end to end is 13.46 ret.centerToFront = ret.wheelbase * 0.4 ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia() - ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking elif candidate == CAR.BUICK_LACROSSE: ret.mass = 1712. + STD_CARGO_KG @@ -175,7 +174,6 @@ class CarInterface(CarInterfaceBase): ret.wheelbase = 2.95 # 116 inches in meters ret.steerRatio = 17.3 ret.centerToFront = ret.wheelbase * 0.5 - ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.ESCALADE_ESV: diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 5f3db2fa88..d20b7f5d7a 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -ad3192c5ab1743bc1671c5c29816b360747cc3e0 +a4ee2bfc9a9518a23a4f0fac4df124d1f12deb79 From dcbadc554d009c0e8d5c9a034cf748391c5015a8 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Mar 2023 01:27:23 +0800 Subject: [PATCH 1148/1179] cabana: sets the line width with floating point precision. (#27653) --- tools/cabana/chartswidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 09fcbf2ee2..c98ca3bc69 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -843,7 +843,7 @@ QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { series->setUseOpenGL(true); // Qt doesn't properly apply device pixel ratio in OpenGL mode QPen pen = series->pen(); - pen.setWidth(2.0 * qApp->devicePixelRatio()); + pen.setWidthF(2.0 * devicePixelRatioF()); series->setPen(pen); #endif chart()->addSeries(series); From 89d767da49a32bd78024ac224236f82bf2b2fff5 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 23 Mar 2023 02:02:34 +0800 Subject: [PATCH 1149/1179] cabana: improve find similar bits (#27651) * improve find similar bits * 2 precision --- tools/cabana/mainwin.cc | 6 +- tools/cabana/streams/abstractstream.h | 1 + tools/cabana/streams/replaystream.h | 1 + tools/cabana/tools/findsimilarbits.cc | 108 ++++++++++++++++---------- tools/cabana/tools/findsimilarbits.h | 5 +- 5 files changed, 77 insertions(+), 44 deletions(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index befbf270c6..b7cfd9dc2a 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -133,8 +133,10 @@ void MainWindow::createActions() { commands_act->setDefaultWidget(undo_view); commands_menu->addAction(commands_act); - QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); - tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); + if (!can->liveStreaming()) { + QMenu *tools_menu = menuBar()->addMenu(tr("&Tools")); + tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits); + } QMenu *help_menu = menuBar()->addMenu(tr("&Help")); help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents); diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h index 3c7bdd6132..8e19f69d2a 100644 --- a/tools/cabana/streams/abstractstream.h +++ b/tools/cabana/streams/abstractstream.h @@ -50,6 +50,7 @@ public: virtual void setSpeed(float speed) {} virtual bool isPaused() const { return false; } virtual void pause(bool pause) {} + virtual const std::vector *rawEvents() const { return nullptr; } const std::unordered_map> &events() const { return events_; } virtual const std::vector> getTimeline() { return {}; } void mergeEvents(std::vector::const_iterator first, std::vector::const_iterator last, bool append); diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h index 6fc61f7f36..10dc804716 100644 --- a/tools/cabana/streams/replaystream.h +++ b/tools/cabana/streams/replaystream.h @@ -23,6 +23,7 @@ public: inline void setSpeed(float speed) override { replay->setSpeed(speed); } inline bool isPaused() const override { return replay->isPaused(); } void pause(bool pause) override; + const std::vector *rawEvents() const override { return replay->events(); } inline const std::vector> getTimeline() override { return replay->getTimeline(); } private: diff --git a/tools/cabana/tools/findsimilarbits.cc b/tools/cabana/tools/findsimilarbits.cc index ffd0df0501..a44ac76059 100644 --- a/tools/cabana/tools/findsimilarbits.cc +++ b/tools/cabana/tools/findsimilarbits.cc @@ -1,5 +1,6 @@ #include "tools/cabana/tools/findsimilarbits.h" +#include #include #include #include @@ -16,20 +17,23 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi QVBoxLayout *main_layout = new QVBoxLayout(this); - QHBoxLayout *form_layout = new QHBoxLayout(); - bus_combo = new QComboBox(this); + QHBoxLayout *src_layout = new QHBoxLayout(); + src_bus_combo = new QComboBox(this); + find_bus_combo = new QComboBox(this); QSet bus_set; for (auto it = can->last_msgs.begin(); it != can->last_msgs.end(); ++it) { bus_set << it.key().source; } - for (uint8_t bus : bus_set) { - bus_combo->addItem(QString::number(bus), bus); + for (auto cb : {src_bus_combo, find_bus_combo}) { + for (uint8_t bus : bus_set) { + cb->addItem(QString::number(bus), bus); + } + cb->model()->sort(0); + cb->setCurrentIndex(0); } - bus_combo->model()->sort(0); - bus_combo->setCurrentIndex(0); msg_cb = new QComboBox(this); - // TODO: update when bus_combo changes + // TODO: update when src_bus_combo changes for (auto &[id, msg] : dbc()->getMessages(0)) { msg_cb->addItem(msg.name, id.address); } @@ -37,29 +41,44 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi msg_cb->setCurrentIndex(0); byte_idx_sb = new QSpinBox(this); + byte_idx_sb->setFixedWidth(50); byte_idx_sb->setRange(0, 63); bit_idx_sb = new QSpinBox(this); + bit_idx_sb->setFixedWidth(50); bit_idx_sb->setRange(0, 7); - form_layout->addWidget(new QLabel("Bus")); - form_layout->addWidget(bus_combo); - form_layout->addWidget(msg_cb); - form_layout->addWidget(new QLabel("Byte Index")); - form_layout->addWidget(byte_idx_sb); - form_layout->addWidget(new QLabel("Bit Index")); - form_layout->addWidget(bit_idx_sb); - + src_layout->addWidget(new QLabel(tr("Bus"))); + src_layout->addWidget(src_bus_combo); + src_layout->addWidget(msg_cb); + src_layout->addWidget(new QLabel(tr("Byte Index"))); + src_layout->addWidget(byte_idx_sb); + src_layout->addWidget(new QLabel(tr("Bit Index"))); + src_layout->addWidget(bit_idx_sb); + src_layout->addStretch(0); + QHBoxLayout *find_layout = new QHBoxLayout(); + find_layout->addWidget(new QLabel(tr("Bus"))); + find_layout->addWidget(find_bus_combo); + find_layout->addWidget(new QLabel(tr("Equal"))); + equal_combo = new QComboBox(this); + equal_combo->addItems({"Yes", "No"}); + find_layout->addWidget(equal_combo); min_msgs = new QLineEdit(this); min_msgs->setValidator(new QIntValidator(this)); min_msgs->setText("100"); - form_layout->addWidget(new QLabel("Min msg count")); - form_layout->addWidget(min_msgs); + find_layout->addWidget(new QLabel(tr("Min msg count"))); + find_layout->addWidget(min_msgs); search_btn = new QPushButton(tr("&Find"), this); - form_layout->addWidget(search_btn); - form_layout->addStretch(1); - main_layout->addLayout(form_layout); + find_layout->addWidget(search_btn); + find_layout->addStretch(0); + + QGridLayout *grid_layout = new QGridLayout(); + grid_layout->addWidget(new QLabel("Find From:"), 0, 0); + grid_layout->addLayout(src_layout, 0, 1); + grid_layout->addWidget(new QLabel("Find In:"), 1, 0); + grid_layout->addLayout(find_layout, 1, 1); + main_layout->addLayout(grid_layout); table = new QTableWidget(this); table->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -70,10 +89,9 @@ FindSimilarBitsDlg::FindSimilarBitsDlg(QWidget *parent) : QDialog(parent, Qt::Wi setMinimumSize({700, 500}); QObject::connect(search_btn, &QPushButton::clicked, this, &FindSimilarBitsDlg::find); - QObject::connect(table, &QTableWidget::doubleClicked, [this](const QModelIndex &index) { if (index.isValid()) { - MessageId msg_id = {.source = (uint8_t)bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; + MessageId msg_id = {.source = (uint8_t)find_bus_combo->currentData().toUInt(), .address = table->item(index.row(), 0)->text().toUInt(0, 16)}; emit openMessage(msg_id); } }); @@ -83,7 +101,8 @@ void FindSimilarBitsDlg::find() { search_btn->setEnabled(false); table->clear(); uint32_t selected_address = msg_cb->currentData().toUInt(); - auto msg_mismatched = calcBits(bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), min_msgs->text().toInt()); + auto msg_mismatched = calcBits(src_bus_combo->currentText().toUInt(), selected_address, byte_idx_sb->value(), bit_idx_sb->value(), + find_bus_combo->currentText().toUInt(), equal_combo->currentIndex() == 0, min_msgs->text().toInt()); table->setRowCount(msg_mismatched.size()); table->setColumnCount(6); table->setHorizontalHeaderLabels({"address", "byte idx", "bit idx", "mismatches", "total msgs", "% mismatched"}); @@ -94,32 +113,41 @@ void FindSimilarBitsDlg::find() { table->setItem(i, 2, new QTableWidgetItem(QString::number(m.bit_idx))); table->setItem(i, 3, new QTableWidgetItem(QString::number(m.mismatches))); table->setItem(i, 4, new QTableWidgetItem(QString::number(m.total))); - table->setItem(i, 5, new QTableWidgetItem(QString::number(m.perc))); + table->setItem(i, 5, new QTableWidgetItem(QString::number(m.perc, 'f', 2))); } search_btn->setEnabled(true); } -QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt) { +QList FindSimilarBitsDlg::calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, + int bit_idx, uint8_t find_bus, bool equal, int min_msgs_cnt) { QHash> mismatches; QHash msg_count; + auto events = can->rawEvents(); int bit_to_find = -1; - for (const auto &[id, msg] : can->events()) { - if (id.source == bus) { - for (const auto &c : msg) { - if (id.address == selected_address && c.size > byte_idx) { - bit_to_find = ((c.dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + for (auto e : *events) { + if (e->which == cereal::Event::Which::CAN) { + for (const auto &c : e->event.getCan()) { + uint8_t src = c.getSrc(); + uint32_t address = c.getAddress(); + const auto dat = c.getDat(); + if (src == bus) { + if (address == selected_address && dat.size() > byte_idx) { + bit_to_find = ((dat[byte_idx] >> (7 - bit_idx)) & 1) != 0; + } } - ++msg_count[id.address]; - if (bit_to_find == -1) continue; + if (src == find_bus) { + ++msg_count[address]; + if (bit_to_find == -1) continue; - auto &mismatched = mismatches[id.address]; - if (mismatched.size() < c.size * 8) { - mismatched.resize(c.size * 8); - } - for (int i = 0; i < c.size; ++i) { - for (int j = 0; j < 8; ++j) { - int bit = ((c.dat[i] >> (7 - j)) & 1) != 0; - mismatched[i * 8 + j] += (bit != bit_to_find); + auto &mismatched = mismatches[address]; + if (mismatched.size() < dat.size() * 8) { + mismatched.resize(dat.size() * 8); + } + for (int i = 0; i < dat.size(); ++i) { + for (int j = 0; j < 8; ++j) { + int bit = ((dat[i] >> (7 - j)) & 1) != 0; + mismatched[i * 8 + j] += equal ? (bit != bit_to_find) : (bit == bit_to_find); + } } } } diff --git a/tools/cabana/tools/findsimilarbits.h b/tools/cabana/tools/findsimilarbits.h index 53d7806a8f..a40e2cd8df 100644 --- a/tools/cabana/tools/findsimilarbits.h +++ b/tools/cabana/tools/findsimilarbits.h @@ -22,11 +22,12 @@ private: uint32_t address, byte_idx, bit_idx, mismatches, total; float perc; }; - QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, int min_msgs_cnt); + QList calcBits(uint8_t bus, uint32_t selected_address, int byte_idx, int bit_idx, uint8_t find_bus, + bool equal, int min_msgs_cnt); void find(); QTableWidget *table; - QComboBox *bus_combo, *msg_cb; + QComboBox *src_bus_combo, *find_bus_combo, *msg_cb, *equal_combo; QSpinBox *byte_idx_sb, *bit_idx_sb; QPushButton *search_btn; QLineEdit *min_msgs; From 8b8c4d810f84ae980f0a99c48e7fccc5888dc091 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Mar 2023 13:37:09 -0700 Subject: [PATCH 1150/1179] test lateral limits: remove Konas from blacklist (#27424) * remove konas from blacklist * update measured accel * remove * no longer needed --- selfdrive/car/tests/test_lateral_limits.py | 12 ------------ selfdrive/car/torque_data/params.yaml | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/selfdrive/car/tests/test_lateral_limits.py b/selfdrive/car/tests/test_lateral_limits.py index 3efdd7404e..d3e4de1798 100755 --- a/selfdrive/car/tests/test_lateral_limits.py +++ b/selfdrive/car/tests/test_lateral_limits.py @@ -10,7 +10,6 @@ from common.realtime import DT_CTRL from selfdrive.car.car_helpers import interfaces from selfdrive.car.fingerprints import all_known_cars from selfdrive.car.interfaces import get_torque_params -from selfdrive.car.hyundai.values import CAR as HYUNDAI CAR_MODELS = all_known_cars() @@ -22,14 +21,6 @@ MAX_LAT_ACCEL = 3.0 # m/s^2 # jerk is measured over half a second JERK_MEAS_FRAMES = 0.5 / DT_CTRL -# TODO: update the max measured lateral accel for these cars -ABOVE_LIMITS_CARS = [ - HYUNDAI.KONA_EV, - HYUNDAI.KONA_HEV, - HYUNDAI.KONA, - HYUNDAI.KONA_EV_2022, -] - car_model_jerks: DefaultDict[str, Dict[str, float]] = defaultdict(dict) @@ -52,9 +43,6 @@ class TestLateralLimits(unittest.TestCase): if CP.notCar: raise unittest.SkipTest - if CP.carFingerprint in ABOVE_LIMITS_CARS: - raise unittest.SkipTest - CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams cls.control_params = CarControllerParams(CP) cls.torque_params = get_torque_params(cls.car_model) diff --git a/selfdrive/car/torque_data/params.yaml b/selfdrive/car/torque_data/params.yaml index 6f8cfe0ce6..cb423e1d87 100644 --- a/selfdrive/car/torque_data/params.yaml +++ b/selfdrive/car/torque_data/params.yaml @@ -30,7 +30,7 @@ HYUNDAI IONIQ 5 2022: [3.172929, 2.713050, 0.096019] HYUNDAI IONIQ ELECTRIC LIMITED 2019: [1.7662975472852054, 1.613755614526594, 0.17087579756306276] HYUNDAI IONIQ PHEV 2020: [3.2928700076638537, 2.1193482926455656, 0.12463700961468778] HYUNDAI IONIQ PLUG-IN HYBRID 2019: [2.970807902012267, 1.6312321830002083, 0.1088964990357482] -HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 3.2961956260770484, 0.12359762054065548] +HYUNDAI KONA ELECTRIC 2019: [3.078814714619148, 2.307336938253934, 0.12359762054065548] HYUNDAI PALISADE 2020: [2.544642494803999, 1.8721703683337008, 0.1301424599248651] HYUNDAI SANTA FE 2019: [3.0787027729757632, 2.6173437483495565, 0.1207019341823945] HYUNDAI SANTA FE HYBRID 2022: [3.501877602644835, 2.729064118456137, 0.10384068104538963] From 25a7f87b424b2a4fd116aff5a5a83ecd1fd87f07 Mon Sep 17 00:00:00 2001 From: ZwX1616 Date: Wed, 22 Mar 2023 13:44:29 -0700 Subject: [PATCH 1151/1179] camerad: reduce daytime HDR blur (#27644) * 60hz * be dynamic * cast --------- Co-authored-by: Comma Device --- system/camerad/cameras/camera_qcom2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/camerad/cameras/camera_qcom2.cc b/system/camerad/cameras/camera_qcom2.cc index 92b3bde413..94116b11cd 100644 --- a/system/camerad/cameras/camera_qcom2.cc +++ b/system/camerad/cameras/camera_qcom2.cc @@ -1175,7 +1175,7 @@ void CameraState::set_camera_exposure(float grey_frac) { // t_HCG&t_LCG + t_VS on LPD, t_SPD on SPD uint32_t hcg_time = exposure_time; uint32_t lcg_time = hcg_time; - uint32_t spd_time = exposure_time_max + VS_TIME_MAX_OX03C10; + uint32_t spd_time = std::min(std::max((uint32_t)exposure_time, (exposure_time_max + VS_TIME_MAX_OX03C10) / 3), exposure_time_max + VS_TIME_MAX_OX03C10); uint32_t vs_time = std::min(std::max((uint32_t)exposure_time / 40, VS_TIME_MIN_OX03C10), VS_TIME_MAX_OX03C10); uint32_t real_gain = ox03c10_analog_gains_reg[new_exp_g]; From e05e7850e176c4a229608c3972c665b11510d9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Wed, 22 Mar 2023 19:10:19 -0700 Subject: [PATCH 1152/1179] Laika cleaner flow (#27633) * laika flow * test fixes * unexpected type * unexpected type * explicit type * ref commit * back to prev val * ref 2 --- selfdrive/locationd/laikad.py | 72 ++++++++++-------------- selfdrive/locationd/test/test_laikad.py | 15 +++-- selfdrive/test/process_replay/ref_commit | 2 +- 3 files changed, 41 insertions(+), 48 deletions(-) diff --git a/selfdrive/locationd/laikad.py b/selfdrive/locationd/laikad.py index 2e3ee1b7f0..59176c586b 100755 --- a/selfdrive/locationd/laikad.py +++ b/selfdrive/locationd/laikad.py @@ -7,7 +7,7 @@ from collections import defaultdict from concurrent.futures import Future, ProcessPoolExecutor from datetime import datetime from enum import IntEnum -from typing import List, Optional +from typing import List, Optional, Dict, Any import numpy as np @@ -241,12 +241,14 @@ class Laikad: new_meas = [m for m in new_meas if 1e7 < m.observables['C1C'] < 3e7] processed_measurements = process_measurements(new_meas, self.astro_dog) if self.last_fix_pos is not None: - corrected_measurements = correct_measurements(processed_measurements, self.last_fix_pos, self.astro_dog) - instant_fix = self.get_lsq_fix(t, corrected_measurements) - #instant_fix = self.get_lsq_fix(t, processed_measurements) + est_pos = self.last_fix_pos else: - corrected_measurements = [] - instant_fix = self.get_lsq_fix(t, processed_measurements) + est_pos = self.gnss_kf.x[GStates.ECEF_POS].tolist() + corrected_measurements = correct_measurements(processed_measurements, est_pos, self.astro_dog) + return corrected_measurements + + def calc_fix(self, t, measurements): + instant_fix = self.get_lsq_fix(t, measurements) if instant_fix is None: return None else: @@ -254,64 +256,52 @@ class Laikad: self.last_fix_t = t self.last_fix_pos = position_estimate self.lat_fix_pos_std = position_std - if (t*1e9) % 10 == 0: - cloudlog.debug(f"Measurements Incoming/Processed/Corrected: {len(new_meas), len(processed_measurements), len(corrected_measurements)}") - return position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, processed_measurements + return position_estimate, position_std, velocity_estimate, velocity_std def process_gnss_msg(self, gnss_msg, gnss_mono_time: int, block=False): out_msg = messaging.new_message("gnssMeasurements") - out_msg.gnssMeasurements = { - "timeToFirstFix": self.ttff, - "ephemerisStatuses": self.create_ephem_statuses(), - } + t = gnss_mono_time * 1e-9 + msg_dict: Dict[str, Any] = {"measTime": gnss_mono_time} if self.first_log_time is None: self.first_log_time = 1e-9 * gnss_mono_time if self.is_ephemeris(gnss_msg): self.read_ephemeris(gnss_msg) - return out_msg elif self.is_good_report(gnss_msg): week, tow, new_meas = self.read_report(gnss_msg) self.gps_week = week - if len(new_meas) == 0: - return out_msg - - t = gnss_mono_time * 1e-9 if week > 0: self.got_first_gnss_msg = True latest_msg_t = GPSTime(week, tow) if self.auto_fetch_navs: self.fetch_navs(latest_msg_t, block) - output = self.process_report(new_meas, t) - if output is None: - return out_msg - if self.ttff <= 0: - self.ttff = max(1e-3, t - self.first_log_time) - position_estimate, position_std, velocity_estimate, velocity_std, corrected_measurements, _ = output + corrected_measurements = self.process_report(new_meas, t) + msg_dict['correctedMeasurements'] = [create_measurement_msg(m) for m in corrected_measurements] - self.update_localizer(position_estimate, t, corrected_measurements) - meas_msgs = [create_measurement_msg(m) for m in corrected_measurements] + fix = self.calc_fix(t, corrected_measurements) measurement_msg = log.LiveLocationKalman.Measurement.new_message + if fix is not None: + position_estimate, position_std, velocity_estimate, velocity_std = fix + if self.ttff <= 0: + self.ttff = max(1e-3, t - self.first_log_time) + msg_dict["positionECEF"] = measurement_msg(value=position_estimate, std=position_std.tolist(), valid=bool(self.last_fix_t == t)) + msg_dict["velocityECEF"] = measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)) + self.update_localizer(self.last_fix_pos, t, corrected_measurements) P_diag = self.gnss_kf.P.diagonal() kf_valid = all(self.kf_valid(t)) - out_msg.gnssMeasurements = { - "gpsWeek": week, - "gpsTimeOfWeek": tow, - "kalmanPositionECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), + msg_dict["kalmanPositionECEF"] = measurement_msg(value=self.gnss_kf.x[GStates.ECEF_POS].tolist(), std=np.sqrt(P_diag[GStates.ECEF_POS]).tolist(), - valid=kf_valid), - "kalmanVelocityECEF": measurement_msg(value=self.gnss_kf.x[GStates.ECEF_VELOCITY].tolist(), + valid=kf_valid) + msg_dict["kalmanVelocityECEF"] = measurement_msg(value=self.gnss_kf.x[GStates.ECEF_VELOCITY].tolist(), std=np.sqrt(P_diag[GStates.ECEF_VELOCITY]).tolist(), - valid=kf_valid), - "positionECEF": measurement_msg(value=position_estimate, std=position_std.tolist(), valid=bool(self.last_fix_t == t)), - "velocityECEF": measurement_msg(value=velocity_estimate, std=velocity_std.tolist(), valid=bool(self.last_fix_t == t)), + valid=kf_valid) - "measTime": gnss_mono_time, - "correctedMeasurements": meas_msgs, - "timeToFirstFix": self.ttff, - "ephemerisStatuses": self.create_ephem_statuses(), - } + msg_dict['gpsWeek'] = self.last_report_time.week + msg_dict['gpsTimeOfWeek'] = self.last_report_time.tow + msg_dict['timeToFirstFix'] = self.ttff + msg_dict['ephemerisStatuses'] = self.create_ephem_statuses() + out_msg.gnssMeasurements = msg_dict return out_msg def update_localizer(self, est_pos, t: float, measurements: List[GNSSMeasurement]): @@ -324,7 +314,7 @@ class Laikad: cloudlog.error("Time gap of over 10s detected, gnss kalman reset") elif not valid[2]: cloudlog.error("Gnss kalman filter state is nan") - if len(est_pos) > 0: + if est_pos is not None and len(est_pos) > 0: cloudlog.info(f"Reset kalman filter with {est_pos}") self.init_gnss_localizer(est_pos) else: diff --git a/selfdrive/locationd/test/test_laikad.py b/selfdrive/locationd/test/test_laikad.py index 265db50c6d..e184dc3ec4 100755 --- a/selfdrive/locationd/test/test_laikad.py +++ b/selfdrive/locationd/test/test_laikad.py @@ -180,7 +180,7 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.ULTRA_RAPID_ORBIT) correct_msgs = verify_messages(self.logs, laikad) - correct_msgs_expected = 559 + correct_msgs_expected = 560 self.assertEqual(correct_msgs_expected, len(correct_msgs)) self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @@ -201,9 +201,11 @@ class TestLaikad(unittest.TestCase): laikad = Laikad(auto_update=True, valid_ephem_types=EphemerisType.NAV, use_qcom=use_qcom) # Disable fetch_orbits to test NAV only correct_msgs = verify_messages(logs, laikad) - correct_msgs_expected = 42 if use_qcom else 559 + correct_msgs_expected = 44 if use_qcom else 560 + valid_fix_expected = 43 if use_qcom else 560 + self.assertEqual(correct_msgs_expected, len(correct_msgs)) - self.assertEqual(correct_msgs_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + self.assertEqual(valid_fix_expected, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) @mock.patch('laika.downloader.download_and_cache_file') def test_laika_offline(self, downloader_mock): @@ -216,8 +218,9 @@ class TestLaikad(unittest.TestCase): downloader_mock.side_effect = DownloadFailed laikad = Laikad(auto_update=False) correct_msgs = verify_messages(self.logs, laikad) - self.assertEqual(375, len(correct_msgs)) - self.assertEqual(375, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) + expected_msgs = 376 + self.assertEqual(expected_msgs, len(correct_msgs)) + self.assertEqual(expected_msgs, len([m for m in correct_msgs if m.gnssMeasurements.positionECEF.valid])) def test_laika_get_orbits(self): laikad = Laikad(auto_update=False) @@ -325,7 +328,7 @@ class TestLaikad(unittest.TestCase): gm = msg.gnssMeasurements if len(gm.correctedMeasurements) != 0 and gm.positionECEF.valid: cnt += 1 - self.assertEqual(cnt, 559) + self.assertEqual(cnt, 560) def dict_has_values(self, dct): self.assertGreater(len(dct), 0) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index d20b7f5d7a..556781738d 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -a4ee2bfc9a9518a23a4f0fac4df124d1f12deb79 +50f1e873095fe2462d2aadb9c401bda76759c01c From 26541d9e7aa30b1705873e8360b806b52712fde7 Mon Sep 17 00:00:00 2001 From: YassineYousfi Date: Wed, 22 Mar 2023 20:19:46 -0700 Subject: [PATCH 1153/1179] new model: trained on new dataset (#27637) * df733db3-fad2-4485-abe9-59a6a47f2233/449 946c0f55-247d-4790-a407-c07e4364b340/700 * fix reducel2 df733db3-fad2-4485-abe9-59a6a47f2233/449 946c0f55-247d-4790-a407-c07e4364b340/700 * update ref commit --- 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 a483fa4db4..13759c62f8 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:736ddc08497d7596bae4d9515a8efb996676be80e67a6d34d632bb8af2ed3fa9 -size 45962515 +oid sha256:5121deb0d5c683b0fbee4c1cad7bc625953bf127b1383fb7599a6b644efd0aea +size 46011200 diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit index ad09668a46..bd026f5710 100644 --- a/selfdrive/test/process_replay/model_replay_ref_commit +++ b/selfdrive/test/process_replay/model_replay_ref_commit @@ -1 +1 @@ -ab64afd1abd1059c14f50c67b51e5ef89029f216 +82db08d52b155336e9a1dadd11485d5acdf2eba0 From 727a94cc7837e8556a243170111294440722a233 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 22 Mar 2023 21:58:04 -0700 Subject: [PATCH 1154/1179] fw_versions: cleanup common types (#27658) * use common type * use it in fw_versions * add typing to queries --- selfdrive/car/ecu_addrs.py | 12 +++++++----- selfdrive/car/fw_versions.py | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py index e5d550fac8..86bae91b06 100755 --- a/selfdrive/car/ecu_addrs.py +++ b/selfdrive/car/ecu_addrs.py @@ -9,6 +9,8 @@ from selfdrive.car import make_can_msg from selfdrive.boardd.boardd import can_list_to_can_capnp from system.swaglog import cloudlog +EcuAddrBusType = Tuple[int, Optional[int], int] + def make_tester_present_msg(addr, bus, subaddr=None): dat = [0x02, SERVICE_TYPE.TESTER_PRESENT, 0x0] @@ -33,16 +35,16 @@ def is_tester_present_response(msg: capnp.lib.capnp._DynamicStructReader, subadd return False -def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> Set[Tuple[int, Optional[int], int]]: +def get_all_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, bus: int, timeout: float = 1, debug: bool = True) -> Set[EcuAddrBusType]: addr_list = [0x700 + i for i in range(256)] + [0x18da00f1 + (i << 8) for i in range(256)] - queries: Set[Tuple[int, Optional[int], int]] = {(addr, None, bus) for addr in addr_list} + queries: Set[EcuAddrBusType] = {(addr, None, bus) for addr in addr_list} responses = queries return get_ecu_addrs(logcan, sendcan, queries, responses, timeout=timeout, debug=debug) -def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, queries: Set[Tuple[int, Optional[int], int]], - responses: Set[Tuple[int, Optional[int], int]], timeout: float = 1, debug: bool = False) -> Set[Tuple[int, Optional[int], int]]: - ecu_responses: Set[Tuple[int, Optional[int], int]] = set() # set((addr, subaddr, bus),) +def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, queries: Set[EcuAddrBusType], + responses: Set[EcuAddrBusType], timeout: float = 1, debug: bool = False) -> Set[EcuAddrBusType]: + ecu_responses: Set[EcuAddrBusType] = set() # set((addr, subaddr, bus),) try: msgs = [make_tester_present_msg(addr, bus, subaddr) for addr, subaddr, bus in queries] diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 8092ac0b76..344d734038 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 from collections import defaultdict -from typing import Any, Optional, Set, Tuple +from typing import Any, List, Optional, Set from tqdm import tqdm import panda.python.uds as uds from cereal import car from common.params import Params -from selfdrive.car.ecu_addrs import get_ecu_addrs +from selfdrive.car.ecu_addrs import EcuAddrBusType, get_ecu_addrs from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery @@ -146,9 +146,9 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): return True, set() -def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[Tuple[int, Optional[int], int]]: - queries = list() - parallel_queries = list() +def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: + queries: List[List[EcuAddrBusType]] = list() + parallel_queries: List[EcuAddrBusType] = list() responses = set() for brand, r in REQUESTS: From 42449b482d46565242341ca2d7e3a7255572f6a2 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 00:14:31 -0700 Subject: [PATCH 1155/1179] boardd: ability to switch between ELM safety params (#27656) * indecisive * rename to generic FW query * remove code and update comment * we need this to start off, unless we set multiplexing immediately * draft * draft 2 * try that * can't do this either, boardd might read Enabled after removing, but before setting new Request param * this should work * use one less param * fix params * match behavior (set all pandas to safety param of 1, disabling multiplexing for fingerprinting * clean up (some tests may temp break) * fix param name and sort * time it * yes it does matter * add to hyundai's bus 5 query * remove hyundai for now * this should work * clean up * clean up * flip argument around, clean up * fix test_startup * some clean up * rm line * comment makes more sense * required typing * clean up common type * comments * Update selfdrive/car/car_helpers.py * line * whoops, need to set before vin! * fix debug * annoying * more debugging * bug fix (needs both keys always) * debuGG debuGG * Revert "debuGG" This reverts commit 55b2f429324c0b92d5cfb2cabf8b20db1e166248. * Revert "more debugging" This reverts commit 02934c3403ad5270f03093508b704c151d1ccb2a. * Revert "annoying" This reverts commit 8b4e5e09989f9a0217e3ec1c0ba68735929b7366. * clean that up * bumpback * bumpback * every second write param * flip * stuff * move up? * fix timing out in CI * rm --- common/params.cc | 5 +- selfdrive/boardd/boardd.cc | 29 +++++----- .../boardd/tests/test_boardd_loopback.py | 2 +- selfdrive/car/car_helpers.py | 13 +++-- selfdrive/car/fw_query_definitions.py | 4 +- selfdrive/car/fw_versions.py | 57 +++++++++---------- selfdrive/car/honda/values.py | 2 +- selfdrive/controls/tests/test_startup.py | 5 +- .../test/process_replay/process_replay.py | 1 - 9 files changed, 62 insertions(+), 56 deletions(-) diff --git a/common/params.cc b/common/params.cc index c084e03d38..428830a112 100644 --- a/common/params.cc +++ b/common/params.cc @@ -111,7 +111,7 @@ std::unordered_map keys = { {"DoReboot", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START}, - {"FirmwareObdQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"ForcePowerDown", CLEAR_ON_MANAGER_START}, {"GitBranch", PERSISTENT}, {"GitCommit", PERSISTENT}, @@ -155,7 +155,8 @@ std::unordered_map keys = { {"NavSettingTime24h", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT}, {"NavdRender", PERSISTENT}, - {"ObdMultiplexingDisabled", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, + {"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"OpenpilotEnabledToggle", PERSISTENT}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"PandaSignatures", CLEAR_ON_MANAGER_START}, diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 5d885c2c79..3dc54b856a 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -113,32 +113,35 @@ bool safety_setter_thread(std::vector pandas) { return false; } - // set to ELM327 for fingerprinting + // initialize to ELM327 without OBD multiplexing for fingerprinting + bool obd_multiplexing_enabled = false; for (int i = 0; i < pandas.size(); i++) { - const uint16_t safety_param = (i > 0) ? 1U : 0U; - pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); + pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); } - // wait for FW query at OBD port to finish + // openpilot can switch between multiplexing modes for different FW queries while (true) { if (do_exit || !check_all_connected(pandas) || !ignition) { return false; } - if (p.getBool("FirmwareObdQueryDone")) { - LOGW("finished FW query at OBD port"); + bool obd_multiplexing_requested = p.getBool("ObdMultiplexingEnabled"); + if (obd_multiplexing_requested != obd_multiplexing_enabled) { + const uint16_t safety_param = obd_multiplexing_requested ? 0U : 1U; + for (int i = 0; i < pandas.size(); i++) { + pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); + } + obd_multiplexing_enabled = obd_multiplexing_requested; + p.putBool("ObdMultiplexingChanged", true); + } + + if (p.getBool("FirmwareQueryDone")) { + LOGW("finished FW query"); break; } util::sleep_for(20); } - // set to ELM327 to finish fingerprinting and for potential ECU knockouts - for (Panda *panda : pandas) { - panda->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U); - } - - p.putBool("ObdMultiplexingDisabled", true); - std::string params; LOGW("waiting for params to set safety model"); while (true) { diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index b8ebbd88a3..d614f0b126 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -51,7 +51,7 @@ class TestBoardd(unittest.TestCase): cp.safetyConfigs = [safety_config]*num_pandas params = Params() - params.put_bool("FirmwareObdQueryDone", True) + params.put_bool("FirmwareQueryDone", True) params.put_bool("ControlsReady", True) params.put("CarParams", cp.to_bytes()) diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index dc82f56197..6a131c77de 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -8,7 +8,7 @@ from system.version import is_comma_remote, is_tested_branch from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars from selfdrive.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN -from selfdrive.car.fw_versions import disable_obd_multiplexing, get_fw_versions_ordered, match_fw_to_car, get_present_ecus +from selfdrive.car.fw_versions import get_fw_versions_ordered, get_present_ecus, match_fw_to_car, set_obd_multiplexing from system.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.car import gen_empty_fingerprint @@ -80,12 +80,13 @@ 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() + params = Params() if not skip_fw_query: # Vin query only reliably works through OBDII bus = 1 - cached_params = Params().get("CarParamsCache") + cached_params = params.get("CarParamsCache") if cached_params is not None: cached_params = car.CarParams.from_bytes(cached_params) if cached_params.carName == "mock": @@ -98,6 +99,7 @@ def fingerprint(logcan, sendcan, num_pandas): cached = True else: cloudlog.warning("Getting VIN & FW versions") + set_obd_multiplexing(params, True) vin_rx_addr, vin = get_vin(logcan, sendcan, bus) ecu_rx_addrs = get_present_ecus(logcan, sendcan, num_pandas=num_pandas) car_fw = get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, num_pandas=num_pandas) @@ -113,10 +115,11 @@ def fingerprint(logcan, sendcan, num_pandas): cloudlog.event("Malformed VIN", vin=vin, error=True) vin = VIN_UNKNOWN cloudlog.warning("VIN %s", vin) - - params = Params() params.put("CarVin", vin) - disable_obd_multiplexing(params) + + # disable OBD multiplexing for potential ECU knockouts + set_obd_multiplexing(params, False) + params.put_bool("FirmwareQueryDone", True) finger = gen_empty_fingerprint() candidate_cars = {i: all_legacy_fingerprint_cars() for i in [0, 1]} # attempt fingerprint on both bus 0 and 1 diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index dd3b19f6de..4c2baa58d7 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -59,8 +59,8 @@ class Request: bus: int = 1 # FW responses from these queries will not be used for fingerprinting logging: bool = False - # These requests are done once OBD multiplexing is disabled, after all others - non_obd: bool = False + # boardd toggles OBD multiplexing on/off as needed + obd_multiplexing: bool = True @dataclass diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 344d734038..51bf99ebf4 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 from collections import defaultdict -from typing import Any, List, Optional, Set +from typing import Any, Dict, List, Set from tqdm import tqdm import panda.python.uds as uds @@ -147,8 +147,10 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: - queries: List[List[EcuAddrBusType]] = list() - parallel_queries: List[EcuAddrBusType] = list() + params = Params() + # queries are split by OBD multiplexing mode + queries: Dict[bool, List[List[EcuAddrBusType]]] = {True: [], False: []} + parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []} responses = set() for brand, r in REQUESTS: @@ -163,21 +165,24 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: a = (addr, sub_addr, r.bus) # Build set of queries if sub_addr is None: - if a not in parallel_queries: - parallel_queries.append(a) + if a not in parallel_queries[r.obd_multiplexing]: + parallel_queries[r.obd_multiplexing].append(a) else: # subaddresses must be queried one by one - if [a] not in queries: - queries.append([a]) + if [a] not in queries[r.obd_multiplexing]: + queries[r.obd_multiplexing].append([a]) # Build set of expected responses to filter response_addr = uds.get_rx_addr_for_tx_addr(addr, r.rx_offset) responses.add((response_addr, sub_addr, r.bus)) - queries.insert(0, parallel_queries) + for obd_multiplexing in queries: + queries[obd_multiplexing].insert(0, parallel_queries[obd_multiplexing]) ecu_responses = set() - for query in queries: - ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) + for obd_multiplexing in queries: + set_obd_multiplexing(params, obd_multiplexing) + for query in queries[obd_multiplexing]: + ecu_responses.update(get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) return ecu_responses @@ -198,13 +203,13 @@ def get_brand_ecu_matches(ecu_rx_addrs): return brand_matches -def disable_obd_multiplexing(params): - if not params.get_bool("ObdMultiplexingDisabled"): - params.put_bool("FirmwareObdQueryDone", True) - - cloudlog.warning("Waiting for OBD multiplexing to be disabled") - params.get_bool("ObdMultiplexingDisabled", block=True) - cloudlog.warning("OBD multiplexing disabled") +def set_obd_multiplexing(params: Params, obd_multiplexing: bool): + if params.get_bool("ObdMultiplexingEnabled") != obd_multiplexing: + cloudlog.warning(f"Setting OBD multiplexing to {obd_multiplexing}") + params.remove("ObdMultiplexingChanged") + params.put_bool("ObdMultiplexingEnabled", obd_multiplexing) + params.get_bool("ObdMultiplexingChanged", block=True) + cloudlog.warning("OBD multiplexing set successfully") def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pandas=1, debug=False, progress=False): @@ -212,7 +217,6 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand all_car_fw = [] brand_matches = get_brand_ecu_matches(ecu_rx_addrs) - matched_brand: Optional[str] = None 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, num_pandas=num_pandas, debug=debug, progress=progress) @@ -220,21 +224,14 @@ def get_fw_versions_ordered(logcan, sendcan, ecu_rx_addrs, timeout=0.1, num_pand # Try to match using FW returned from this brand only matches = match_fw_to_car_exact(build_fw_dict(car_fw)) if len(matches) == 1: - matched_brand = brand break - disable_obd_multiplexing(Params()) - - # Do non-OBD queries for matched brand, or all if no match is found - for brand in FW_QUERY_CONFIGS.keys(): - if brand == matched_brand or matched_brand is None: - all_car_fw.extend(get_fw_versions(logcan, sendcan, query_brand=brand, timeout=timeout, num_pandas=num_pandas, obd_multiplexed=False, debug=debug, progress=progress)) - return all_car_fw -def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, num_pandas=1, obd_multiplexed=True, 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() + params = Params() # Each brand can define extra ECUs to query for data collection for brand, config in FW_QUERY_CONFIGS.items(): @@ -281,9 +278,9 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue - # Or if request is not designated for current multiplexing mode - elif r.non_obd == obd_multiplexed: - continue + + # Toggle OBD multiplexing for each request + set_obd_multiplexing(params, r.obd_multiplexing) try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 0737bea147..009a549afd 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -186,7 +186,7 @@ FW_QUERY_CONFIG = FwQueryConfig( [StdQueries.UDS_VERSION_RESPONSE], bus=1, logging=True, - non_obd=True, + obd_multiplexing=False, ), ], extra_ecus=[ diff --git a/selfdrive/controls/tests/test_startup.py b/selfdrive/controls/tests/test_startup.py index 92fc2468bb..18c8e79026 100755 --- a/selfdrive/controls/tests/test_startup.py +++ b/selfdrive/controls/tests/test_startup.py @@ -72,7 +72,6 @@ class TestStartup(unittest.TestCase): params.clear_all() params.put_bool("Passive", False) params.put_bool("OpenpilotEnabledToggle", True) - params.put_bool("ObdMultiplexingDisabled", True) # Build capnn version of FW array if fw_versions is not None: @@ -109,6 +108,10 @@ class TestStartup(unittest.TestCase): finger = _FINGERPRINTS[car_model][0] for _ in range(1000): + # controlsd waits for boardd to echo back that it has changed the multiplexing mode + if not params.get_bool("ObdMultiplexingChanged"): + params.put_bool("ObdMultiplexingChanged", True) + msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()] pm.send('can', can_list_to_can_capnp(msgs)) diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index 9c0225796d..2b9096b423 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -397,7 +397,6 @@ def setup_env(simulation=False, CP=None, cfg=None, controlsState=None, lr=None): params.put_bool("DisengageOnAccelerator", True) params.put_bool("WideCameraOnly", False) params.put_bool("DisableLogging", False) - params.put_bool("ObdMultiplexingDisabled", True) os.environ["NO_RADAR_SLEEP"] = "1" os.environ["REPLAY"] = "1" From 1a560a1a6c114352b85959f96190d97f49f48010 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Fri, 24 Mar 2023 01:19:39 +0800 Subject: [PATCH 1156/1179] cabana: fix button geometries (#27659) --- tools/cabana/signaledit.cc | 3 +-- tools/cabana/signaledit.h | 11 ++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index d91f6c1401..4cd06e8a7d 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -415,7 +415,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), hl->addWidget(collapse_btn); // tree view - tree = new QTreeView(this); + tree = new TreeView(this); tree->setModel(model = new SignalModel(this)); tree->setItemDelegate(new SignalItemDelegate(this)); tree->setFrameShape(QFrame::NoFrame); @@ -439,7 +439,6 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts), QObject::connect(tree, &QTreeView::viewportEntered, [this]() { emit highlight(nullptr); }); QObject::connect(tree, &QTreeView::entered, [this](const QModelIndex &index) { emit highlight(model->getItem(index)->sig); }); QObject::connect(model, &QAbstractItemModel::modelReset, this, &SignalView::rowsChanged); - QObject::connect(model, &QAbstractItemModel::rowsInserted, this, &SignalView::rowsChanged); QObject::connect(model, &QAbstractItemModel::rowsRemoved, this, &SignalView::rowsChanged); QObject::connect(dbc(), &DBCManager::signalAdded, [this](MessageId id, const cabana::Signal *sig) { selectSignal(sig); }); diff --git a/tools/cabana/signaledit.h b/tools/cabana/signaledit.h index ae73a7b3bc..d6bad6d88c 100644 --- a/tools/cabana/signaledit.h +++ b/tools/cabana/signaledit.h @@ -108,8 +108,17 @@ private: void rowsChanged(); void leaveEvent(QEvent *event); + struct TreeView : public QTreeView { + TreeView(QWidget *parent) : QTreeView(parent) {} + void rowsInserted(const QModelIndex &parent, int start, int end) override { + ((SignalView *)parentWidget())->rowsChanged(); + // update widget geometries in QTreeView::rowsInserted + QTreeView::rowsInserted(parent, start, end); + } + }; + MessageId msg_id; - QTreeView *tree; + TreeView *tree; QLineEdit *filter_edit; ChartsWidget *charts; QLabel *signal_count_lb; From a0e225e4afe971f92fa0980c3f89b1d9818f53a5 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 21:14:57 -0700 Subject: [PATCH 1157/1179] FPv2: don't multiplex second panda (#27663) * fix this way * or can fix this way * simplify * fix --- selfdrive/boardd/boardd.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 3dc54b856a..4faa08d536 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -127,8 +127,8 @@ bool safety_setter_thread(std::vector pandas) { bool obd_multiplexing_requested = p.getBool("ObdMultiplexingEnabled"); if (obd_multiplexing_requested != obd_multiplexing_enabled) { - const uint16_t safety_param = obd_multiplexing_requested ? 0U : 1U; for (int i = 0; i < pandas.size(); i++) { + const uint16_t safety_param = (i > 0 || !obd_multiplexing_requested) ? 1U : 0U; pandas[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param); } obd_multiplexing_enabled = obd_multiplexing_requested; From 049fffb39f875152b2e03df13566fddbd0249a4f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 23:07:27 -0700 Subject: [PATCH 1158/1179] bump cereal --- cereal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cereal b/cereal index 7492dc3f45..494cd28f3b 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 7492dc3f45702dfdbe0f353f38844e7fbf39ca71 +Subproject commit 494cd28f3ba2eaf8e27180b357858f8441b6d90c From 5ab45890aa28e4d97044bb80564de1fb1c2b5492 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 23:31:38 -0700 Subject: [PATCH 1159/1179] Hyundai CAN FD: log hvac FW version (#27668) * add parking and hvac ecus * needs a new query sadly * move space * temp * comment * fix * mid-solution stash * pretty cleannnnnnn * everything seems to be working * bump cereal * this is a smaller diff, easier to merge * bump cereal * just hvac * bump to master --- cereal | 2 +- selfdrive/car/hyundai/values.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cereal b/cereal index 494cd28f3b..d0ca2639d0 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 494cd28f3ba2eaf8e27180b357858f8441b6d90c +Subproject commit d0ca2639d057acda9ce56766f60658417ab6834a diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index fc0469ffed..55645f2050 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -359,18 +359,19 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar], + whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac], bus=4, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar], + whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar, Ecu.hvac], bus=5, ), ], extra_ecus=[ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms + (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], ) From ecbd7150eb68ca79737c43914e91dbc7c633c812 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 23 Mar 2023 23:47:15 -0700 Subject: [PATCH 1160/1179] FwQueryConfig: auxiliary field to add requests for first aux panda (#27666) * mid-solution stash * pretty cleannnnnnn * everything seems to be working * rename * space * reduce obd multiplexing transitions from 3 to 1 (0.3s to 0.1s) --- selfdrive/car/fw_query_definitions.py | 10 ++++++++++ selfdrive/car/hyundai/values.py | 12 +++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py index 4c2baa58d7..7ae9bee404 100755 --- a/selfdrive/car/fw_query_definitions.py +++ b/selfdrive/car/fw_query_definitions.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import capnp +import copy from dataclasses import dataclass, field import struct from typing import Dict, List, Optional, Tuple @@ -57,6 +58,8 @@ class Request: whitelist_ecus: List[int] = field(default_factory=list) rx_offset: int = 0x8 bus: int = 1 + # Whether this query should be run on the first auxiliary panda (CAN FD cars for example) + auxiliary: bool = False # FW responses from these queries will not be used for fingerprinting logging: bool = False # boardd toggles OBD multiplexing on/off as needed @@ -71,3 +74,10 @@ class FwQueryConfig: non_essential_ecus: Dict[capnp.lib.capnp._EnumModule, List[str]] = field(default_factory=dict) # Ecus added for data collection, not to be fingerprinted on extra_ecus: List[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]]] = field(default_factory=list) + + def __post_init__(self): + for i in range(len(self.requests)): + if self.requests[i].auxiliary: + new_request = copy.deepcopy(self.requests[i]) + new_request.bus += 4 + self.requests.append(new_request) diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 55645f2050..5c677951b7 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -355,18 +355,24 @@ FW_QUERY_CONFIG = FwQueryConfig( [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar], ), - # CAN-FD queries (camera) + + # CAN-FD queries (from camera) + # TODO: combine shared whitelists with CAN requests Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac], - bus=4, + bus=0, + auxiliary=True, + obd_multiplexing=False, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], [HYUNDAI_VERSION_RESPONSE], whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar, Ecu.hvac], - bus=5, + bus=1, + auxiliary=True, + obd_multiplexing=False, ), ], extra_ecus=[ From 021661b316f488682c9e4c1b586c9fb51384cdf6 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 00:12:25 -0700 Subject: [PATCH 1161/1179] Hyundai CAN FD: log ADAS parking ECU FW version (#27662) * add parking and hvac ecus * needs a new query sadly * move space * temp * comment * fix * mid-solution stash * pretty cleannnnnnn * everything seems to be working * bump cereal * bump to master * bump to master * don't multiplex when we don't need it --- cereal | 2 +- selfdrive/car/hyundai/values.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index d0ca2639d0..3c5ff1c6d0 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit d0ca2639d057acda9ce56766f60658417ab6834a +Subproject commit 3c5ff1c6d069be21b32e2ac202115f4ea5d21bc7 diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 5c677951b7..57d306496b 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -335,10 +335,15 @@ FINGERPRINTS = { HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ p16(0xf100) # Long description + +HYUNDAI_VERSION_REQUEST_ALT = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(0xf110) # Alt long description + HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_SPARE_PART_NUMBER) + \ p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + \ p16(0xf100) + HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) FW_QUERY_CONFIG = FwQueryConfig( @@ -374,9 +379,28 @@ FW_QUERY_CONFIG = FwQueryConfig( auxiliary=True, obd_multiplexing=False, ), + + # CAN-FD debugging queries + Request( + [HYUNDAI_VERSION_REQUEST_ALT], + [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.parking], + bus=0, + auxiliary=True, + obd_multiplexing=False, + ), + Request( + [HYUNDAI_VERSION_REQUEST_ALT], + [HYUNDAI_VERSION_RESPONSE], + whitelist_ecus=[Ecu.parking], + bus=1, + auxiliary=True, + obd_multiplexing=False, + ), ], extra_ecus=[ (Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms + (Ecu.parking, 0x7b1, None), # ADAS Parking ECU (may exist on all platforms) (Ecu.hvac, 0x7b3, None), # HVAC Control Assembly (Ecu.cornerRadar, 0x7b7, None), ], From 2ad9eec882e6be5aff4ae6a55e3ffb6f76a3d85b Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 00:25:37 -0700 Subject: [PATCH 1162/1179] FPv2: log OBD multiplexed requests (#27667) * log multiplexed requests * bump cereal * bump cereal to master --- cereal | 2 +- selfdrive/car/fw_versions.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cereal b/cereal index 3c5ff1c6d0..c516d5e985 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit 3c5ff1c6d069be21b32e2ac202115f4ea5d21bc7 +Subproject commit c516d5e9856fdb1f5ca856e430ac69aebb2ff017 diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 51bf99ebf4..e71d161f7f 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -300,6 +300,7 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, f.brand = brand f.bus = r.bus f.logging = r.logging or ecu_key in logging_addrs + f.obdMultiplexing = r.obd_multiplexing if sub_addr is not None: f.subAddress = sub_addr From 9e023b3eadcf4d8ed0b59fd5fbe4041342be322f Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 00:29:48 -0700 Subject: [PATCH 1163/1179] FPv2: only set multiplexing when needed (#27669) * only set multiplexing if bus matters * these don't matter anymore --- selfdrive/car/fw_versions.py | 3 ++- selfdrive/car/hyundai/values.py | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index e71d161f7f..9bb04ee821 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -280,7 +280,8 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, continue # Toggle OBD multiplexing for each request - set_obd_multiplexing(params, r.obd_multiplexing) + if r.bus % 4 == 1: + set_obd_multiplexing(params, r.obd_multiplexing) try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (brand, 'any') and diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 57d306496b..bb26d68329 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -369,7 +369,6 @@ FW_QUERY_CONFIG = FwQueryConfig( whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac], bus=0, auxiliary=True, - obd_multiplexing=False, ), Request( [HYUNDAI_VERSION_REQUEST_LONG], @@ -387,7 +386,6 @@ FW_QUERY_CONFIG = FwQueryConfig( whitelist_ecus=[Ecu.parking], bus=0, auxiliary=True, - obd_multiplexing=False, ), Request( [HYUNDAI_VERSION_REQUEST_ALT], From f08132475dc94214c6deda42add8bb4360220ea6 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 25 Mar 2023 02:01:03 +0800 Subject: [PATCH 1164/1179] cabana: align signal value vcenter (#27675) --- tools/cabana/historylog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 3e80a6a697..4ebe8e0473 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -21,7 +21,7 @@ QVariant HistoryLogModel::data(const QModelIndex &index, int role) const { } else if (role == BytesRole) { return m.data; } else if (role == Qt::TextAlignmentRole) { - return Qt::AlignRight; + return (uint32_t)(Qt::AlignRight | Qt::AlignVCenter); } return {}; } From 9c84af296c325f310bad23657bc35e725be45541 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 25 Mar 2023 02:01:26 +0800 Subject: [PATCH 1165/1179] cabana: clear the old timeline after opening a new route from menu (#27672) --- tools/cabana/videowidget.cc | 24 ++++++++++++++---------- tools/cabana/videowidget.h | 3 +++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 536ae7ba97..e36e62131f 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -8,11 +8,12 @@ #include #include #include -#include #include #include #include +const int MIN_VIDEO_HEIGHT = 100; + static const QColor timeline_colors[] = { [(int)TimelineType::None] = QColor(111, 143, 175), [(int)TimelineType::Engaged] = QColor(0, 163, 108), @@ -22,7 +23,7 @@ static const QColor timeline_colors[] = { [(int)TimelineType::AlertCritical] = QColor(199, 0, 57), }; -inline QString formatTime(int seconds) { +static inline QString formatTime(int seconds) { return QDateTime::fromTime_t(seconds).toString(seconds > 60 * 60 ? "hh:mm:ss" : "mm:ss"); } @@ -106,7 +107,7 @@ QWidget *VideoWidget::createCameraWidget() { slider_layout->addWidget(end_time_label); l->addLayout(slider_layout); - cam_widget->setMinimumHeight(100); + cam_widget->setMinimumHeight(MIN_VIDEO_HEIGHT); cam_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); @@ -164,16 +165,12 @@ void VideoWidget::updatePlayBtnState() { } // Slider -Slider::Slider(QWidget *parent) : QSlider(Qt::Horizontal, parent) { - QTimer *timer = new QTimer(this); - timer->setInterval(2000); - timer->callOnTimeout([this]() { +Slider::Slider(QWidget *parent) : timer(this), QSlider(Qt::Horizontal, parent) { + timer.callOnTimeout([this]() { timeline = can->getTimeline(); update(); }); setMouseTracking(true); - - QObject::connect(can, SIGNAL(streamStarted()), timer, SLOT(start())); QObject::connect(can, &AbstractStream::streamStarted, this, &Slider::streamStarted); } @@ -187,11 +184,13 @@ void Slider::streamStarted() { thumnail_future.waitForFinished(); abort_load_thumbnail = false; thumbnails.clear(); + timeline.clear(); + timer.start(2000); thumnail_future = QtConcurrent::run(this, &Slider::loadThumbnails); } void Slider::loadThumbnails() { - const auto segments = can->route()->segments(); + const auto &segments = can->route()->segments(); for (auto it = segments.rbegin(); it != segments.rend() && !abort_load_thumbnail; ++it) { std::string qlog = it->second.qlog.toStdString(); if (!qlog.empty()) { @@ -280,3 +279,8 @@ void Slider::mouseMoveEvent(QMouseEvent *e) { QToolTip::showText(pt, thumb, this, rect()); QSlider::mouseMoveEvent(e); } + +void Slider::leaveEvent(QEvent *event) { + QToolTip::hideText(); + QSlider::leaveEvent(event); +} diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index d10b09fec5..a5ce8c345f 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/qt/widgets/controls.h" @@ -24,6 +25,7 @@ public: private: void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; + void leaveEvent(QEvent *event) override; void sliderChange(QAbstractSlider::SliderChange change) override; void paintEvent(QPaintEvent *ev) override; void streamStarted(); @@ -37,6 +39,7 @@ private: QMap thumbnails; QFuture thumnail_future; QSize thumbnail_size = {}; + QTimer timer; }; class VideoWidget : public QWidget { From 76319d02d843b9809a6d7bedec64db523fa12d68 Mon Sep 17 00:00:00 2001 From: mitchellgoffpc Date: Fri, 24 Mar 2023 16:16:38 -0700 Subject: [PATCH 1166/1179] Added tritonclient to xx deps --- poetry.lock | 303 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 303 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 4abd6777ba..b7554ac03a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -119,6 +119,7 @@ packaging = ">20.6" [package.source] type = "url" url = "https://github.com/commaai/apex/releases/download/pytorch2.0.0%2Bcu11.8/apex-0.1-cp38-cp38-linux_x86_64.whl" + [[package]] name = "appdirs" version = "1.4.4" @@ -459,6 +460,14 @@ python-versions = "*" docutils = ">=0.12" Sphinx = ">=4.0,<5.0.0 || >5.0.0,<6" +[[package]] +name = "brotli" +version = "1.0.9" +description = "Python bindings for the Brotli compression library" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "cachecontrol" version = "0.12.11" @@ -1193,6 +1202,20 @@ monitor = ["psutil (>=5.7.0)"] recommended = ["backports.socketpair", "cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "psutil (>=5.7.0)", "selectors2"] test = ["backports.socketpair", "cffi (>=1.12.2)", "contextvars (==2.4)", "coverage (>=5.0)", "coveralls (>=1.7.0)", "dnspython (>=1.16.0,<2.0)", "futures", "idna", "mock", "objgraph", "psutil (>=5.7.0)", "requests", "selectors2"] +[[package]] +name = "geventhttpclient" +version = "2.0.2" +description = "http client library for gevent" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +brotli = "*" +certifi = "*" +gevent = ">=0.13" +six = "*" + [[package]] name = "greenlet" version = "1.1.3.post0" @@ -2608,6 +2631,7 @@ numpy = [ [package.source] type = "url" url = "https://github.com/commaai/opencv-python-builder/releases/download/4.5.5.64%2Bcu118/opencv_python_headless-4.5.5.64-cp38-cp38-manylinux_2_31_x86_64.whl" + [[package]] name = "osmium" version = "3.4.1" @@ -3359,6 +3383,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "python-rapidjson" +version = "1.10" +description = "Python wrapper around rapidjson" +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "python-socketio" version = "5.7.2" @@ -4260,6 +4292,7 @@ opt-einsum = ["opt-einsum (>=3.3)"] [package.source] type = "url" url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl" + [[package]] name = "torchsummary" version = "1.5.1" @@ -4288,6 +4321,7 @@ scipy = ["scipy"] [package.source] type = "url" url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.1%2Bcu118-cp38-cp38-linux_x86_64.whl" + [[package]] name = "tornado" version = "6.2" @@ -4343,6 +4377,25 @@ torch = "*" tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"] tutorials = ["matplotlib", "pandas", "tabulate"] +[[package]] +name = "tritonclient" +version = "2.28.0" +description = "Python client library and utilities for communicating with Triton Inference Server" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +aiohttp = {version = ">=3.8.1", optional = true, markers = "extra == \"http\""} +geventhttpclient = {version = ">=1.4.4,<=2.0.2", optional = true, markers = "extra == \"http\""} +numpy = ">=1.19.1" +python-rapidjson = ">=0.9.1" + +[package.extras] +all = ["aiohttp (>=3.8.1)", "geventhttpclient (>=1.4.4,<=2.0.2)", "grpcio (==1.41.0)", "numpy (>=1.19.1)", "protobuf (>=3.5.0,<3.20)", "python-rapidjson (>=0.9.1)"] +grpc = ["grpcio (==1.41.0)", "numpy (>=1.19.1)", "protobuf (>=3.5.0,<3.20)", "python-rapidjson (>=0.9.1)"] +http = ["aiohttp (>=3.8.1)", "geventhttpclient (>=1.4.4,<=2.0.2)", "numpy (>=1.19.1)", "python-rapidjson (>=0.9.1)"] + [[package]] name = "types-atomicwrites" version = "1.4.5.1" @@ -4606,7 +4659,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "~3.8" -content-hash = "a16ec604c5251dc860a44f7133289d0b7b16120757f8c903f3917329753c52d1" +content-hash = "b7cd75dfa0dcddff224696ccc7f41d87aac64652f744ab386321c1eee920fbe9" [metadata.files] adal = [ @@ -4916,6 +4969,90 @@ breathe = [ {file = "breathe-4.34.0-py3-none-any.whl", hash = "sha256:48804dcf0e607a89fb6ad88c729ef12743a42db03ae9489be4ef8f7c4011774a"}, {file = "breathe-4.34.0.tar.gz", hash = "sha256:ac0768a5e84addad3e632028fe67749c567aba2b29088493b64c2c1634bcdba1"}, ] +brotli = [ + {file = "Brotli-1.0.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70"}, + {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b"}, + {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6"}, + {file = "Brotli-1.0.9-cp27-cp27m-win32.whl", hash = "sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa"}, + {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452"}, + {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7"}, + {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031"}, + {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb"}, + {file = "Brotli-1.0.9-cp310-cp310-win32.whl", hash = "sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181"}, + {file = "Brotli-1.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2"}, + {file = "Brotli-1.0.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cc0283a406774f465fb45ec7efb66857c09ffefbe49ec20b7882eff6d3c86d3a"}, + {file = "Brotli-1.0.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:11d3283d89af7033236fa4e73ec2cbe743d4f6a81d41bd234f24bf63dde979df"}, + {file = "Brotli-1.0.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c1306004d49b84bd0c4f90457c6f57ad109f5cc6067a9664e12b7b79a9948ad"}, + {file = "Brotli-1.0.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1375b5d17d6145c798661b67e4ae9d5496920d9265e2f00f1c2c0b5ae91fbde"}, + {file = "Brotli-1.0.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cab1b5964b39607a66adbba01f1c12df2e55ac36c81ec6ed44f2fca44178bf1a"}, + {file = "Brotli-1.0.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ed6a5b3d23ecc00ea02e1ed8e0ff9a08f4fc87a1f58a2530e71c0f48adf882f"}, + {file = "Brotli-1.0.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cb02ed34557afde2d2da68194d12f5719ee96cfb2eacc886352cb73e3808fc5d"}, + {file = "Brotli-1.0.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b3523f51818e8f16599613edddb1ff924eeb4b53ab7e7197f85cbc321cdca32f"}, + {file = "Brotli-1.0.9-cp311-cp311-win32.whl", hash = "sha256:ba72d37e2a924717990f4d7482e8ac88e2ef43fb95491eb6e0d124d77d2a150d"}, + {file = "Brotli-1.0.9-cp311-cp311-win_amd64.whl", hash = "sha256:3ffaadcaeafe9d30a7e4e1e97ad727e4f5610b9fa2f7551998471e3736738679"}, + {file = "Brotli-1.0.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4"}, + {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296"}, + {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430"}, + {file = "Brotli-1.0.9-cp35-cp35m-win32.whl", hash = "sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1"}, + {file = "Brotli-1.0.9-cp35-cp35m-win_amd64.whl", hash = "sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea"}, + {file = "Brotli-1.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b"}, + {file = "Brotli-1.0.9-cp36-cp36m-win32.whl", hash = "sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14"}, + {file = "Brotli-1.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c"}, + {file = "Brotli-1.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d"}, + {file = "Brotli-1.0.9-cp37-cp37m-win32.whl", hash = "sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"}, + {file = "Brotli-1.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5"}, + {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb"}, + {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649"}, + {file = "Brotli-1.0.9-cp38-cp38-win32.whl", hash = "sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429"}, + {file = "Brotli-1.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f"}, + {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19"}, + {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c"}, + {file = "Brotli-1.0.9-cp39-cp39-win32.whl", hash = "sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3"}, + {file = "Brotli-1.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:73fd30d4ce0ea48010564ccee1a26bfe39323fde05cb34b5863455629db61dc7"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02177603aaca36e1fd21b091cb742bb3b305a569e2402f1ca38af471777fb019"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b43775532a5904bc938f9c15b77c613cb6ad6fb30990f3b0afaea82797a402d8"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5bf37a08493232fbb0f8229f1824b366c2fc1d02d64e7e918af40acd15f3e337"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:330e3f10cd01da535c70d09c4283ba2df5fb78e915bea0a28becad6e2ac010be"}, + {file = "Brotli-1.0.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e1abbeef02962596548382e393f56e4c94acd286bd0c5afba756cffc33670e8a"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3148362937217b7072cf80a2dcc007f09bb5ecb96dae4617316638194113d5be"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336b40348269f9b91268378de5ff44dc6fbaa2268194f85177b53463d313842a"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b8b09a16a1950b9ef495a0f8b9d0a87599a9d1f179e2d4ac014b2ec831f87e7"}, + {file = "Brotli-1.0.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c8e521a0ce7cf690ca84b8cc2272ddaf9d8a50294fd086da67e517439614c755"}, + {file = "Brotli-1.0.9.zip", hash = "sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438"}, +] cachecontrol = [ {file = "CacheControl-0.12.11-py2.py3-none-any.whl", hash = "sha256:2c75d6a8938cb1933c75c50184549ad42728a27e9f6b92fd677c3151aa72555b"}, {file = "CacheControl-0.12.11.tar.gz", hash = "sha256:a5b9fcc986b184db101aa280b42ecdcdfc524892596f606858e0b7a8b4d9e144"}, @@ -5700,6 +5837,86 @@ gevent = [ {file = "gevent-22.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0569e133bb620de1001ac807ad9a8abaadedd25349c6d695f80c9048a3f59d42"}, {file = "gevent-22.10.1.tar.gz", hash = "sha256:df3042349c9a4460eeaec8d0e56d737cb183eed055e75a6af9dbda94aaddaf4d"}, ] +geventhttpclient = [ + {file = "geventhttpclient-2.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd76acdc7e7ee5c54c7b279f806b28957a6b092f79c40db34adcfd972749343c"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:320a2c756d8a4f296de370476a1515485c186d9e22c3fc29e04f8f743a7d47bb"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36d3345c6585b09738195a7c45d279a87ccbab0350f1cce3679d3f0dce8577a1"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:407d54499556c2741b93691b86da93232590b013f4a0b773327d766fe3e5c0a9"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcf325131b0e4600b793643108cd85dddd66bbf532fd2eb498be5727ef532a1e"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5841dd02e6f792a4ef15dbd04fefe620c831ba0b78105808160bb779a31af4"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2ba69422d4e8670dd99803b1313ba574a4d41f52e92b512af51068c9c577bdc1"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e3af579c6b46b9caa515a8baf6a2cadeafcd1d41ad22ca5712851f074a40b47"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6ff7fc19f9a4fdd54a2b1c106a705ea2c679fa049685ed763051d417725bdab1"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-win32.whl", hash = "sha256:eec7c52e8eb817674a193e0124486b507215d9e86d34f2638bf9a9292d16f815"}, + {file = "geventhttpclient-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:0e9f7283c01d970e643d89da81127869a8d94bb7a0081020dcad5b590bc007c4"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5ceb492d43a659b895794999dc40d0e7c23b1d41dd34040bbacd0dc264b57d5b"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95959c201d3151fa8f57e0f1ce184476d1173996bdde41dc7d600006023dc5be"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:31c7febba298ecf44838561074a3fb7a01523adca286469b5a82dcc90e8d6a07"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:996c5f453d810b3c592160193d6832a065cca0112e92adc74e62df0e4c564df6"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f817e226c02b5a71d86de3772d6accdf250288d1e6825e426c713759830162d"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c55b7ac0ba0e1e1afbf297b7608f0b3a0bbc34fb4b0c19b7869f32a77ddc6209"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6775bc81e25c48fa58b034444aecfa508b0c3d1bc1e4ae546cc17661be1f51aa"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a0156882c73537bbbbc7c693ae44c9808119963174078692613ffa4feea21fcf"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ebb582a291c4c5daaac2ea115b413f4be86874baa60def44d333301cee17bd7"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-win32.whl", hash = "sha256:716f1f72f50b841daf9c9511a01fc31a030866510a11863f27741e26e4f556a7"}, + {file = "geventhttpclient-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:777fcdb72077dfbf70516ecb9e9022246dd337b83a4c1e96f17f3ab9e15f4547"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:379d90d8b1fcdda94e74d693806e0b0116c0610504e7f62d5576bac738dc66a5"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00b7b2b836294c091c53789a469c5671202d79420b5191931df4e3a767d607fa"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d075355862d7726eb3436f0136fce7650c884f2d04eaae7a39fed3aad9798bc"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa7b1a27f950d209fe223a97906fe41312dc12c92372424639b8a9b96f1adf91"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fe4e06313aad353b103950780b050d3958000464cc732d621ff8ea3cacbd2bc4"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:84d7be660b6bc53dd53e3f46b3bc5d275972a8116bd183a77139bb4d9d6d9fb1"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:81f839d6becd664d0972b488422f5dc821f8ad2f2196d53aa5e4d799a3a35a66"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:e707f62271a093e6e3af6f1bbd8cc398b414b8c508fe6b15505dd8e76c4409ac"}, + {file = "geventhttpclient-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:28d7655d1d50bc75ece683a0ae8faf978821d4aeae358d77b59371548db07f1e"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58877b4440a580063571a23fbc616aed7c735c6bf9ef525c5129783df8b6966"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57c993c4b2bea551c4a71b75ae1e172e9f3e4352f704ff1b619a0f16aa762f76"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f67e789e31c7b1ce440cd1465dcdefeca29ba6108735eac0b1a593d3a55b7f"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3326e115ec7e7ce95a5d0d47698e8f3584944c4c434a7404937d56b17136b8"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ef328ee3e7dca5055b833fdf3c181647a335abf0249947b27f5df2d95390198c"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:27049ea40e3b559eee380310272aaa9b7c19e73c1d9e51e2ec137362be2caa70"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b88a10538341e33fed1682c0dd4579c655d49db5863e7456583085a1cd6bd9d4"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:d52aba2c38420b3fc518188449f1c2a46b1a99adf1c0266c68e72ee0422cd0fa"}, + {file = "geventhttpclient-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3648626ca58ea4b340e695d78e5d533e6b8be78d375edbd42ff188bc3447e095"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fcf96e212b55b93490f3a5fcdfe7a2ef4995a0d13b7d9df398b11e319b7a86b1"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e9f2ff09706e3a64a99886d5f2595f3bf364821bc609f2865dbc3e499e21a36"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:721c3075897bfc81e918066f16ae3d1a88c7bb14eeeb831a4f89ea636474643e"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91615fed7931acd49cfe5fc30984acd5411dc1f2643b1544c879d1a537233c6d"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7adaa29e5699dea54e0224d1d2d9d8869668d8ad79f5b89433ff9c46f9424a6c"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9be5000ba57336a90b438782117c1e43205f51f49aa9b1499a82e210e8431b11"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:12d271cc53486efb3716e99855dc5cb84f2cd3fc9f3243721747bb39ec0fff8a"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b9c0c6b75b3905000d2490dc64b4c98a8bac155efbc0ff8917ac082ae0bad261"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e956a457d8831dc81d6f046ab09ebeec680f9a1e9c07e25a1906e77b287918ee"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-win32.whl", hash = "sha256:bc46d5479673dfb293ea428c057d2e23e48ebef5c5d44587cdbaada7f87553e4"}, + {file = "geventhttpclient-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:f44153e4b3ef9b901edcd14be54145a0058bf5fa371b3e583153865fac866245"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ebf98db9435824cf0b80b5247be6c88b20bfafd6249f7ebaabb85297da37e380"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c8b7298eb1ebd015257bf4503e34f5fbbe64bd83324140f76b511046aba5a0d5"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:60b81a6d4e65db7c1a5350c9fb72ebf800b478849a7e8020d1ab93af237a3747"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad6c2fcbc3733785bd3b8c2bb43d1f605f9085b0a8b70ce354d198f37143f884"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94edb022fa50d576cf63f6dd0c437c1acd24a719872a5935991aaf08f8e88cb2"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca459cedb3827d960362e05ea3a4ae600a6d0d93de77eac2ac0f79828e5e18c"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7551b6db860b56411de1f96618e91b54f65e1a7be8d10255bd1adfb738bb6ee5"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bcb7e061c243308d9a44b02de5298001e917f1636a9f270c10da86601fcc8dfa"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96922d170ef8933f4c20036e8d70d4fbe861f54c543e32e7459ebdbaafa65a2e"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ebb3c993903d40fd4bb1f3e55b84c62c8fc1d14433ae6d4d477dd9a325354c94"}, + {file = "geventhttpclient-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:dbccf1ba155dea3ea99ba0e67a835c05b4303f05298e85f5bb2a46700ccdf092"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8770b8ab9e8c31d2aaf8a6fbc63fbb7239c58db10bb49cee191ca5c141c61542"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daff1e977fccf98f27266d3891afdc101f1d705a48331754909e960bcae83f8a"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2435e0f2a60e00d977822ec4c12e7851deb7aa49a23d32d648e72c641aae3b05"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09acd03d0a8c1bb7d5a1cb6fcb77aaa19a907c1b4915ab58da5d283675edb0a5"}, + {file = "geventhttpclient-2.0.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:5d0813d97050446dab2fb243312e6c446e4ef5e9591befd597ef8f2887f8e2a8"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:852da9bb0fc792cdca5ffc9327490094783e42415494b3569e5d532615027439"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79304a63a9d0512f2757c5862487b332b18a9c85feebecf6ebc3526c6dd1ba2"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c1c783fce45f16db448d7e34864f1e9c22fe60a7780d2c1c14edbb1fb7262e"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77c407c2b4bea817c6f752502db4ab0e9f9465b4fb85b459d1332b5f93a3096c"}, + {file = "geventhttpclient-2.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f0d70a83ef4ab93102c6601477c13e9cdbc87205e5237fbf5797e30dc9d3ee8"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b03f298ec19b8a4717cce8112fe30322c9e5bfada84dde61a1a44d1eeffc1d3c"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2dc94b9a23eb6744a8c729aec2b1cdc4e39acf1d8f16ea85a62810aa6b2cae5"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:805554594bb29231fd990cc2cbbe493d223d76a6085fec891dd76bb4e0928933"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb23527d98f626ca7a4e8961ed9bdc6aed3388de306614c69a133b34262460f4"}, + {file = "geventhttpclient-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a594ab319872a38fb7f16be4cfb107d3c63c43a081f2abe241834e9877f27401"}, + {file = "geventhttpclient-2.0.2.tar.gz", hash = "sha256:8135a85200b170def7293d01dd1557931fcd1bec1ac78c52ad7cedd22368b9ba"}, +] greenlet = [ {file = "greenlet-1.1.3.post0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3"}, {file = "greenlet-1.1.3.post0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589"}, @@ -6679,6 +6896,7 @@ onnx = [ ] onnx2torch = [ {file = "onnx2torch-1.5.4-py3-none-any.whl", hash = "sha256:fd1a0fe05072bfb9f3d86d9330299b130b41f11bd4ae634db17078974e711725"}, + {file = "onnx2torch-1.5.4.tar.gz", hash = "sha256:df837b557a63540223d85fde4a1d679fde0ca8d8bb89d5379c030b01eddc9c24"}, ] onnxoptimizer = [ {file = "onnxoptimizer-0.3.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e73a5e2e3ca4db9bff54f7131768749c861677b97ee811a136fcf1a52783cf6e"}, @@ -7348,6 +7566,64 @@ python-engineio = [ python-logstash = [ {file = "python-logstash-0.4.8.tar.gz", hash = "sha256:d04e1ce11ecc107e4a4f3b807fc57d96811e964a554081b3bbb44732f74ef5f9"}, ] +python-rapidjson = [ + {file = "python-rapidjson-1.10.tar.gz", hash = "sha256:acfecbf5edb91ec72a20a125de7f56b8c2f6161eff4c65382c8ee6a2484d3540"}, + {file = "python_rapidjson-1.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1db7b0af882999f5685eb7046a0f3b3aca5d55a3e84b3089747d29a4ec6fdade"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87c8c8b615513f9dc414af1554140589036d14840f5e1f1845965e1c0a080e1"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0a2f5c4abe529ca2764343416e35710a263832533b7bdc76c3285efb5b5ecc8"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40467c3a6d8f070cc4d196fe46a79ed59d1a13a4d3fdc6a0325a21816600e5a7"}, + {file = "python_rapidjson-1.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df4e7237a3e77666ccb9b437013294e6aa3968528f7c61f60f6f38eea0f8f79"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:99a5215f24ff1fa6cc67ee275a6852aa56d934d3b8cd7a40197feb632b54fd76"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3dbea0ee9fa1cd6ecc13a949f6bb94013639d39cdb56f58df4ab61130d35e57c"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:6d1d0c5da3bd5f701b1aed550e1e7bd59b16ae642877cddf18815006cf998f9a"}, + {file = "python_rapidjson-1.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:072f76c1f1483bcc4056d7d3a8b0319bf841a73e955f188302094b62b2163bf9"}, + {file = "python_rapidjson-1.10-cp310-cp310-win32.whl", hash = "sha256:c95d466307a2140a7687a575103980c6e81c9f62d19556cafad3d6b2932b7eb1"}, + {file = "python_rapidjson-1.10-cp310-cp310-win_amd64.whl", hash = "sha256:454ffda58cc6fed64d983b1b8ae4b39a563b4fd671dae9132e06450025898539"}, + {file = "python_rapidjson-1.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fff343076fbeee0cd7e4e3fb9472f2d567a127ec7b8b5b7ecba6bf7960a3ce07"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:686482c67727edad4b6d0c753bc159f35134a5a623e9651c4b7c008ef2996252"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ef7d55688b7123d62690b193537cc048fa9f35cfa43d249fedc0d9fd398890a"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f27c0601792533ab6e98452961d61566480dc155da19d2a358a5fd9a85d9321"}, + {file = "python_rapidjson-1.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95176e35e3bacb8a1a27f563e815b5b57c717992c871b1c25fd76a835fbba32c"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47a0ec20886b8be86af307c10d699a447e22979ed7dd1f2b7ed5cb7496b3d920"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f7968c0cb09d9a76aa2483556ba46ab42634baf216cb2f2c7cd6bf77119a33c1"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5faab270a4dd49216ceaca7169682680b2f5df8311c1ed259e4612d9d0cf61b7"}, + {file = "python_rapidjson-1.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:81b797934dc037810f5f98af138b55a3b6f18dd569cc5e8f81fe79956a4717ca"}, + {file = "python_rapidjson-1.10-cp311-cp311-win32.whl", hash = "sha256:6c1d62cc58a61629fc5e216fb7b3a1b02787c98fded874a7b474b1e6325e377e"}, + {file = "python_rapidjson-1.10-cp311-cp311-win_amd64.whl", hash = "sha256:29d31fc4254f1a4dca420e58bd1331e990fc2959d09ff2daa7934d52732a8491"}, + {file = "python_rapidjson-1.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:718f4e217b511cfbf9166f55ccf4bf4e4538495bee403e390cf89791c0debc26"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:541bbb96353cf3fe2bdb29e727087226532be4e4573daad6f042cfdea533a564"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50f0402a6899c6a177d4a37152deefcd59c61e44bef56b71e8d006a186c86286"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c035e17744d6d6fba073b550b0040a74e55f2ad33fd798df206ff6879b41ad10"}, + {file = "python_rapidjson-1.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da970bde42309a74a5556e696673ea11c4545b8bee5081b84265ded460b2e9ef"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7437a649821008aa456f2fbec737880d7f9bdda7ec94cc1743a43ccf32b5d26"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:362d969bbd277f78bf0b1ffaa810857ea40351146b827f896f8d49e9c25fc99c"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:409256e7748c4ab7f17b3793c7a78ca01914c487644fc42140d116ed4dec8c4f"}, + {file = "python_rapidjson-1.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a34a7e2853456fe50ba2ee22e38e7841e55eee10021d4496cce62285f148e8e7"}, + {file = "python_rapidjson-1.10-cp37-cp37m-win32.whl", hash = "sha256:bc4a97940e5afa60a598483d0eb863b26e4810aaf030d92a4301f5fc183e1b6d"}, + {file = "python_rapidjson-1.10-cp37-cp37m-win_amd64.whl", hash = "sha256:89586b67f9c69b66885774acebf3d018e7b8f93cea2b3cffa306ec9d37877594"}, + {file = "python_rapidjson-1.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2e38082b1a8ce3e2bd55821852c0cd643cdabe6497fd9c054f6b47a099afbea0"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0955ef22fabb36b26fcad702ae54c1bce2bc2a74b1883c42d251d72011d0d426"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9db03c68ab0158bcdf80299b2c980186d148aa3e05d5650fea5148a425a29a"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde8ab0f06debaa06d93085f19dc3ec3db53f22883f1625dd32b96a87e7009de"}, + {file = "python_rapidjson-1.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23539c9f7d85d64a00d3cb44c7d9ab3be2184d4da42a5f3263dcfd1d0203ee43"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bfd484285f3477acef0bb45abd2b80b6252e35a5a53395ce48f0327cbe43c23"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8b0ed643ebaa8ddf3f40422752efe83abda29aa30a9e6866ccd9dd591b5057d0"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:5aeca661a0f229f1312fb3ad3e1a5c6736d49942d80d4931810158559eb8f119"}, + {file = "python_rapidjson-1.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8a68ed066e8f0878b7112f943cf35ba9e5217395bcdd8cb478cde01871e2701c"}, + {file = "python_rapidjson-1.10-cp38-cp38-win32.whl", hash = "sha256:d286be6f63446776c4958bb37824c683194b4878fc9cd5b7255134fb5a6ba536"}, + {file = "python_rapidjson-1.10-cp38-cp38-win_amd64.whl", hash = "sha256:aece5270c6e6d5c3d54586c9a5fb9677d70d7019744a59560c5c369c7b9bba25"}, + {file = "python_rapidjson-1.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc09c5ad0fe71f262cdcc5655409f132f1560a8af80e76e7757945ce401fdbab"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f6447bd7a8ff5135ab7e372b48a174d3c560d5b322e32bd465e8458e6e4593"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22ede69213885391b46cc14596bfd4cd1a5c6f34a2db6600fb08b03982dbc7b7"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a9425129623718a04b885a12190faa23e7997c4e8632054e18df7ea473f746d"}, + {file = "python_rapidjson-1.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60e10f32e1a8d155448842934cbe71eb620b4b4a0cb3627ba4c4856e27556534"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8d23caab17b87ed5b82e28cdc19172ba1ca65c982e3fff387961d3f33710031f"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f07d4fcdcfd64bdad0143b9705c5d5089677ebddf60ac6c1f8074a34b1c70cf9"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:87b991c7ae435489c56a46cef228d2b65a3df689ee4fe24fab69c791c841f633"}, + {file = "python_rapidjson-1.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3706a5c4f21073c04be133c36565efc6e3f5646a03c8d19af78c19d7c70eb708"}, + {file = "python_rapidjson-1.10-cp39-cp39-win32.whl", hash = "sha256:47f9078ea6884f700166a8728d863609fec62232e66a33b8fb4a7706ce7c731c"}, + {file = "python_rapidjson-1.10-cp39-cp39-win_amd64.whl", hash = "sha256:9e4921ab7002ae9faad7f439a7c50aa195039f177e9e51a76c34c97966c79a79"}, +] python-socketio = [ {file = "python-socketio-5.7.2.tar.gz", hash = "sha256:92395062d9db3c13d30e7cdedaa0e1330bba78505645db695415f9a3c628d097"}, {file = "python_socketio-5.7.2-py3-none-any.whl", hash = "sha256:d9a9f047e6fdd306c852fbac36516f4b495c2096f8ad9ceb8803b8e5ff5622e3"}, @@ -7721,6 +7997,18 @@ setproctitle = [ {file = "setproctitle-1.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7f2719a398e1a2c01c2a63bf30377a34d0b6ef61946ab9cf4d550733af8f1ef1"}, {file = "setproctitle-1.3.2-cp310-cp310-win32.whl", hash = "sha256:e425be62524dc0c593985da794ee73eb8a17abb10fe692ee43bb39e201d7a099"}, {file = "setproctitle-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:e85e50b9c67854f89635a86247412f3ad66b132a4d8534ac017547197c88f27d"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a97d51c17d438cf5be284775a322d57b7ca9505bb7e118c28b1824ecaf8aeaa"}, + {file = "setproctitle-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587c7d6780109fbd8a627758063d08ab0421377c0853780e5c356873cdf0f077"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d17c8bd073cbf8d141993db45145a70b307385b69171d6b54bcf23e5d644de"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e932089c35a396dc31a5a1fc49889dd559548d14cb2237adae260382a090382e"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e4f8f12258a8739c565292a551c3db62cca4ed4f6b6126664e2381acb4931bf"}, + {file = "setproctitle-1.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:570d255fd99c7f14d8f91363c3ea96bd54f8742275796bca67e1414aeca7d8c3"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a8e0881568c5e6beff91ef73c0ec8ac2a9d3ecc9edd6bd83c31ca34f770910c4"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4bba3be4c1fabf170595b71f3af46c6d482fbe7d9e0563999b49999a31876f77"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:37ece938110cab2bb3957e3910af8152ca15f2b6efdf4f2612e3f6b7e5459b80"}, + {file = "setproctitle-1.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db684d6bbb735a80bcbc3737856385b55d53f8a44ce9b46e9a5682c5133a9bf7"}, + {file = "setproctitle-1.3.2-cp311-cp311-win32.whl", hash = "sha256:ca58cd260ea02759238d994cfae844fc8b1e206c684beb8f38877dcab8451dfc"}, + {file = "setproctitle-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:88486e6cce2a18a033013d17b30a594f1c5cb42520c49c19e6ade40b864bb7ff"}, {file = "setproctitle-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:92c626edc66169a1b09e9541b9c0c9f10488447d8a2b1d87c8f0672e771bc927"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:710e16fa3bade3b026907e4a5e841124983620046166f355bbb84be364bf2a02"}, {file = "setproctitle-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f29b75e86260b0ab59adb12661ef9f113d2f93a59951373eb6d68a852b13e83"}, @@ -8090,6 +8378,15 @@ traitlets = [ {file = "traitlets-5.5.0.tar.gz", hash = "sha256:b122f9ff2f2f6c1709dab289a05555be011c87828e911c0cf4074b85cb780a79"}, ] triton = [ + {file = "triton-2.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38806ee9663f4b0f7cd64790e96c579374089e58f49aac4a6608121aa55e2505"}, + {file = "triton-2.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:226941c7b8595219ddef59a1fdb821e8c744289a132415ddd584facedeb475b1"}, + {file = "triton-2.0.0-1-cp36-cp36m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4c9fc8c89874bc48eb7e7b2107a9b8d2c0bf139778637be5bfccb09191685cfd"}, + {file = "triton-2.0.0-1-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d2684b6a60b9f174f447f36f933e9a45f31db96cb723723ecd2dcfd1c57b778b"}, + {file = "triton-2.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d4978298b74fcf59a75fe71e535c092b023088933b2f1df933ec32615e4beef"}, + {file = "triton-2.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:74f118c12b437fb2ca25e1a04759173b517582fcf4c7be11913316c764213656"}, + {file = "triton-2.0.0-1-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9618815a8da1d9157514f08f855d9e9ff92e329cd81c0305003eb9ec25cc5add"}, + {file = "triton-2.0.0-1-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aca3303629cd3136375b82cb9921727f804e47ebee27b2677fef23005c3851a"}, + {file = "triton-2.0.0-1-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e3e13aa8b527c9b642e3a9defcc0fbd8ffbe1c80d8ac8c15a01692478dc64d8a"}, {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"}, {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"}, {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"}, @@ -8100,6 +8397,10 @@ triton = [ {file = "triton-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42a0d2c3fc2eab4ba71384f2e785fbfd47aa41ae05fa58bf12cb31dcbd0aeceb"}, {file = "triton-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c47b72c72693198163ece9d90a721299e4fb3b8e24fd13141e384ad952724f"}, ] +tritonclient = [ + {file = "tritonclient-2.28.0-py3-none-any.whl", hash = "sha256:1f58bbe09a88c35f7979de8ab6579a5337372951f723c0aba31e8bee3e8d79da"}, + {file = "tritonclient-2.28.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:47d93197a0876a743012db4c03f1100f7b225b9aaf8d5f8025bf4a5d9e61bfd2"}, +] types-atomicwrites = [ {file = "types-atomicwrites-1.4.5.1.tar.gz", hash = "sha256:9e9f0923ebf93524b28bcece5a23ac8c3820f39b060df29f671936d2e4bc04bc"}, {file = "types_atomicwrites-1.4.5.1-py3-none-any.whl", hash = "sha256:2f1febbdc78b55453b189fa5b136dce34bab7d1d82319163d470e404aab55c83"}, diff --git a/pyproject.toml b/pyproject.toml index 7506ee552d..47994779b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -174,6 +174,7 @@ Werkzeug = "^2.1.2" zerorpc = { git = "https://github.com/commaai/zerorpc-python.git", branch = "master" } omegaconf = "^2.3.0" osmnx = "==1.2.2" +tritonclient = {version = "2.28.0", extras = ["http"]} [build-system] From c25ce02639a86f6627314ecd3b3c101d82d7498f Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Fri, 24 Mar 2023 16:48:07 -0700 Subject: [PATCH 1167/1179] tici: turn off fan after boot (#27680) * tici: turn off fan after boot * tmp if --------- Co-authored-by: Comma Device --- system/hardware/tici/hardware.py | 6 ++++++ system/hardware/tici/pins.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 9c1cc930c1..46db097da1 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -452,6 +452,12 @@ class Tici(HardwareBase): # Allow thermald to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") + # TODO: remove the if once agnos 7 ships + # Turn off fan, turned on by the ABL + if os.path.exists('/sys/class/gpio/gpio49/'): + gpio_init(GPIO.SOM_ST_IO, True) + gpio_set(GPIO.SOM_ST_IO, 0) + # *** IRQ config *** # move these off the default core diff --git a/system/hardware/tici/pins.py b/system/hardware/tici/pins.py index fe31b9311d..082a402f15 100644 --- a/system/hardware/tici/pins.py +++ b/system/hardware/tici/pins.py @@ -10,6 +10,8 @@ class GPIO: STM_RST_N = 124 STM_BOOT0 = 134 + SOM_ST_IO = 49 + LTE_RST_N = 50 LTE_PWRKEY = 116 LTE_BOOT = 52 From b2beb3792ec34dd1cc3bf554b845f5f496812343 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 17:44:49 -0700 Subject: [PATCH 1168/1179] Lexus: LSS is standard on ES (#27684) * standard on 17 and 18 https://dealerinspire-brochure.s3.amazonaws.com/834.pdf & https://www.lexus.com/content/dam/lexus/documents/brochures/models/2018/MY18-Lexus-ES-and-ES-Hybrid-Brochure.pdf * update docs --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index 1f668dbe8b..d9eef56215 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -126,7 +126,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| +|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 4edafc0c28..190f7faa61 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -168,7 +168,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { # Lexus CAR.LEXUS_CTH: ToyotaCarInfo("Lexus CT Hybrid 2017-18", "Lexus Safety System+"), - CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18", "Lexus Safety System+"), + CAR.LEXUS_ESH: ToyotaCarInfo("Lexus ES Hybrid 2017-18"), CAR.LEXUS_ES_TSS2: ToyotaCarInfo("Lexus ES 2019-22"), CAR.LEXUS_ESH_TSS2: ToyotaCarInfo("Lexus ES Hybrid 2019-23", video_link="https://youtu.be/BZ29osRVJeg?t=12"), CAR.LEXUS_IS: ToyotaCarInfo("Lexus IS 2017-19"), From c2bdbaa3462808bbe274d0adcb4f08ba9609dd90 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 17:48:31 -0700 Subject: [PATCH 1169/1179] Lexus: 2017 RC is not supported (#27678) we don't support 2017 --- docs/CARS.md | 2 +- selfdrive/car/toyota/values.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index d9eef56215..3e23316bd8 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -133,7 +133,7 @@ A supported vehicle is one that just works when you install a comma three. All s |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| |Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| -|Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| +|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|| |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|| diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 190f7faa61..2398e012d6 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -176,7 +176,7 @@ CAR_INFO: Dict[str, Union[ToyotaCarInfo, List[ToyotaCarInfo]]] = { CAR.LEXUS_NXH: ToyotaCarInfo("Lexus NX Hybrid 2018-19"), CAR.LEXUS_NX_TSS2: ToyotaCarInfo("Lexus NX 2020-21"), CAR.LEXUS_NXH_TSS2: ToyotaCarInfo("Lexus NX Hybrid 2020-21"), - CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2017-20"), + CAR.LEXUS_RC: ToyotaCarInfo("Lexus RC 2018-20"), CAR.LEXUS_RX: [ ToyotaCarInfo("Lexus RX 2016", "Lexus Safety System+"), ToyotaCarInfo("Lexus RX 2017-19"), From d443d8f5e30e2d9110893c181d433fe9af2d91e9 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 19:11:50 -0700 Subject: [PATCH 1170/1179] VW: add missing Arteon 2019 FW (#27671) * add missing arteon 2019 fw * duplicate --- selfdrive/car/volkswagen/values.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py index e63975b0c0..bdd82088a1 100755 --- a/selfdrive/car/volkswagen/values.py +++ b/selfdrive/car/volkswagen/values.py @@ -293,6 +293,7 @@ FW_VERSIONS = { b'\xf1\x873G0906259N \xf1\x890004', b'\xf1\x873G0906259P \xf1\x890001', b'\xf1\x875NA907115H \xf1\x890002', + b'\xf1\x873G0906259G \xf1\x890004', ], (Ecu.transmission, 0x7e1, None): [ b'\xf1\x8709G927158L \xf1\x893611', @@ -304,17 +305,19 @@ FW_VERSIONS = { b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1616001613121157161111572900', b'\xf1\x873Q0959655BK\xf1\x890703\xf1\x82\x0e1616001613121177161113772900', b'\xf1\x873Q0959655DL\xf1\x890732\xf1\x82\0161812141812171105141123052J00', + b'\xf1\x873Q0959655CK\xf1\x890711\xf1\x82\x0e1712141712141105121122052900', ], (Ecu.eps, 0x712, None): [ b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571B41815A1', b'\xf1\x873Q0909144L \xf1\x895081\xf1\x82\x0571B00817A1', - b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\00567B0020800', + b'\xf1\x875Q0910143C \xf1\x892211\xf1\x82\x0567B0020800', b'\xf1\x875WA907145M \xf1\x891051\xf1\x82\x002MB4092M7N', ], (Ecu.fwdRadar, 0x757, None): [ b'\xf1\x872Q0907572AA\xf1\x890396', b'\xf1\x872Q0907572T \xf1\x890383', b'\xf1\x875Q0907572J \xf1\x890654', + b'\xf1\x875Q0907572R \xf1\x890771', ], }, CAR.ATLAS_MK1: { From b61a0b785af911d12816d405edc8e904416a6271 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Fri, 24 Mar 2023 20:07:11 -0700 Subject: [PATCH 1171/1179] Toyota: use DBC for alt brake safety param (#27686) * use DBC * use DBC --- selfdrive/car/toyota/interface.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index e6476863c3..33a87451e9 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -2,7 +2,7 @@ from cereal import car from common.conversions import Conversions as CV from panda import Panda -from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ +from selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR from selfdrive.car import STD_CARGO_KG, scale_tire_stiffness, get_safety_config from selfdrive.car.interfaces import CarInterfaceBase @@ -21,7 +21,8 @@ class CarInterface(CarInterfaceBase): ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] - if candidate in (CAR.RAV4, CAR.PRIUS_V, CAR.COROLLA, CAR.LEXUS_ESH, CAR.LEXUS_CTH): + # BRAKE_MODULE is on a different address for these cars + if DBC[candidate]["pt"] == "toyota_new_mc_pt_generated": ret.safetyConfigs[0].safetyParam |= Panda.FLAG_TOYOTA_ALT_BRAKE if candidate in ANGLE_CONTROL_CAR: From 33afefd346e4348aacb122a486066741731b7d05 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sat, 25 Mar 2023 12:54:41 +0800 Subject: [PATCH 1172/1179] cabana: enables user to select the zoom area when the mouse press on the data point (#27679) zoom anywhere --- tools/cabana/chartswidget.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index c98ca3bc69..72c9e1ba91 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -9,8 +9,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -849,6 +850,13 @@ QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { chart()->addSeries(series); series->attachAxis(axis_x); series->attachAxis(axis_y); + + // disables the delivery of mouse events to the opengl widget. + // this enables the user to select the zoom area when the mouse press on the data point. + auto glwidget = findChild(); + if (glwidget && !glwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) { + glwidget->setAttribute(Qt::WA_TransparentForMouseEvents); + } return series; } From 084e83cda1415189539755343e74e9342e7ec42d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 25 Mar 2023 01:02:11 -0700 Subject: [PATCH 1173/1179] FPv2: replace temporary variable with config (#27692) * query extra ecus (still need to match) * match against extra ecus * clean p * clean p * switch that around * can clean that up * values * rm * not used --- selfdrive/car/fw_versions.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 9bb04ee821..6918913f80 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -19,7 +19,7 @@ FW_QUERY_CONFIGS = get_interface_attr('FW_QUERY_CONFIG', ignore_none=True) VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True) MODEL_TO_BRAND = {c: b for b, e in VERSIONS.items() for c in e} -REQUESTS = [(brand, r) for brand, config in FW_QUERY_CONFIGS.items() for r in config.requests] +REQUESTS = [(brand, config, r) for brand, config in FW_QUERY_CONFIGS.items() for r in config.requests] def chunks(l, n=128): @@ -153,7 +153,7 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []} responses = set() - for brand, r in REQUESTS: + for brand, _, r in REQUESTS: # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue @@ -190,9 +190,9 @@ def get_brand_ecu_matches(ecu_rx_addrs): """Returns dictionary of brands and matches with ECUs in their FW versions""" brand_addrs = get_brand_addrs() - brand_matches = {brand: set() for brand, _ in REQUESTS} + brand_matches = {brand: set() for brand, _, _ in REQUESTS} - brand_rx_offsets = set((brand, r.rx_offset) for brand, r in REQUESTS) + brand_rx_offsets = set((brand, r.rx_offset) for brand, _, r in REQUESTS) for addr, sub_addr, _ in ecu_rx_addrs: # Since we can't know what request an ecu responded to, add matches for all possible rx offsets for brand, rx_offset in brand_rx_offsets: @@ -247,19 +247,15 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # ECUs using a subaddress need be queried one by one, the rest can be done in parallel addrs = [] parallel_addrs = [] - logging_addrs = [] ecu_types = {} for brand, brand_versions in versions.items(): - for candidate, ecu in brand_versions.items(): + for ecu in brand_versions.values(): for ecu_type, addr, sub_addr in ecu.keys(): a = (brand, addr, sub_addr) if a not in ecu_types: ecu_types[a] = ecu_type - if a not in logging_addrs and candidate == "debug": - logging_addrs.append(a) - if sub_addr is None: if a not in parallel_addrs: parallel_addrs.append(a) @@ -271,10 +267,10 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, # Get versions and build capnp list to put into CarParams car_fw = [] - requests = [(brand, r) for brand, r in REQUESTS if query_brand is None or brand == query_brand] + requests = [(brand, config, r) for brand, config, r in REQUESTS if query_brand is None or brand == query_brand] for addr in tqdm(addrs, disable=not progress): for addr_chunk in chunks(addr): - for brand, r in requests: + for brand, config, r in requests: # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue @@ -292,15 +288,14 @@ def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, for (tx_addr, sub_addr), version in query.get_data(timeout).items(): f = car.CarParams.CarFw.new_message() - ecu_key = (brand, tx_addr, sub_addr) - f.ecu = ecu_types.get(ecu_key, Ecu.unknown) + f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown) f.fwVersion = version f.address = tx_addr f.responseAddress = uds.get_rx_addr_for_tx_addr(tx_addr, r.rx_offset) f.request = r.request f.brand = brand f.bus = r.bus - f.logging = r.logging or ecu_key in logging_addrs + f.logging = r.logging or (f.ecu, tx_addr, sub_addr) in config.extra_ecus f.obdMultiplexing = r.obd_multiplexing if sub_addr is not None: From 6f35d23c062ab000af90f5a0d7704eab8682479d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 25 Mar 2023 01:07:58 -0700 Subject: [PATCH 1174/1179] FPv2: match brand against extra ecus (#27688) * query extra ecus (still need to match) * match against extra ecus * clean p * clean p * switch that around * can clean that up * values --- selfdrive/car/fw_versions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py index 6918913f80..f85b7f6b7d 100755 --- a/selfdrive/car/fw_versions.py +++ b/selfdrive/car/fw_versions.py @@ -39,6 +39,8 @@ def build_fw_dict(fw_versions, filter_brand=None): def get_brand_addrs(): brand_addrs = defaultdict(set) for brand, cars in VERSIONS.items(): + # Add ecus in database + extra ecus to match against + brand_addrs[brand] |= {(addr, sub_addr) for _, addr, sub_addr in FW_QUERY_CONFIGS[brand].extra_ecus} for fw in cars.values(): brand_addrs[brand] |= {(addr, sub_addr) for _, addr, sub_addr in fw.keys()} return brand_addrs @@ -153,13 +155,13 @@ def get_present_ecus(logcan, sendcan, num_pandas=1) -> Set[EcuAddrBusType]: parallel_queries: Dict[bool, List[EcuAddrBusType]] = {True: [], False: []} responses = set() - for brand, _, r in REQUESTS: + for brand, config, r in REQUESTS: # Skip query if no panda available if r.bus > num_pandas * 4 - 1: continue for brand_versions in VERSIONS[brand].values(): - for ecu_type, addr, sub_addr in brand_versions: + for ecu_type, addr, sub_addr in list(brand_versions) + config.extra_ecus: # Only query ecus in whitelist if whitelist is not empty if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus: a = (addr, sub_addr, r.bus) From c77a0feab4e8474f73e47d7f111f3f41f0d68ff3 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 06:38:41 +0800 Subject: [PATCH 1175/1179] cabana: fix high DPI issues in chart (#27694) --- tools/cabana/chartswidget.cc | 79 +++++++++++++++++++----------------- tools/cabana/chartswidget.h | 6 +-- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/tools/cabana/chartswidget.cc b/tools/cabana/chartswidget.cc index 72c9e1ba91..a6eabfd1ae 100644 --- a/tools/cabana/chartswidget.cc +++ b/tools/cabana/chartswidget.cc @@ -21,7 +21,7 @@ static inline bool xLessThan(const QPointF &p, float x) { return p.x() < x; } // ChartsWidget -ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { +ChartsWidget::ChartsWidget(QWidget *parent) : align_timer(this), QFrame(parent) { setFrameStyle(QFrame::StyledPanel | QFrame::Plain); QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setContentsMargins(0, 0, 0, 0); @@ -89,6 +89,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) { range_slider->setValue(max_chart_range); updateToolBar(); + align_timer.setSingleShot(true); + QObject::connect(&align_timer, &QTimer::timeout, this, &ChartsWidget::alignCharts); QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll); QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged); QObject::connect(can, &AbstractStream::updated, this, &ChartsWidget::updateState); @@ -200,7 +202,7 @@ ChartView *ChartsWidget::createChart() { QObject::connect(chart, &ChartView::zoomReset, this, &ChartsWidget::zoomReset); QObject::connect(chart, &ChartView::seriesRemoved, this, &ChartsWidget::seriesChanged); QObject::connect(chart, &ChartView::seriesAdded, this, &ChartsWidget::seriesChanged); - QObject::connect(chart, &ChartView::axisYLabelWidthChanged, this, &ChartsWidget::alignCharts); + QObject::connect(chart, &ChartView::axisYLabelWidthChanged, &align_timer, qOverload<>(&QTimer::start)); charts.push_back(chart); updateLayout(); return chart; @@ -312,7 +314,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) { axis_y = new QValueAxis(this); chart->addAxis(axis_x, Qt::AlignBottom); chart->addAxis(axis_y, Qt::AlignLeft); - chart->legend()->layout()->setContentsMargins(16, 0, 40, 0); + chart->legend()->layout()->setContentsMargins(0, 0, 0, 0); chart->legend()->setShowToolTips(true); chart->setMargins({0, 0, 0, 0}); @@ -438,24 +440,34 @@ void ChartView::manageSeries() { } void ChartView::resizeEvent(QResizeEvent *event) { - updatePlotArea(align_to); - int top_margin = style()->pixelMetric(QStyle::PM_LayoutTopMargin); - int spacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); - int x = event->size().width() - close_btn_proxy->size().width() - style()->pixelMetric(QStyle::PM_LayoutRightMargin); - close_btn_proxy->setPos(x, top_margin); - manage_btn_proxy->setPos(x - manage_btn_proxy->size().width() - spacing, top_margin); - move_icon->setPos(style()->pixelMetric(QStyle::PM_LayoutLeftMargin), top_margin); + qreal left, top, right, bottom; + chart()->layout()->getContentsMargins(&left, &top, &right, &bottom); + move_icon->setPos(left, top); + close_btn_proxy->setPos(rect().right() - right - close_btn_proxy->size().width(), top); + int x = close_btn_proxy->pos().x() - manage_btn_proxy->size().width() - style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + manage_btn_proxy->setPos(x, top); + chart()->legend()->setGeometry({move_icon->sceneBoundingRect().topRight(), manage_btn_proxy->sceneBoundingRect().bottomLeft()}); + if (align_to > 0) { + updatePlotArea(align_to); + } QChartView::resizeEvent(event); } -void ChartView::updatePlotArea(int left) { - QRect r = rect(); - if (align_to != left || r != background->rect()) { - align_to = left; - background->setRect(r); - chart()->legend()->setGeometry(QRect(r.left(), r.top(), r.width(), 45)); - chart()->setPlotArea(QRect(align_to, r.top() + 45, r.width() - align_to - 36, r.height() - 80)); +void ChartView::updatePlotArea(int left_pos) { + if (align_to != left_pos || rect() != background->rect()) { + align_to = left_pos; + background->setRect(rect()); + + qreal left, top, right, bottom; + chart()->layout()->getContentsMargins(&left, &top, &right, &bottom); + QSizeF x_label_size = QFontMetrics(axis_x->labelsFont()).size(Qt::TextSingleLine, QString::number(axis_x->max(), 'f', 2)); + x_label_size += QSizeF{5 * devicePixelRatioF(), 5 * devicePixelRatioF()}; + int adjust_top = chart()->legend()->geometry().height() + style()->pixelMetric(QStyle::PM_LayoutTopMargin); + chart()->setPlotArea(rect().adjusted(align_to + left, adjust_top + top, -x_label_size.width() / 2 - right, -x_label_size.height() - bottom)); chart()->layout()->invalidate(); + if (can->isPaused()) { + update(); + } } } @@ -476,7 +488,6 @@ void ChartView::updatePlot(double cur, double min, double max) { updateAxisY(); updateSeriesPoints(); } - scene()->invalidate({}, QGraphicsScene::ForegroundLayer); } @@ -490,7 +501,7 @@ void ChartView::updateSeriesPoints() { int pixels_per_point = width() / num_points; if (series_type == SeriesType::Scatter) { - ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8)); + ((QScatterSeries *)s.series)->setMarkerSize(std::clamp(pixels_per_point / 3, 2, 8) * devicePixelRatioF()); } else { s.series->setPointsVisible(pixels_per_point > 20); } @@ -508,7 +519,7 @@ void ChartView::updateSeries(const cabana::Signal *sig) { s.series->setColor(getColor(s.sig)); auto msgs = can->events().at(s.msg_id); - auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time=s.last_value_mono_time}); + auto first = std::upper_bound(msgs.cbegin(), msgs.cend(), CanEvent{.mono_time = s.last_value_mono_time}); int new_size = std::max(s.vals.size() + std::distance(first, msgs.cend()), settings.max_cached_minutes * 60 * 100); if (s.vals.capacity() <= new_size) { s.vals.reserve(new_size * 2); @@ -569,7 +580,7 @@ void ChartView::updateAxisY() { if (axis_y->titleText() != unit) { axis_y->setTitleText(unit); - y_label_width = 0;// recalc width + y_label_width = 0; // recalc width } double delta = std::abs(max - min) < 1e-3 ? 1 : (max - min) * 0.05; @@ -578,10 +589,10 @@ void ChartView::updateAxisY() { axis_y->setRange(min_y, max_y); axis_y->setTickCount(tick_count); + int title_spacing = unit.isEmpty() ? 0 : QFontMetrics(axis_y->titleFont()).size(Qt::TextSingleLine, unit).height(); QFontMetrics fm(axis_y->labelsFont()); int n = qMax(int(-qFloor(std::log10((max_y - min_y) / (tick_count - 1)))), 0) + 1; - int title_spacing = axis_y->titleText().isEmpty() ? 0 : 20; - y_label_width = title_spacing + qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; // left margin 15 + y_label_width = title_spacing + qMax(fm.width(QString::number(min_y, 'f', n)), fm.width(QString::number(max_y, 'f', n))) + 15; axis_y->setLabelFormat(QString("%.%1f").arg(n)); emit axisYLabelWidthChanged(y_label_width); } @@ -628,10 +639,7 @@ void ChartView::mousePressEvent(QMouseEvent *event) { drag->setMimeData(mimeData); drag->setPixmap(grab()); drag->setHotSpot(event->pos()); - Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction); - if (dropAction == Qt::MoveAction) { - return; - } + drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::MoveAction); } else if (event->button() == Qt::LeftButton && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { if (!can->liveStreaming()) { // Save current playback state when scrubbing @@ -639,7 +647,6 @@ void ChartView::mousePressEvent(QMouseEvent *event) { if (resume_after_scrub) { can->pause(true); } - is_scrubbing = true; } } else { @@ -687,20 +694,18 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) { } void ChartView::mouseMoveEvent(QMouseEvent *ev) { + const auto plot_area = chart()->plotArea(); // Scrubbing if (is_scrubbing && QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) { - if (chart()->plotArea().contains(ev->pos())) { - double t = chart()->mapToValue(ev->pos()).x(); - // Prevent seeking past the end of the route - t = std::clamp(t, 0., can->totalSeconds()); - can->seekTo(t); + if (plot_area.contains(ev->pos())) { + can->seekTo(std::clamp(chart()->mapToValue(ev->pos()).x(), 0., can->totalSeconds())); } return; } auto rubber = findChild(); bool is_zooming = rubber && rubber->isVisible(); - const auto plot_area = chart()->plotArea(); + is_scrubbing = false; clearTrackPoints(); if (!is_zooming && plot_area.contains(ev->pos())) { @@ -838,8 +843,8 @@ QXYSeries *ChartView::createSeries(SeriesType type, QColor color) { chart()->legend()->setMarkerShape(QLegend::MarkerShapeCircle); } series->setColor(color); - // TODO: Due to a bug in CameraWidget the camera frames - // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed + // TODO: Due to a bug in CameraWidget the camera frames + // are drawn instead of the graphs on MacOS. Re-enable OpenGL when fixed #ifndef __APPLE__ series->setUseOpenGL(true); // Qt doesn't properly apply device pixel ratio in OpenGL mode @@ -939,7 +944,7 @@ SeriesSelector::SeriesSelector(QString title, QWidget *parent) : QDialog(parent) QObject::connect(available_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::add); QObject::connect(selected_list, &QListWidget::itemDoubleClicked, this, &SeriesSelector::remove); QObject::connect(add_btn, &QPushButton::clicked, [this]() { if (auto item = available_list->currentItem()) add(item); }); - QObject::connect(remove_btn, &QPushButton::clicked, [this]() { if (auto item = selected_list->currentItem()) remove(item);}); + QObject::connect(remove_btn, &QPushButton::clicked, [this]() { if (auto item = selected_list->currentItem()) remove(item); }); QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); QObject::connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } diff --git a/tools/cabana/chartswidget.h b/tools/cabana/chartswidget.h index c7470a6f12..731be47d06 100644 --- a/tools/cabana/chartswidget.h +++ b/tools/cabana/chartswidget.h @@ -1,12 +1,11 @@ #pragma once -#include #include #include #include #include #include -#include +#include #include #include #include @@ -122,7 +121,7 @@ private: void resizeEvent(QResizeEvent *event) override; void alignCharts(); void newChart(); - ChartView * createChart(); + ChartView *createChart(); void removeChart(ChartView *chart); void eventsMerged(); void updateState(); @@ -154,6 +153,7 @@ private: QAction *columns_action; int column_count = 1; int current_column_count = 0; + QTimer align_timer; }; class SeriesSelector : public QDialog { From 8150e4a4b864e266bac4a0f4cc95816424f0d463 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 06:38:55 +0800 Subject: [PATCH 1176/1179] cabana: support qlogs (#27689) --- tools/cabana/streams/replaystream.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc index 140a795d3a..8bc9af8ab2 100644 --- a/tools/cabana/streams/replaystream.cc +++ b/tools/cabana/streams/replaystream.cc @@ -33,11 +33,6 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir) { QObject::connect(replay.get(), &Replay::streamStarted, this, &AbstractStream::streamStarted); QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments); if (replay->load()) { - const auto &segments = replay->route()->segments(); - if (std::none_of(segments.begin(), segments.end(), [](auto &s) { return s.second.rlog.length() > 0; })) { - qWarning() << "no rlogs in route" << route; - return false; - } replay->start(); return true; } From 8bd4c0f5103d09ef90313ba4b6a55d51ff27744d Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 06:39:21 +0800 Subject: [PATCH 1177/1179] cabana: update state after creating new signal (#27690) --- tools/cabana/signaledit.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cabana/signaledit.cc b/tools/cabana/signaledit.cc index 4cd06e8a7d..99ec09195b 100644 --- a/tools/cabana/signaledit.cc +++ b/tools/cabana/signaledit.cc @@ -279,6 +279,7 @@ void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) { beginInsertRows({}, i, i); insertItem(root.get(), i, sig); endInsertRows(); + updateState(nullptr); } } From 583c4a031f433fb4b48c5dc0a522b71cdbd6f23c Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 26 Mar 2023 07:03:16 +0800 Subject: [PATCH 1178/1179] cabana: improve LogSlider (#27673) * improve logslider * fix code indentation --- tools/cabana/util.cc | 28 ++++++++++++---------------- tools/cabana/util.h | 23 ++++++++++++++++------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc index b37b7911ed..e5a9749103 100644 --- a/tools/cabana/util.cc +++ b/tools/cabana/util.cc @@ -4,10 +4,8 @@ #include #include #include -#include - -#include #include +#include #include "selfdrive/ui/qt/util.h" @@ -42,7 +40,7 @@ void ChangeTracker::compute(const QByteArray &dat, double ts, uint32_t freq) { } // Track bit level changes - for (int bit = 0; bit < 8; bit++){ + for (int bit = 0; bit < 8; bit++) { if ((cur ^ last) & (1 << bit)) { bit_change_counts[i][bit] += 1; } @@ -67,7 +65,6 @@ void ChangeTracker::clear() { colors.clear(); } - // SegmentTree void SegmentTree::build(const QVector &arr) { @@ -116,7 +113,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem & int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin); QRect rc{option.rect.left() + h_margin, option.rect.top() + v_margin, byte_width, option.rect.height() - 2 * v_margin}; - auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText: QPalette::Text; + auto color_role = option.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text; painter->setPen(option.palette.color(color_role)); painter->setFont(fixed_font); for (int i = 0; i < byte_list.size(); ++i) { @@ -139,7 +136,7 @@ QColor getColor(const cabana::Signal *sig) { return QColor::fromHsvF(h, s, v); } -NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) { } +NameValidator::NameValidator(QObject *parent) : QRegExpValidator(QRegExp("^(\\w+)"), parent) {} QValidator::State NameValidator::validate(QString &input, int &pos) const { input.replace(' ', '_'); @@ -175,7 +172,6 @@ QToolButton *toolButton(const QString &icon, const QString &tooltip) { return btn; }; - QString toHex(uint8_t byte) { static std::array hex = []() { std::array ret; @@ -186,11 +182,11 @@ QString toHex(uint8_t byte) { } int num_decimals(double num) { - const QString string = QString::number(num); - const QStringList split = string.split('.'); - if (split.size() == 1) { - return 0; - } else { - return split[1].size(); - } - } + const QString string = QString::number(num); + const QStringList split = string.split('.'); + if (split.size() == 1) { + return 0; + } else { + return split[1].size(); + } +} diff --git a/tools/cabana/util.h b/tools/cabana/util.h index 3cf14982a9..330da77179 100644 --- a/tools/cabana/util.h +++ b/tools/cabana/util.h @@ -36,17 +36,26 @@ class LogSlider : public QSlider { public: LogSlider(double factor, Qt::Orientation orientation, QWidget *parent = nullptr) : factor(factor), QSlider(orientation, parent) {}; - void setRange(double min, double max) { QSlider::setRange(logScale(min), logScale(max)); } - int value() const { return invLogScale(QSlider::value()); } - void setValue(int value) { QSlider::setValue(logScale(value)); } + void setRange(double min, double max) { + log_min = factor * std::log10(min); + log_max = factor * std::log10(max); + QSlider::setRange(min, max); + setValue(QSlider::value()); + } + int value() const { + double v = log_min + (log_max - log_min) * ((QSlider::value() - minimum()) / double(maximum() - minimum())); + return std::lround(std::pow(10, v / factor)); + } + void setValue(int v) { + double log_v = std::clamp(factor * std::log10(v), log_min, log_max); + v = minimum() + (maximum() - minimum()) * ((log_v - log_min) / (log_max - log_min)); + QSlider::setValue(v); + } private: - double factor; - int logScale(int value) const { return factor * std::log10(value); } - int invLogScale(int value) const { return std::pow(10, value / factor); } + double factor, log_min = 0, log_max = 1; }; - enum { ColorsRole = Qt::UserRole + 1, BytesRole = Qt::UserRole + 2 From 083f008d94a037174f27417c6e2d1698f7ee897f Mon Sep 17 00:00:00 2001 From: AlexandreSato <66435071+AlexandreSato@users.noreply.github.com> Date: Sun, 26 Mar 2023 21:06:33 -0300 Subject: [PATCH 1179/1179] caban: fix typo (#27700) --- tools/cabana/mainwin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc index b7cfd9dc2a..c739e26744 100644 --- a/tools/cabana/mainwin.cc +++ b/tools/cabana/mainwin.cc @@ -336,7 +336,7 @@ void MainWindow::loadDBCFromFingerprint() { if (can->liveStreaming()) { video_dock->setWindowTitle(can->routeName()); } else { - video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); + video_dock->setWindowTitle(tr("ROUTE: %1 FINGERPRINT: %2").arg(can->routeName()).arg(fingerprint.isEmpty() ? tr("Unknown Car") : fingerprint)); } if (!fingerprint.isEmpty()) { auto dbc_name = fingerprint_to_dbc[fingerprint];